diff options
| author | Joakim Verona | 2010-10-18 22:05:07 +0200 |
|---|---|---|
| committer | Joakim Verona | 2010-10-18 22:05:07 +0200 |
| commit | 13cfe8df462ab8da9f0028e16cc84dcaceaca3d1 (patch) | |
| tree | 723f254768f9e503504ab4c8b68801f80a56591a /lisp/progmodes/sql.el | |
| parent | 35f4b80a934b299b3b18e62f5db44f64c240e65b (diff) | |
| parent | e48eb34332dc91de823314090451459ba2ffacbf (diff) | |
| download | emacs-13cfe8df462ab8da9f0028e16cc84dcaceaca3d1.tar.gz emacs-13cfe8df462ab8da9f0028e16cc84dcaceaca3d1.zip | |
merge from upstream
Diffstat (limited to 'lisp/progmodes/sql.el')
| -rw-r--r-- | lisp/progmodes/sql.el | 608 |
1 files changed, 421 insertions, 187 deletions
diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el index a80a555c13f..7148027f487 100644 --- a/lisp/progmodes/sql.el +++ b/lisp/progmodes/sql.el | |||
| @@ -5,10 +5,9 @@ | |||
| 5 | 5 | ||
| 6 | ;; Author: Alex Schroeder <alex@gnu.org> | 6 | ;; Author: Alex Schroeder <alex@gnu.org> |
| 7 | ;; Maintainer: Michael Mauger <mmaug@yahoo.com> | 7 | ;; Maintainer: Michael Mauger <mmaug@yahoo.com> |
| 8 | ;; Version: 2.6 | 8 | ;; Version: 2.8 |
| 9 | ;; Keywords: comm languages processes | 9 | ;; Keywords: comm languages processes |
| 10 | ;; URL: http://savannah.gnu.org/cgi-bin/viewcvs/emacs/emacs/lisp/progmodes/sql.el | 10 | ;; URL: http://savannah.gnu.org/cgi-bin/viewcvs/emacs/emacs/lisp/progmodes/sql.el |
| 11 | ;; URL: http://www.emacswiki.org/cgi-bin/wiki.pl?SqlMode | ||
| 12 | 11 | ||
| 13 | ;; This file is part of GNU Emacs. | 12 | ;; This file is part of GNU Emacs. |
| 14 | 13 | ||
| @@ -286,6 +285,9 @@ Customizing your password will store it in your ~/.emacs file." | |||
| 286 | 285 | ||
| 287 | (define-widget 'sql-login-params 'lazy | 286 | (define-widget 'sql-login-params 'lazy |
| 288 | "Widget definition of the login parameters list" | 287 | "Widget definition of the login parameters list" |
| 288 | ;; FIXME: does not implement :default property for the user, | ||
| 289 | ;; database and server options. Anybody have some guidance on how to | ||
| 290 | ;; do this. | ||
| 289 | :tag "Login Parameters" | 291 | :tag "Login Parameters" |
| 290 | :type '(repeat (choice | 292 | :type '(repeat (choice |
| 291 | (const user) | 293 | (const user) |
| @@ -300,7 +302,7 @@ Customizing your password will store it in your ~/.emacs file." | |||
| 300 | (const :format "" server) | 302 | (const :format "" server) |
| 301 | (const :format "" :completion) | 303 | (const :format "" :completion) |
| 302 | (restricted-sexp | 304 | (restricted-sexp |
| 303 | :match-alternatives (listp symbolp)))) | 305 | :match-alternatives (listp stringp)))) |
| 304 | (choice :tag "database" | 306 | (choice :tag "database" |
| 305 | (const database) | 307 | (const database) |
| 306 | (list :tag "file" | 308 | (list :tag "file" |
| @@ -311,7 +313,7 @@ Customizing your password will store it in your ~/.emacs file." | |||
| 311 | (const :format "" database) | 313 | (const :format "" database) |
| 312 | (const :format "" :completion) | 314 | (const :format "" :completion) |
| 313 | (restricted-sexp | 315 | (restricted-sexp |
| 314 | :match-alternatives (listp symbolp)))) | 316 | :match-alternatives (listp stringp)))) |
| 315 | (const port)))) | 317 | (const port)))) |
| 316 | 318 | ||
| 317 | ;; SQL Product support | 319 | ;; SQL Product support |
| @@ -401,6 +403,8 @@ Customizing your password will store it in your ~/.emacs file." | |||
| 401 | :sqli-options sql-mysql-options | 403 | :sqli-options sql-mysql-options |
| 402 | :sqli-login sql-mysql-login-params | 404 | :sqli-login sql-mysql-login-params |
| 403 | :sqli-comint-func sql-comint-mysql | 405 | :sqli-comint-func sql-comint-mysql |
| 406 | :list-all "SHOW TABLES;" | ||
| 407 | :list-table "DESCRIBE %s;" | ||
| 404 | :prompt-regexp "^mysql> " | 408 | :prompt-regexp "^mysql> " |
| 405 | :prompt-length 6 | 409 | :prompt-length 6 |
| 406 | :prompt-cont-regexp "^ -> " | 410 | :prompt-cont-regexp "^ -> " |
| @@ -428,6 +432,8 @@ Customizing your password will store it in your ~/.emacs file." | |||
| 428 | :sqli-options sql-postgres-options | 432 | :sqli-options sql-postgres-options |
| 429 | :sqli-login sql-postgres-login-params | 433 | :sqli-login sql-postgres-login-params |
| 430 | :sqli-comint-func sql-comint-postgres | 434 | :sqli-comint-func sql-comint-postgres |
| 435 | :list-all ("\\d+" . "\\dS+") | ||
| 436 | :list-table ("\\d+ %s" . "\\dS+ %s") | ||
| 431 | :prompt-regexp "^.*=[#>] " | 437 | :prompt-regexp "^.*=[#>] " |
| 432 | :prompt-length 5 | 438 | :prompt-length 5 |
| 433 | :prompt-cont-regexp "^.*[-(][#>] " | 439 | :prompt-cont-regexp "^.*[-(][#>] " |
| @@ -452,6 +458,8 @@ Customizing your password will store it in your ~/.emacs file." | |||
| 452 | :sqli-options sql-sqlite-options | 458 | :sqli-options sql-sqlite-options |
| 453 | :sqli-login sql-sqlite-login-params | 459 | :sqli-login sql-sqlite-login-params |
| 454 | :sqli-comint-func sql-comint-sqlite | 460 | :sqli-comint-func sql-comint-sqlite |
| 461 | :list-all ".tables" | ||
| 462 | :list-table ".schema %s" | ||
| 455 | :prompt-regexp "^sqlite> " | 463 | :prompt-regexp "^sqlite> " |
| 456 | :prompt-length 8 | 464 | :prompt-length 8 |
| 457 | :prompt-cont-regexp "^ ...> " | 465 | :prompt-cont-regexp "^ ...> " |
| @@ -510,6 +518,23 @@ may be any one of the following: | |||
| 510 | database. Do product specific | 518 | database. Do product specific |
| 511 | configuration of comint in this function. | 519 | configuration of comint in this function. |
| 512 | 520 | ||
| 521 | :list-all Command string or function which produces | ||
| 522 | a listing of all objects in the database. | ||
| 523 | If it's a cons cell, then the car | ||
| 524 | produces the standard list of objects and | ||
| 525 | the cdr produces an enhanced list of | ||
| 526 | objects. What \"enhanced\" means is | ||
| 527 | dependent on the SQL product and may not | ||
| 528 | exist. In general though, the | ||
| 529 | \"enhanced\" list should include visible | ||
| 530 | objects from other schemas. | ||
| 531 | |||
| 532 | :list-table Command string or function which produces | ||
| 533 | a detailed listing of a specific database | ||
| 534 | table. If its a cons cell, then the car | ||
| 535 | produces the standard list and the cdr | ||
| 536 | produces an enhanced list. | ||
| 537 | |||
| 513 | :prompt-regexp regular expression string that matches | 538 | :prompt-regexp regular expression string that matches |
| 514 | the prompt issued by the product | 539 | the prompt issued by the product |
| 515 | interpreter. | 540 | interpreter. |
| @@ -941,7 +966,9 @@ add your name with a \"-U\" prefix (such as \"-Umark\") to the list." | |||
| 941 | :version "20.8" | 966 | :version "20.8" |
| 942 | :group 'SQL) | 967 | :group 'SQL) |
| 943 | 968 | ||
| 944 | (defcustom sql-postgres-login-params '(user database server) | 969 | (defcustom sql-postgres-login-params `((user :default ,(user-login-name)) |
| 970 | (database :default ,(user-login-name)) | ||
| 971 | server) | ||
| 945 | "List of login parameters needed to connect to Postgres." | 972 | "List of login parameters needed to connect to Postgres." |
| 946 | :type 'sql-login-params | 973 | :type 'sql-login-params |
| 947 | :version "24.1" | 974 | :version "24.1" |
| @@ -1025,6 +1052,12 @@ Starts `sql-interactive-mode' after doing some setup." | |||
| 1025 | 1052 | ||
| 1026 | ;; Passwords are not kept in a history. | 1053 | ;; Passwords are not kept in a history. |
| 1027 | 1054 | ||
| 1055 | (defvar sql-product-history nil | ||
| 1056 | "History of products used.") | ||
| 1057 | |||
| 1058 | (defvar sql-connection-history nil | ||
| 1059 | "History of connections used.") | ||
| 1060 | |||
| 1028 | (defvar sql-buffer nil | 1061 | (defvar sql-buffer nil |
| 1029 | "Current SQLi buffer. | 1062 | "Current SQLi buffer. |
| 1030 | 1063 | ||
| @@ -1052,11 +1085,24 @@ You can change `sql-prompt-length' on `sql-interactive-mode-hook'.") | |||
| 1052 | 1085 | ||
| 1053 | Used by `sql-rename-buffer'.") | 1086 | Used by `sql-rename-buffer'.") |
| 1054 | 1087 | ||
| 1055 | (defun sql-buffer-live-p (buffer) | 1088 | (defun sql-buffer-live-p (buffer &optional product) |
| 1056 | "Returns non-nil if the process associated with buffer is live." | 1089 | "Returns non-nil if the process associated with buffer is live. |
| 1057 | (and buffer | 1090 | |
| 1058 | (buffer-live-p (get-buffer buffer)) | 1091 | BUFFER can be a buffer object or a buffer name. The buffer must |
| 1059 | (get-buffer-process buffer))) | 1092 | be a live buffer, have an running process attached to it, be in |
| 1093 | `sql-interactive-mode', and, if PRODUCT is specified, it's | ||
| 1094 | `sql-product' must match." | ||
| 1095 | |||
| 1096 | (when buffer | ||
| 1097 | (setq buffer (get-buffer buffer)) | ||
| 1098 | (and buffer | ||
| 1099 | (buffer-live-p buffer) | ||
| 1100 | (get-buffer-process buffer) | ||
| 1101 | (comint-check-proc buffer) | ||
| 1102 | (with-current-buffer buffer | ||
| 1103 | (and (derived-mode-p 'sql-interactive-mode) | ||
| 1104 | (or (not product) | ||
| 1105 | (eq product sql-product))))))) | ||
| 1060 | 1106 | ||
| 1061 | ;; Keymap for sql-interactive-mode. | 1107 | ;; Keymap for sql-interactive-mode. |
| 1062 | 1108 | ||
| @@ -1073,6 +1119,8 @@ Used by `sql-rename-buffer'.") | |||
| 1073 | (define-key map (kbd "O") 'sql-magic-go) | 1119 | (define-key map (kbd "O") 'sql-magic-go) |
| 1074 | (define-key map (kbd "o") 'sql-magic-go) | 1120 | (define-key map (kbd "o") 'sql-magic-go) |
| 1075 | (define-key map (kbd ";") 'sql-magic-semicolon) | 1121 | (define-key map (kbd ";") 'sql-magic-semicolon) |
| 1122 | (define-key map (kbd "C-c C-l a") 'sql-list-all) | ||
| 1123 | (define-key map (kbd "C-c C-l t") 'sql-list-table) | ||
| 1076 | map) | 1124 | map) |
| 1077 | "Mode map used for `sql-interactive-mode'. | 1125 | "Mode map used for `sql-interactive-mode'. |
| 1078 | Based on `comint-mode-map'.") | 1126 | Based on `comint-mode-map'.") |
| @@ -1086,6 +1134,8 @@ Based on `comint-mode-map'.") | |||
| 1086 | (define-key map (kbd "C-c C-s") 'sql-send-string) | 1134 | (define-key map (kbd "C-c C-s") 'sql-send-string) |
| 1087 | (define-key map (kbd "C-c C-b") 'sql-send-buffer) | 1135 | (define-key map (kbd "C-c C-b") 'sql-send-buffer) |
| 1088 | (define-key map (kbd "C-c C-i") 'sql-product-interactive) | 1136 | (define-key map (kbd "C-c C-i") 'sql-product-interactive) |
| 1137 | (define-key map (kbd "C-c C-l a") 'sql-list-all) | ||
| 1138 | (define-key map (kbd "C-c C-l t") 'sql-list-table) | ||
| 1089 | map) | 1139 | map) |
| 1090 | "Mode map used for `sql-mode'.") | 1140 | "Mode map used for `sql-mode'.") |
| 1091 | 1141 | ||
| @@ -1101,6 +1151,9 @@ Based on `comint-mode-map'.") | |||
| 1101 | ["Send Buffer" sql-send-buffer (sql-buffer-live-p sql-buffer)] | 1151 | ["Send Buffer" sql-send-buffer (sql-buffer-live-p sql-buffer)] |
| 1102 | ["Send String" sql-send-string (sql-buffer-live-p sql-buffer)] | 1152 | ["Send String" sql-send-string (sql-buffer-live-p sql-buffer)] |
| 1103 | "--" | 1153 | "--" |
| 1154 | ["List all objects" sql-list-all (sql-buffer-live-p sql-buffer)] | ||
| 1155 | ["List table details" sql-list-table (sql-buffer-live-p sql-buffer)] | ||
| 1156 | "--" | ||
| 1104 | ["Start SQLi session" sql-product-interactive | 1157 | ["Start SQLi session" sql-product-interactive |
| 1105 | :visible (not sql-connection-alist) | 1158 | :visible (not sql-connection-alist) |
| 1106 | :enable (sql-get-product-feature sql-product :sqli-comint-func)] | 1159 | :enable (sql-get-product-feature sql-product :sqli-comint-func)] |
| @@ -1139,7 +1192,10 @@ Based on `comint-mode-map'.") | |||
| 1139 | "Menu for `sql-interactive-mode'." | 1192 | "Menu for `sql-interactive-mode'." |
| 1140 | '("SQL" | 1193 | '("SQL" |
| 1141 | ["Rename Buffer" sql-rename-buffer t] | 1194 | ["Rename Buffer" sql-rename-buffer t] |
| 1142 | ["Save Connection" sql-save-connection (not sql-connection)])) | 1195 | ["Save Connection" sql-save-connection (not sql-connection)] |
| 1196 | "--" | ||
| 1197 | ["List all objects" sql-list-all t] | ||
| 1198 | ["List table details" sql-list-table t])) | ||
| 1143 | 1199 | ||
| 1144 | ;; Abbreviations -- if you want more of them, define them in your | 1200 | ;; Abbreviations -- if you want more of them, define them in your |
| 1145 | ;; ~/.emacs file. Abbrevs have to be enabled in your ~/.emacs, too. | 1201 | ;; ~/.emacs file. Abbrevs have to be enabled in your ~/.emacs, too. |
| @@ -2122,6 +2178,16 @@ highlighting rules in SQL mode.") | |||
| 2122 | 2178 | ||
| 2123 | ;;; SQL Product support functions | 2179 | ;;; SQL Product support functions |
| 2124 | 2180 | ||
| 2181 | (defun sql-read-product (prompt &optional initial) | ||
| 2182 | "Read a valid SQL product." | ||
| 2183 | (let ((init (or (and initial (symbol-name initial)) "ansi"))) | ||
| 2184 | (intern (completing-read | ||
| 2185 | prompt | ||
| 2186 | (mapcar (lambda (info) (symbol-name (car info))) | ||
| 2187 | sql-product-alist) | ||
| 2188 | nil 'require-match | ||
| 2189 | init 'sql-product-history init)))) | ||
| 2190 | |||
| 2125 | (defun sql-add-product (product display &rest plist) | 2191 | (defun sql-add-product (product display &rest plist) |
| 2126 | "Add support for a database product in `sql-mode'. | 2192 | "Add support for a database product in `sql-mode'. |
| 2127 | 2193 | ||
| @@ -2312,10 +2378,9 @@ adds a fontification pattern to fontify identifiers ending in | |||
| 2312 | (mapcar | 2378 | (mapcar |
| 2313 | (lambda (param) | 2379 | (lambda (param) |
| 2314 | (let ((token (or (and (listp param) (car param)) param)) | 2380 | (let ((token (or (and (listp param) (car param)) param)) |
| 2315 | (type (or (and (listp param) (nth 1 param)) nil)) | 2381 | (plist (or (and (listp param) (cdr param)) nil))) |
| 2316 | (arg (or (and (listp param) (nth 2 param)) nil))) | ||
| 2317 | 2382 | ||
| 2318 | (funcall body token type arg))) | 2383 | (funcall body token plist))) |
| 2319 | login-params))) | 2384 | login-params))) |
| 2320 | 2385 | ||
| 2321 | 2386 | ||
| @@ -2335,11 +2400,7 @@ adds a fontification pattern to fontify identifiers ending in | |||
| 2335 | (defun sql-set-product (product) | 2400 | (defun sql-set-product (product) |
| 2336 | "Set `sql-product' to PRODUCT and enable appropriate highlighting." | 2401 | "Set `sql-product' to PRODUCT and enable appropriate highlighting." |
| 2337 | (interactive | 2402 | (interactive |
| 2338 | (list (completing-read "SQL product: " | 2403 | (list (sql-read-product "SQL product: "))) |
| 2339 | (mapcar (lambda (info) (symbol-name (car info))) | ||
| 2340 | sql-product-alist) | ||
| 2341 | nil 'require-match | ||
| 2342 | (or (and sql-product (symbol-name sql-product)) "ansi")))) | ||
| 2343 | (if (stringp product) (setq product (intern product))) | 2404 | (if (stringp product) (setq product (intern product))) |
| 2344 | (when (not (assoc product sql-product-alist)) | 2405 | (when (not (assoc product sql-product-alist)) |
| 2345 | (error "SQL product %s is not supported; treated as ANSI" product) | 2406 | (error "SQL product %s is not supported; treated as ANSI" product) |
| @@ -2479,37 +2540,53 @@ appended to the SQLi buffer without disturbing your SQL buffer." | |||
| 2479 | "Read a password using PROMPT. Optional DEFAULT is password to start with." | 2540 | "Read a password using PROMPT. Optional DEFAULT is password to start with." |
| 2480 | (read-passwd prompt nil default)) | 2541 | (read-passwd prompt nil default)) |
| 2481 | 2542 | ||
| 2482 | (defun sql-get-login-ext (prompt last-value history-var type arg) | 2543 | (defun sql-get-login-ext (prompt last-value history-var plist) |
| 2483 | "Prompt user with extended login parameters. | 2544 | "Prompt user with extended login parameters. |
| 2484 | 2545 | ||
| 2485 | If TYPE is nil, then the user is simply prompted for a string | 2546 | If PLIST is nil, then the user is simply prompted for a string |
| 2486 | value. | 2547 | value. |
| 2487 | 2548 | ||
| 2488 | If TYPE is `:file', then the user is prompted for a file | 2549 | The property `:default' specifies the default value. If the |
| 2489 | name that must match the regexp pattern specified in the ARG | 2550 | `:number' property is non-nil then ask for a number. |
| 2490 | argument. | ||
| 2491 | 2551 | ||
| 2492 | If TYPE is `:completion', then the user is prompted for a string | 2552 | The `:file' property prompts for a file name that must match the |
| 2493 | specified by ARG. (ARG is used as the PREDICATE argument to | 2553 | regexp pattern specified in its value. |
| 2494 | `completing-read'.)" | ||
| 2495 | (cond | ||
| 2496 | ((eq type nil) | ||
| 2497 | (read-from-minibuffer prompt last-value nil nil history-var)) | ||
| 2498 | 2554 | ||
| 2499 | ((eq type :file) | 2555 | The `:completion' property prompts for a string specified by its |
| 2500 | (let ((use-dialog-box nil)) | 2556 | value. (The property value is used as the PREDICATE argument to |
| 2557 | `completing-read'.)" | ||
| 2558 | (let* ((default (plist-get plist :default)) | ||
| 2559 | (prompt-def | ||
| 2560 | (if default | ||
| 2561 | (if (string-match "\\(\\):[ \t]*\\'" prompt) | ||
| 2562 | (replace-match (format " (default \"%s\")" default) t t prompt 1) | ||
| 2563 | (replace-regexp-in-string "[ \t]*\\'" | ||
| 2564 | (format " (default \"%s\") " default) | ||
| 2565 | prompt t t)) | ||
| 2566 | prompt)) | ||
| 2567 | (use-dialog-box nil)) | ||
| 2568 | (cond | ||
| 2569 | ((plist-member plist :file) | ||
| 2501 | (expand-file-name | 2570 | (expand-file-name |
| 2502 | (read-file-name prompt | 2571 | (read-file-name prompt |
| 2503 | (file-name-directory last-value) nil t | 2572 | (file-name-directory last-value) default t |
| 2504 | (file-name-nondirectory last-value) | 2573 | (file-name-nondirectory last-value) |
| 2505 | (if arg | 2574 | (when (plist-get plist :file) |
| 2506 | `(lambda (f) | 2575 | `(lambda (f) |
| 2507 | (string-match (concat "\\<" ,arg "\\>") | 2576 | (string-match |
| 2508 | (file-name-nondirectory f))) | 2577 | (concat "\\<" ,(plist-get plist :file) "\\>") |
| 2509 | nil))))) | 2578 | (file-name-nondirectory f))))))) |
| 2510 | 2579 | ||
| 2511 | ((eq type :completion) | 2580 | ((plist-member plist :completion) |
| 2512 | (completing-read prompt arg nil t last-value history-var)))) | 2581 | (completing-read prompt-def (plist-get plist :completion) nil t |
| 2582 | last-value history-var default)) | ||
| 2583 | |||
| 2584 | ((plist-get plist :number) | ||
| 2585 | (read-number prompt (or default last-value 0))) | ||
| 2586 | |||
| 2587 | (t | ||
| 2588 | (let ((r (read-from-minibuffer prompt-def last-value nil nil history-var nil))) | ||
| 2589 | (if (string= "" r) (or default "") r)))))) | ||
| 2513 | 2590 | ||
| 2514 | (defun sql-get-login (&rest what) | 2591 | (defun sql-get-login (&rest what) |
| 2515 | "Get username, password and database from the user. | 2592 | "Get username, password and database from the user. |
| @@ -2528,72 +2605,69 @@ symbol `password', for the server if it contains the symbol | |||
| 2528 | `database'. The members of WHAT are processed in the order in | 2605 | `database'. The members of WHAT are processed in the order in |
| 2529 | which they are provided. | 2606 | which they are provided. |
| 2530 | 2607 | ||
| 2531 | The tokens for `database' and `server' may also be lists to | 2608 | Each token may also be a list with the token in the car and a |
| 2532 | control or limit the values that can be supplied. These can be | 2609 | plist of options as the cdr. The following properties are |
| 2533 | of the form: | 2610 | supported: |
| 2534 | |||
| 2535 | \(database :file \".+\\\\.EXT\") | ||
| 2536 | \(database :completion FUNCTION) | ||
| 2537 | 2611 | ||
| 2538 | The `server' token supports the same forms. | 2612 | :file <filename-regexp> |
| 2613 | :completion <list-of-strings-or-function> | ||
| 2614 | :default <default-value> | ||
| 2615 | :number t | ||
| 2539 | 2616 | ||
| 2540 | In order to ask the user for username, password and database, call the | 2617 | In order to ask the user for username, password and database, call the |
| 2541 | function like this: (sql-get-login 'user 'password 'database)." | 2618 | function like this: (sql-get-login 'user 'password 'database)." |
| 2542 | (interactive) | 2619 | (interactive) |
| 2543 | (mapcar | 2620 | (mapcar |
| 2544 | (lambda (w) | 2621 | (lambda (w) |
| 2545 | (let ((token (or (and (listp w) (car w)) w)) | 2622 | (let ((token (or (and (consp w) (car w)) w)) |
| 2546 | (type (or (and (listp w) (nth 1 w)) nil)) | 2623 | (plist (or (and (consp w) (cdr w)) nil))) |
| 2547 | (arg (or (and (listp w) (nth 2 w)) nil))) | 2624 | |
| 2548 | 2625 | (cond | |
| 2549 | (cond | 2626 | ((eq token 'user) ; user |
| 2550 | ((eq token 'user) ; user | 2627 | (setq sql-user |
| 2551 | (setq sql-user | 2628 | (sql-get-login-ext "User: " sql-user |
| 2552 | (read-from-minibuffer "User: " sql-user nil nil | 2629 | 'sql-user-history plist))) |
| 2553 | 'sql-user-history))) | 2630 | |
| 2554 | 2631 | ((eq token 'password) ; password | |
| 2555 | ((eq token 'password) ; password | 2632 | (setq sql-password |
| 2556 | (setq sql-password | 2633 | (sql-read-passwd "Password: " sql-password))) |
| 2557 | (sql-read-passwd "Password: " sql-password))) | 2634 | |
| 2558 | 2635 | ((eq token 'server) ; server | |
| 2559 | ((eq token 'server) ; server | 2636 | (setq sql-server |
| 2560 | (setq sql-server | 2637 | (sql-get-login-ext "Server: " sql-server |
| 2561 | (sql-get-login-ext "Server: " sql-server | 2638 | 'sql-server-history plist))) |
| 2562 | 'sql-server-history type arg))) | 2639 | |
| 2563 | 2640 | ((eq token 'database) ; database | |
| 2564 | ((eq token 'database) ; database | 2641 | (setq sql-database |
| 2565 | (setq sql-database | 2642 | (sql-get-login-ext "Database: " sql-database |
| 2566 | (sql-get-login-ext "Database: " sql-database | 2643 | 'sql-database-history plist))) |
| 2567 | 'sql-database-history type arg))) | 2644 | |
| 2568 | 2645 | ((eq token 'port) ; port | |
| 2569 | ((eq token 'port) ; port | 2646 | (setq sql-port |
| 2570 | (setq sql-port | 2647 | (sql-get-login-ext "Port: " sql-port |
| 2571 | (read-number "Port: " (if (numberp sql-port) | 2648 | nil (append '(:number t) plist))))))) |
| 2572 | sql-port | 2649 | what)) |
| 2573 | 0))))))) | 2650 | |
| 2574 | what)) | 2651 | (defun sql-find-sqli-buffer (&optional product) |
| 2575 | |||
| 2576 | (defun sql-find-sqli-buffer () | ||
| 2577 | "Returns the name of the current default SQLi buffer or nil. | 2652 | "Returns the name of the current default SQLi buffer or nil. |
| 2578 | In order to qualify, the SQLi buffer must be alive, be in | 2653 | In order to qualify, the SQLi buffer must be alive, be in |
| 2579 | `sql-interactive-mode' and have a process." | 2654 | `sql-interactive-mode' and have a process." |
| 2580 | (let ((default-buffer (default-value 'sql-buffer)) | 2655 | (let ((buf sql-buffer) |
| 2581 | (current-product sql-product)) | 2656 | (prod (or product sql-product))) |
| 2582 | (if (sql-buffer-live-p default-buffer) | 2657 | (or |
| 2583 | default-buffer | 2658 | ;; Current sql-buffer, if there is one. |
| 2584 | (save-current-buffer | 2659 | (and (sql-buffer-live-p buf prod) |
| 2585 | (let ((buflist (buffer-list)) | 2660 | buf) |
| 2586 | (found)) | 2661 | ;; Global sql-buffer |
| 2587 | (while (not (or (null buflist) | 2662 | (and (setq buf (default-value 'sql-buffer)) |
| 2588 | found)) | 2663 | (sql-buffer-live-p buf prod) |
| 2589 | (let ((candidate (car buflist))) | 2664 | buf) |
| 2590 | (set-buffer candidate) | 2665 | ;; Look thru each buffer |
| 2591 | (if (and (sql-buffer-live-p candidate) | 2666 | (car (apply 'append |
| 2592 | (derived-mode-p 'sql-interactive-mode) | 2667 | (mapcar (lambda (b) |
| 2593 | (eq sql-product current-product)) | 2668 | (and (sql-buffer-live-p b prod) |
| 2594 | (setq found (buffer-name candidate))) | 2669 | (list (buffer-name b)))) |
| 2595 | (setq buflist (cdr buflist)))) | 2670 | (buffer-list))))))) |
| 2596 | found))))) | ||
| 2597 | 2671 | ||
| 2598 | (defun sql-set-sqli-buffer-generally () | 2672 | (defun sql-set-sqli-buffer-generally () |
| 2599 | "Set SQLi buffer for all SQL buffers that have none. | 2673 | "Set SQLi buffer for all SQL buffers that have none. |
| @@ -2611,10 +2685,11 @@ using `sql-find-sqli-buffer'. If `sql-buffer' is set, | |||
| 2611 | (let ((candidate (car buflist))) | 2685 | (let ((candidate (car buflist))) |
| 2612 | (set-buffer candidate) | 2686 | (set-buffer candidate) |
| 2613 | (if (and (derived-mode-p 'sql-mode) | 2687 | (if (and (derived-mode-p 'sql-mode) |
| 2614 | (not (buffer-live-p sql-buffer))) | 2688 | (not (sql-buffer-live-p sql-buffer))) |
| 2615 | (progn | 2689 | (progn |
| 2616 | (setq sql-buffer default-buffer) | 2690 | (setq sql-buffer default-buffer) |
| 2617 | (run-hooks 'sql-set-sqli-hook)))) | 2691 | (when default-buffer |
| 2692 | (run-hooks 'sql-set-sqli-hook))))) | ||
| 2618 | (setq buflist (cdr buflist)))))) | 2693 | (setq buflist (cdr buflist)))))) |
| 2619 | 2694 | ||
| 2620 | (defun sql-set-sqli-buffer () | 2695 | (defun sql-set-sqli-buffer () |
| @@ -2632,19 +2707,13 @@ If you call it from anywhere else, it sets the global copy of | |||
| 2632 | (interactive) | 2707 | (interactive) |
| 2633 | (let ((default-buffer (sql-find-sqli-buffer))) | 2708 | (let ((default-buffer (sql-find-sqli-buffer))) |
| 2634 | (if (null default-buffer) | 2709 | (if (null default-buffer) |
| 2635 | (error "There is no suitable SQLi buffer")) | 2710 | (error "There is no suitable SQLi buffer") |
| 2636 | (let ((new-buffer | 2711 | (let ((new-buffer (read-buffer "New SQLi buffer: " default-buffer t))) |
| 2637 | (get-buffer | 2712 | (if (null (sql-buffer-live-p new-buffer)) |
| 2638 | (read-buffer "New SQLi buffer: " default-buffer t)))) | 2713 | (error "Buffer %s is not a working SQLi buffer" new-buffer) |
| 2639 | (if (null (get-buffer-process new-buffer)) | 2714 | (when new-buffer |
| 2640 | (error "Buffer %s has no process" (buffer-name new-buffer))) | 2715 | (setq sql-buffer new-buffer) |
| 2641 | (if (null (with-current-buffer new-buffer | 2716 | (run-hooks 'sql-set-sqli-hook))))))) |
| 2642 | (derived-mode-p 'sql-interactive-mode))) | ||
| 2643 | (error "Buffer %s is no SQLi buffer" (buffer-name new-buffer))) | ||
| 2644 | (if new-buffer | ||
| 2645 | (progn | ||
| 2646 | (setq sql-buffer (buffer-name new-buffer)) | ||
| 2647 | (run-hooks 'sql-set-sqli-hook)))))) | ||
| 2648 | 2717 | ||
| 2649 | (defun sql-show-sqli-buffer () | 2718 | (defun sql-show-sqli-buffer () |
| 2650 | "Show the name of current SQLi buffer. | 2719 | "Show the name of current SQLi buffer. |
| @@ -2682,7 +2751,7 @@ server/database name." | |||
| 2682 | (apply 'append nil | 2751 | (apply 'append nil |
| 2683 | (sql-for-each-login | 2752 | (sql-for-each-login |
| 2684 | (sql-get-product-feature sql-product :sqli-login) | 2753 | (sql-get-product-feature sql-product :sqli-login) |
| 2685 | (lambda (token type arg) | 2754 | (lambda (token plist) |
| 2686 | (cond | 2755 | (cond |
| 2687 | ((eq token 'user) | 2756 | ((eq token 'user) |
| 2688 | (unless (string= "" sql-user) | 2757 | (unless (string= "" sql-user) |
| @@ -2694,13 +2763,13 @@ server/database name." | |||
| 2694 | ((eq token 'server) | 2763 | ((eq token 'server) |
| 2695 | (unless (string= "" sql-server) | 2764 | (unless (string= "" sql-server) |
| 2696 | (list "." | 2765 | (list "." |
| 2697 | (if (eq type :file) | 2766 | (if (plist-member plist :file) |
| 2698 | (file-name-nondirectory sql-server) | 2767 | (file-name-nondirectory sql-server) |
| 2699 | sql-server)))) | 2768 | sql-server)))) |
| 2700 | ((eq token 'database) | 2769 | ((eq token 'database) |
| 2701 | (unless (string= "" sql-database) | 2770 | (unless (string= "" sql-database) |
| 2702 | (list "@" | 2771 | (list "@" |
| 2703 | (if (eq type :file) | 2772 | (if (plist-member plist :file) |
| 2704 | (file-name-nondirectory sql-database) | 2773 | (file-name-nondirectory sql-database) |
| 2705 | sql-database)))) | 2774 | sql-database)))) |
| 2706 | 2775 | ||
| @@ -2742,13 +2811,13 @@ NEW-NAME is empty, then the buffer name will be \"*SQL*\"." | |||
| 2742 | (if (not (derived-mode-p 'sql-interactive-mode)) | 2811 | (if (not (derived-mode-p 'sql-interactive-mode)) |
| 2743 | (message "Current buffer is not a SQL interactive buffer") | 2812 | (message "Current buffer is not a SQL interactive buffer") |
| 2744 | 2813 | ||
| 2745 | (cond | 2814 | (setq sql-alternate-buffer-name |
| 2746 | ((stringp new-name) | 2815 | (cond |
| 2747 | (setq sql-alternate-buffer-name new-name)) | 2816 | ((stringp new-name) new-name) |
| 2748 | ((listp new-name) | 2817 | ((consp new-name) |
| 2749 | (setq sql-alternate-buffer-name | ||
| 2750 | (read-string "Buffer name (\"*SQL: XXX*\"; enter `XXX'): " | 2818 | (read-string "Buffer name (\"*SQL: XXX*\"; enter `XXX'): " |
| 2751 | sql-alternate-buffer-name)))) | 2819 | sql-alternate-buffer-name)) |
| 2820 | (t sql-alternate-buffer-name))) | ||
| 2752 | 2821 | ||
| 2753 | (rename-buffer (if (string= "" sql-alternate-buffer-name) | 2822 | (rename-buffer (if (string= "" sql-alternate-buffer-name) |
| 2754 | "*SQL*" | 2823 | "*SQL*" |
| @@ -2994,6 +3063,171 @@ If given the optional parameter VALUE, sets | |||
| 2994 | 3063 | ||
| 2995 | 3064 | ||
| 2996 | 3065 | ||
| 3066 | ;;; Redirect output functions | ||
| 3067 | |||
| 3068 | (defun sql-redirect (command combuf &optional outbuf save-prior) | ||
| 3069 | "Execute the SQL command and send output to OUTBUF. | ||
| 3070 | |||
| 3071 | COMBUF must be an active SQL interactive buffer. OUTBUF may be | ||
| 3072 | an existing buffer, or the name of a non-existing buffer. If | ||
| 3073 | omitted the output is sent to a temporary buffer which will be | ||
| 3074 | killed after the command completes. COMMAND should be a string | ||
| 3075 | of commands accepted by the SQLi program." | ||
| 3076 | |||
| 3077 | (with-current-buffer combuf | ||
| 3078 | (let ((buf (get-buffer-create (or outbuf " *SQL-Redirect*"))) | ||
| 3079 | (proc (get-buffer-process (current-buffer))) | ||
| 3080 | (comint-prompt-regexp (sql-get-product-feature sql-product | ||
| 3081 | :prompt-regexp)) | ||
| 3082 | (start nil)) | ||
| 3083 | (with-current-buffer buf | ||
| 3084 | (toggle-read-only -1) | ||
| 3085 | (unless save-prior | ||
| 3086 | (erase-buffer)) | ||
| 3087 | (goto-char (point-max)) | ||
| 3088 | (unless (zerop (buffer-size)) | ||
| 3089 | (insert "\n")) | ||
| 3090 | (setq start (point))) | ||
| 3091 | |||
| 3092 | ;; Run the command | ||
| 3093 | (message "Executing SQL command...") | ||
| 3094 | (comint-redirect-send-command-to-process command buf proc nil t) | ||
| 3095 | (while (null comint-redirect-completed) | ||
| 3096 | (accept-process-output nil 1)) | ||
| 3097 | (message "Executing SQL command...done") | ||
| 3098 | |||
| 3099 | ;; Clean up the output results | ||
| 3100 | (with-current-buffer buf | ||
| 3101 | ;; Remove trailing whitespace | ||
| 3102 | (goto-char (point-max)) | ||
| 3103 | (when (looking-back "[ \t\f\n\r]*" start) | ||
| 3104 | (delete-region (match-beginning 0) (match-end 0))) | ||
| 3105 | ;; Remove echo if there was one | ||
| 3106 | (goto-char start) | ||
| 3107 | (when (looking-at (concat "^" (regexp-quote command) "[\\n]")) | ||
| 3108 | (delete-region (match-beginning 0) (match-end 0))) | ||
| 3109 | (goto-char start))))) | ||
| 3110 | |||
| 3111 | (defun sql-redirect-value (command combuf regexp &optional regexp-groups) | ||
| 3112 | "Execute the SQL command and return part of result. | ||
| 3113 | |||
| 3114 | COMBUF must be an active SQL interactive buffer. COMMAND should | ||
| 3115 | be a string of commands accepted by the SQLi program. From the | ||
| 3116 | output, the REGEXP is repeatedly matched and the list of | ||
| 3117 | REGEXP-GROUPS submatches is returned. This behaves much like | ||
| 3118 | \\[comint-redirect-results-list-from-process] but instead of | ||
| 3119 | returning a single submatch it returns a list of each submatch | ||
| 3120 | for each match." | ||
| 3121 | |||
| 3122 | (let ((outbuf " *SQL-Redirect-values*") | ||
| 3123 | (results nil)) | ||
| 3124 | (sql-redirect command combuf outbuf nil) | ||
| 3125 | (with-current-buffer outbuf | ||
| 3126 | (while (re-search-forward regexp nil t) | ||
| 3127 | (push | ||
| 3128 | (cond | ||
| 3129 | ;; no groups-return all of them | ||
| 3130 | ((null regexp-groups) | ||
| 3131 | (let ((i 1) | ||
| 3132 | (r nil)) | ||
| 3133 | (while (match-beginning i) | ||
| 3134 | (push (match-string i) r)) | ||
| 3135 | (nreverse r))) | ||
| 3136 | ;; one group specified | ||
| 3137 | ((numberp regexp-groups) | ||
| 3138 | (match-string regexp-groups)) | ||
| 3139 | ;; list of numbers; return the specified matches only | ||
| 3140 | ((consp regexp-groups) | ||
| 3141 | (mapcar (lambda (c) | ||
| 3142 | (cond | ||
| 3143 | ((numberp c) (match-string c)) | ||
| 3144 | ((stringp c) (match-substitute-replacement c)) | ||
| 3145 | (t (error "sql-redirect-value: unknown REGEXP-GROUPS value - %s" c)))) | ||
| 3146 | regexp-groups)) | ||
| 3147 | ;; String is specified; return replacement string | ||
| 3148 | ((stringp regexp-groups) | ||
| 3149 | (match-substitute-replacement regexp-groups)) | ||
| 3150 | (t | ||
| 3151 | (error "sql-redirect-value: unknown REGEXP-GROUPS value - %s" | ||
| 3152 | regexp-groups))) | ||
| 3153 | results))) | ||
| 3154 | (nreverse results))) | ||
| 3155 | |||
| 3156 | (defun sql-execute (sqlbuf outbuf command arg) | ||
| 3157 | "Executes a command in a SQL interacive buffer and captures the output. | ||
| 3158 | |||
| 3159 | The commands are run in SQLBUF and the output saved in OUTBUF. | ||
| 3160 | COMMAND must be a string, a function or a list of such elements. | ||
| 3161 | Functions are called with SQLBUF, OUTBUF and ARG as parameters; | ||
| 3162 | strings are formatted with ARG and executed. | ||
| 3163 | |||
| 3164 | If the results are empty the OUTBUF is deleted, otherwise the | ||
| 3165 | buffer is popped into a view window. " | ||
| 3166 | (mapc | ||
| 3167 | (lambda (c) | ||
| 3168 | (cond | ||
| 3169 | ((stringp c) | ||
| 3170 | (sql-redirect (if arg (format c arg) c) sqlbuf outbuf) t) | ||
| 3171 | ((functionp c) | ||
| 3172 | (apply c sqlbuf outbuf arg)) | ||
| 3173 | (t (error "Unknown sql-execute item %s" c)))) | ||
| 3174 | (if (consp command) command (cons command nil))) | ||
| 3175 | |||
| 3176 | (setq outbuf (get-buffer outbuf)) | ||
| 3177 | (if (zerop (buffer-size outbuf)) | ||
| 3178 | (kill-buffer outbuf) | ||
| 3179 | (let ((one-win (eq (selected-window) | ||
| 3180 | (get-lru-window)))) | ||
| 3181 | (with-current-buffer outbuf | ||
| 3182 | (set-buffer-modified-p nil) | ||
| 3183 | (toggle-read-only 1)) | ||
| 3184 | (view-buffer-other-window outbuf) | ||
| 3185 | (when one-win | ||
| 3186 | (shrink-window-if-larger-than-buffer))))) | ||
| 3187 | |||
| 3188 | (defun sql-execute-feature (sqlbuf outbuf feature enhanced arg) | ||
| 3189 | "List objects or details in a separate display buffer." | ||
| 3190 | (let (command) | ||
| 3191 | (with-current-buffer sqlbuf | ||
| 3192 | (setq command (sql-get-product-feature sql-product feature))) | ||
| 3193 | (unless command | ||
| 3194 | (error "%s does not support %s" sql-product feature)) | ||
| 3195 | (when (consp command) | ||
| 3196 | (setq command (if enhanced | ||
| 3197 | (cdr command) | ||
| 3198 | (car command)))) | ||
| 3199 | (sql-execute sqlbuf outbuf command arg))) | ||
| 3200 | |||
| 3201 | (defun sql-read-table-name (prompt) | ||
| 3202 | "Read the name of a database table." | ||
| 3203 | ;; TODO: Fetch table/view names from database and provide completion. | ||
| 3204 | ;; Also implement thing-at-point if the buffer has valid names in it | ||
| 3205 | ;; (i.e. sql-mode, sql-interactive-mode, or sql-list-all buffers) | ||
| 3206 | (read-from-minibuffer prompt)) | ||
| 3207 | |||
| 3208 | (defun sql-list-all (&optional enhanced) | ||
| 3209 | "List all database objects." | ||
| 3210 | (interactive "P") | ||
| 3211 | (let ((sqlbuf (sql-find-sqli-buffer))) | ||
| 3212 | (unless sqlbuf | ||
| 3213 | (error "No SQL interactive buffer found")) | ||
| 3214 | (sql-execute-feature sqlbuf "*List All*" :list-all enhanced nil))) | ||
| 3215 | |||
| 3216 | (defun sql-list-table (name &optional enhanced) | ||
| 3217 | "List the details of a database table. " | ||
| 3218 | (interactive | ||
| 3219 | (list (sql-read-table-name "Table name: ") | ||
| 3220 | current-prefix-arg)) | ||
| 3221 | (let ((sqlbuf (sql-find-sqli-buffer))) | ||
| 3222 | (unless sqlbuf | ||
| 3223 | (error "No SQL interactive buffer found")) | ||
| 3224 | (unless name | ||
| 3225 | (error "No table name specified")) | ||
| 3226 | (sql-execute-feature sqlbuf (format "*List %s*" name) | ||
| 3227 | :list-table enhanced name))) | ||
| 3228 | |||
| 3229 | |||
| 3230 | |||
| 2997 | ;;; SQL mode -- uses SQL interactive mode | 3231 | ;;; SQL mode -- uses SQL interactive mode |
| 2998 | 3232 | ||
| 2999 | ;;;###autoload | 3233 | ;;;###autoload |
| @@ -3221,6 +3455,14 @@ Sentinels will always get the two parameters PROCESS and EVENT." | |||
| 3221 | 3455 | ||
| 3222 | ;;; Connection handling | 3456 | ;;; Connection handling |
| 3223 | 3457 | ||
| 3458 | (defun sql-read-connection (prompt &optional initial default) | ||
| 3459 | "Read a connection name." | ||
| 3460 | (let ((completion-ignore-case t)) | ||
| 3461 | (completing-read prompt | ||
| 3462 | (mapcar (lambda (c) (car c)) | ||
| 3463 | sql-connection-alist) | ||
| 3464 | nil t initial 'sql-connection-history default))) | ||
| 3465 | |||
| 3224 | ;;;###autoload | 3466 | ;;;###autoload |
| 3225 | (defun sql-connect (connection) | 3467 | (defun sql-connect (connection) |
| 3226 | "Connect to an interactive session using CONNECTION settings. | 3468 | "Connect to an interactive session using CONNECTION settings. |
| @@ -3234,12 +3476,7 @@ is specified in the connection settings." | |||
| 3234 | ;; Prompt for the connection from those defined in the alist | 3476 | ;; Prompt for the connection from those defined in the alist |
| 3235 | (interactive | 3477 | (interactive |
| 3236 | (if sql-connection-alist | 3478 | (if sql-connection-alist |
| 3237 | (list | 3479 | (list (sql-read-connection "Connection: " nil '(nil))) |
| 3238 | (let ((completion-ignore-case t)) | ||
| 3239 | (completing-read "Connection: " | ||
| 3240 | (mapcar (lambda (c) (car c)) | ||
| 3241 | sql-connection-alist) | ||
| 3242 | nil t nil nil '(())))) | ||
| 3243 | nil)) | 3480 | nil)) |
| 3244 | 3481 | ||
| 3245 | ;; Are there connections defined | 3482 | ;; Are there connections defined |
| @@ -3273,10 +3510,10 @@ is specified in the connection settings." | |||
| 3273 | ;; the remaining params (w/o the connection params) | 3510 | ;; the remaining params (w/o the connection params) |
| 3274 | (rem-params (sql-for-each-login | 3511 | (rem-params (sql-for-each-login |
| 3275 | login-params | 3512 | login-params |
| 3276 | (lambda (token type arg) | 3513 | (lambda (token plist) |
| 3277 | (unless (member token set-params) | 3514 | (unless (member token set-params) |
| 3278 | (if (or type arg) | 3515 | (if plist |
| 3279 | (list token type arg) | 3516 | (cons token plist) |
| 3280 | token))))) | 3517 | token))))) |
| 3281 | ;; Remember the connection | 3518 | ;; Remember the connection |
| 3282 | (sql-connection connection)) | 3519 | (sql-connection connection)) |
| @@ -3317,7 +3554,7 @@ optionally is saved to the user's init file." | |||
| 3317 | (append (list name) | 3554 | (append (list name) |
| 3318 | (sql-for-each-login | 3555 | (sql-for-each-login |
| 3319 | `(product ,@login) | 3556 | `(product ,@login) |
| 3320 | (lambda (token type arg) | 3557 | (lambda (token plist) |
| 3321 | (cond | 3558 | (cond |
| 3322 | ((eq token 'product) `(sql-product ',sql-product)) | 3559 | ((eq token 'product) `(sql-product ',sql-product)) |
| 3323 | ((eq token 'user) `(sql-user ,sql-user)) | 3560 | ((eq token 'user) `(sql-user ,sql-user)) |
| @@ -3365,10 +3602,10 @@ the call to \\[sql-product-interactive] with | |||
| 3365 | 3602 | ||
| 3366 | ;; Handle universal arguments if specified | 3603 | ;; Handle universal arguments if specified |
| 3367 | (when (not (or executing-kbd-macro noninteractive)) | 3604 | (when (not (or executing-kbd-macro noninteractive)) |
| 3368 | (when (and (listp product) | 3605 | (when (and (consp product) |
| 3369 | (not (cdr product)) | 3606 | (not (cdr product)) |
| 3370 | (numberp (car product))) | 3607 | (numberp (car product))) |
| 3371 | (when (>= (car product) 16) | 3608 | (when (>= (prefix-numeric-value product) 16) |
| 3372 | (when (not new-name) | 3609 | (when (not new-name) |
| 3373 | (setq new-name '(4))) | 3610 | (setq new-name '(4))) |
| 3374 | (setq product '(4))))) | 3611 | (setq product '(4))))) |
| @@ -3376,61 +3613,53 @@ the call to \\[sql-product-interactive] with | |||
| 3376 | ;; Get the value of product that we need | 3613 | ;; Get the value of product that we need |
| 3377 | (setq product | 3614 | (setq product |
| 3378 | (cond | 3615 | (cond |
| 3379 | ((equal product '(4)) ; C-u, prompt for product | ||
| 3380 | (intern (completing-read "SQL product: " | ||
| 3381 | (mapcar (lambda (info) (symbol-name (car info))) | ||
| 3382 | sql-product-alist) | ||
| 3383 | nil 'require-match | ||
| 3384 | (or (and sql-product | ||
| 3385 | (symbol-name sql-product)) | ||
| 3386 | "ansi")))) | ||
| 3387 | ((and product ; Product specified | 3616 | ((and product ; Product specified |
| 3388 | (symbolp product)) product) | 3617 | (symbolp product)) product) |
| 3618 | ((= (prefix-numeric-value product) 4) ; C-u, prompt for product | ||
| 3619 | (sql-read-product "SQL product: " sql-product)) | ||
| 3389 | (t sql-product))) ; Default to sql-product | 3620 | (t sql-product))) ; Default to sql-product |
| 3390 | 3621 | ||
| 3391 | ;; If we have a product and it has a interactive mode | 3622 | ;; If we have a product and it has a interactive mode |
| 3392 | (if product | 3623 | (if product |
| 3393 | (when (sql-get-product-feature product :sqli-comint-func) | 3624 | (when (sql-get-product-feature product :sqli-comint-func) |
| 3394 | ;; If no new name specified, fall back on sql-buffer if its for | 3625 | ;; If no new name specified, try to pop to an active SQL |
| 3395 | ;; the same product | 3626 | ;; interactive for the same product |
| 3396 | (if (and (not new-name) | 3627 | (let ((buf (sql-find-sqli-buffer product))) |
| 3397 | sql-buffer | 3628 | (if (and (not new-name) buf) |
| 3398 | (sql-buffer-live-p sql-buffer) | 3629 | (pop-to-buffer buf) |
| 3399 | (comint-check-proc sql-buffer) | 3630 | |
| 3400 | (eq product (with-current-buffer sql-buffer sql-product))) | 3631 | ;; We have a new name or sql-buffer doesn't exist or match |
| 3401 | (pop-to-buffer sql-buffer) | 3632 | ;; Start by remembering where we start |
| 3402 | 3633 | (let ((start-buffer (current-buffer)) | |
| 3403 | ;; We have a new name or sql-buffer doesn't exist or match | 3634 | new-sqli-buffer) |
| 3404 | ;; Start by remembering where we start | 3635 | |
| 3405 | (let* ((start-buffer (current-buffer)) | 3636 | ;; Get credentials. |
| 3406 | new-sqli-buffer) | 3637 | (apply 'sql-get-login (sql-get-product-feature product :sqli-login)) |
| 3407 | 3638 | ||
| 3408 | ;; Get credentials. | 3639 | ;; Connect to database. |
| 3409 | (apply 'sql-get-login (sql-get-product-feature product :sqli-login)) | 3640 | (message "Login...") |
| 3410 | 3641 | (funcall (sql-get-product-feature product :sqli-comint-func) | |
| 3411 | ;; Connect to database. | 3642 | product |
| 3412 | (message "Login...") | 3643 | (sql-get-product-feature product :sqli-options)) |
| 3413 | (funcall (sql-get-product-feature product :sqli-comint-func) | 3644 | |
| 3414 | product | 3645 | ;; Set SQLi mode. |
| 3415 | (sql-get-product-feature product :sqli-options)) | 3646 | (setq new-sqli-buffer (current-buffer)) |
| 3416 | 3647 | (let ((sql-interactive-product product)) | |
| 3417 | ;; Set SQLi mode. | 3648 | (sql-interactive-mode)) |
| 3418 | (setq new-sqli-buffer (current-buffer)) | 3649 | |
| 3419 | (let ((sql-interactive-product product)) | 3650 | ;; Set the new buffer name |
| 3420 | (sql-interactive-mode)) | 3651 | (when new-name |
| 3421 | 3652 | (sql-rename-buffer new-name)) | |
| 3422 | ;; Set the new buffer name | 3653 | |
| 3423 | (when new-name | 3654 | ;; Set `sql-buffer' in the new buffer and the start buffer |
| 3424 | (sql-rename-buffer new-name)) | 3655 | (setq sql-buffer (buffer-name new-sqli-buffer)) |
| 3425 | 3656 | (with-current-buffer start-buffer | |
| 3426 | ;; Set `sql-buffer' in the start buffer | 3657 | (setq sql-buffer (buffer-name new-sqli-buffer)) |
| 3427 | (setq sql-buffer (buffer-name new-sqli-buffer)) | 3658 | (run-hooks 'sql-set-sqli-hook)) |
| 3428 | (with-current-buffer start-buffer | 3659 | |
| 3429 | (setq sql-buffer (buffer-name new-sqli-buffer))) | 3660 | ;; All done. |
| 3430 | 3661 | (message "Login...done") | |
| 3431 | ;; All done. | 3662 | (pop-to-buffer sql-buffer))))) |
| 3432 | (message "Login...done") | ||
| 3433 | (pop-to-buffer sql-buffer)))) | ||
| 3434 | (message "No default SQL product defined. Set `sql-product'."))) | 3663 | (message "No default SQL product defined. Set `sql-product'."))) |
| 3435 | 3664 | ||
| 3436 | (defun sql-comint (product params) | 3665 | (defun sql-comint (product params) |
| @@ -3440,14 +3669,17 @@ PRODUCT is the SQL product. PARAMS is a list of strings which are | |||
| 3440 | passed as command line arguments." | 3669 | passed as command line arguments." |
| 3441 | (let ((program (sql-get-product-feature product :sqli-program)) | 3670 | (let ((program (sql-get-product-feature product :sqli-program)) |
| 3442 | (buf-name "SQL")) | 3671 | (buf-name "SQL")) |
| 3672 | ;; make sure we can find the program | ||
| 3673 | (unless (executable-find program) | ||
| 3674 | (error "Unable to locate SQL program \'%s\'" program)) | ||
| 3443 | ;; Make sure buffer name is unique | 3675 | ;; Make sure buffer name is unique |
| 3444 | (when (get-buffer (format "*%s*" buf-name)) | 3676 | (when (sql-buffer-live-p (format "*%s*" buf-name)) |
| 3445 | (setq buf-name (format "SQL-%s" product)) | 3677 | (setq buf-name (format "SQL-%s" product)) |
| 3446 | (when (get-buffer (format "*%s*" buf-name)) | 3678 | (when (sql-buffer-live-p (format "*%s*" buf-name)) |
| 3447 | (let ((i 1)) | 3679 | (let ((i 1)) |
| 3448 | (while (get-buffer (format "*%s*" | 3680 | (while (sql-buffer-live-p |
| 3449 | (setq buf-name | 3681 | (format "*%s*" |
| 3450 | (format "SQL-%s%d" product i)))) | 3682 | (setq buf-name (format "SQL-%s%d" product i)))) |
| 3451 | (setq i (1+ i)))))) | 3683 | (setq i (1+ i)))))) |
| 3452 | (set-buffer | 3684 | (set-buffer |
| 3453 | (apply 'make-comint buf-name program nil params)))) | 3685 | (apply 'make-comint buf-name program nil params)))) |
| @@ -3890,6 +4122,8 @@ Try to set `comint-output-filter-functions' like this: | |||
| 3890 | (setq params (append (list "-h" sql-server) params))) | 4122 | (setq params (append (list "-h" sql-server) params))) |
| 3891 | (if (not (string= "" sql-user)) | 4123 | (if (not (string= "" sql-user)) |
| 3892 | (setq params (append (list "-U" sql-user) params))) | 4124 | (setq params (append (list "-U" sql-user) params))) |
| 4125 | (if (not (= 0 sql-port)) | ||
| 4126 | (setq params (append (list "-p" sql-port) params))) | ||
| 3893 | (sql-comint product params))) | 4127 | (sql-comint product params))) |
| 3894 | 4128 | ||
| 3895 | 4129 | ||