comparison lisp/progmodes/sql.el @ 110424:03a492f2d1ce

SQL Mode, Version 2.8 - sql-list-all and sql-list-table functions. * progmodes/sql.el: Version 2.8 (sql-login-params): Updated widget structure; changes still needed. (sql-product-alist): Add :list-all and :list-table features for SQLite, Postgres and MySQL products. (sql-redirect): Handle default value. (sql-execute, sql-execute-feature): New functions. (sql-read-table-name): New function. (sql-list-all, sql-list-table): New functions. User API (sql-mode-map, sql-interactive-mode-map): Add key definitions for above functions. (sql-mode-menu, sql-interactive-mode-menu): Add menu definitions for above functions. (sql-postgres-login-params): Add user and database defaults. (sql-buffer-live-p): Bug fix. (sql-product-history); New variable. (sql-read-product): New function. Use it. (sql-set-product, sql-product-interactive): Use it. (sql-connection-history): New variable. (sql-read-connection): New function. Use it. (sql-connect): New function. (sql-for-each-login): Redesign function interface. (sql-make-alternate-buffer-name, sql-save-connection): Use it. (sql-get-login-ext, sql-get-login): Use it. Handle default values. (sql-comint): Check for program. Existing live buffer. (sql-comint-postgres): Add port parameter.
author Michael Mauger <mmaug@yahoo.com>
date Sat, 18 Sep 2010 22:11:18 -0400
parents ba7558616802
children 029e4783cbae
comparison
equal deleted inserted replaced
110423:6c2baabc9d98 110424:03a492f2d1ce
3 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 3 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
4 ;; 2007, 2008, 2009, 2010 Free Software Foundation, Inc. 4 ;; 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
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.7 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
15 ;; GNU Emacs is free software: you can redistribute it and/or modify 14 ;; GNU Emacs is free software: you can redistribute it and/or modify
16 ;; it under the terms of the GNU General Public License as published by 15 ;; it under the terms of the GNU General Public License as published by
284 283
285 ;; Login parameter type 284 ;; Login parameter type
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)
292 (const password) 294 (const password)
293 (choice :tag "server" 295 (choice :tag "server"
298 regexp) 300 regexp)
299 (list :tag "completion" 301 (list :tag "completion"
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"
307 (const :format "" database) 309 (const :format "" database)
308 (const :format "" :file) 310 (const :format "" :file)
309 regexp) 311 regexp)
310 (list :tag "completion" 312 (list :tag "completion"
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
318 320
319 (defvar sql-interactive-product nil 321 (defvar sql-interactive-product nil
399 :font-lock sql-mode-mysql-font-lock-keywords 401 :font-lock sql-mode-mysql-font-lock-keywords
400 :sqli-program sql-mysql-program 402 :sqli-program sql-mysql-program
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 "^ -> "
407 :input-filter sql-remove-tabs-filter) 411 :input-filter sql-remove-tabs-filter)
408 412
426 :font-lock sql-mode-postgres-font-lock-keywords 430 :font-lock sql-mode-postgres-font-lock-keywords
427 :sqli-program sql-postgres-program 431 :sqli-program sql-postgres-program
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 "^.*[-(][#>] "
434 :input-filter sql-remove-tabs-filter 440 :input-filter sql-remove-tabs-filter
435 :terminator ("\\(^\\s-*\\\\g\\|;\\)" . ";")) 441 :terminator ("\\(^\\s-*\\\\g\\|;\\)" . ";"))
450 :font-lock sql-mode-sqlite-font-lock-keywords 456 :font-lock sql-mode-sqlite-font-lock-keywords
451 :sqli-program sql-sqlite-program 457 :sqli-program sql-sqlite-program
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 "^ ...> "
458 :terminator ";") 466 :terminator ";")
459 467
507 `sql-user', `sql-password', 515 `sql-user', `sql-password',
508 `sql-database' and `sql-server' to open a 516 `sql-database' and `sql-server' to open a
509 comint buffer and connect to the 517 comint buffer and connect to the
510 database. Do product specific 518 database. Do product specific
511 configuration of comint in this function. 519 configuration of comint in this function.
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.
512 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.
516 541
939 add your name with a \"-U\" prefix (such as \"-Umark\") to the list." 964 add your name with a \"-U\" prefix (such as \"-Umark\") to the list."
940 :type '(repeat string) 965 :type '(repeat string)
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"
948 :group 'SQL) 975 :group 'SQL)
949 976
1022 1049
1023 (defvar sql-server-history nil 1050 (defvar sql-server-history nil
1024 "History of servers used.") 1051 "History of servers used.")
1025 1052
1026 ;; Passwords are not kept in a history. 1053 ;; Passwords are not kept in a history.
1054
1055 (defvar sql-product-history nil
1056 "History of products used.")
1057
1058 (defvar sql-connection-history nil
1059 "History of connections used.")
1027 1060
1028 (defvar sql-buffer nil 1061 (defvar sql-buffer nil
1029 "Current SQLi buffer. 1062 "Current SQLi buffer.
1030 1063
1031 The global value of `sql-buffer' is the name of the latest SQLi buffer 1064 The global value of `sql-buffer' is the name of the latest SQLi buffer
1065 (and buffer 1098 (and buffer
1066 (buffer-live-p buffer) 1099 (buffer-live-p buffer)
1067 (get-buffer-process buffer) 1100 (get-buffer-process buffer)
1068 (comint-check-proc buffer) 1101 (comint-check-proc buffer)
1069 (with-current-buffer buffer 1102 (with-current-buffer buffer
1070 (and (derived-mode-p 'sql-product-interactive) 1103 (and (derived-mode-p 'sql-interactive-mode)
1071 (or (not product) 1104 (or (not product)
1072 (eq product sql-product))))))) 1105 (eq product sql-product)))))))
1073 1106
1074 ;; Keymap for sql-interactive-mode. 1107 ;; Keymap for sql-interactive-mode.
1075 1108
1084 (define-key map (kbd "C-j") 'sql-accumulate-and-indent) 1117 (define-key map (kbd "C-j") 'sql-accumulate-and-indent)
1085 (define-key map (kbd "C-c C-w") 'sql-copy-column) 1118 (define-key map (kbd "C-c C-w") 'sql-copy-column)
1086 (define-key map (kbd "O") 'sql-magic-go) 1119 (define-key map (kbd "O") 'sql-magic-go)
1087 (define-key map (kbd "o") 'sql-magic-go) 1120 (define-key map (kbd "o") 'sql-magic-go)
1088 (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)
1089 map) 1124 map)
1090 "Mode map used for `sql-interactive-mode'. 1125 "Mode map used for `sql-interactive-mode'.
1091 Based on `comint-mode-map'.") 1126 Based on `comint-mode-map'.")
1092 1127
1093 ;; Keymap for sql-mode. 1128 ;; Keymap for sql-mode.
1097 (define-key map (kbd "C-c C-c") 'sql-send-paragraph) 1132 (define-key map (kbd "C-c C-c") 'sql-send-paragraph)
1098 (define-key map (kbd "C-c C-r") 'sql-send-region) 1133 (define-key map (kbd "C-c C-r") 'sql-send-region)
1099 (define-key map (kbd "C-c C-s") 'sql-send-string) 1134 (define-key map (kbd "C-c C-s") 'sql-send-string)
1100 (define-key map (kbd "C-c C-b") 'sql-send-buffer) 1135 (define-key map (kbd "C-c C-b") 'sql-send-buffer)
1101 (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)
1102 map) 1139 map)
1103 "Mode map used for `sql-mode'.") 1140 "Mode map used for `sql-mode'.")
1104 1141
1105 ;; easy menu for sql-mode. 1142 ;; easy menu for sql-mode.
1106 1143
1111 ["Send Paragraph" sql-send-paragraph (sql-buffer-live-p sql-buffer)] 1148 ["Send Paragraph" sql-send-paragraph (sql-buffer-live-p sql-buffer)]
1112 ["Send Region" sql-send-region (and mark-active 1149 ["Send Region" sql-send-region (and mark-active
1113 (sql-buffer-live-p sql-buffer))] 1150 (sql-buffer-live-p sql-buffer))]
1114 ["Send Buffer" sql-send-buffer (sql-buffer-live-p sql-buffer)] 1151 ["Send Buffer" sql-send-buffer (sql-buffer-live-p sql-buffer)]
1115 ["Send String" sql-send-string (sql-buffer-live-p sql-buffer)] 1152 ["Send String" sql-send-string (sql-buffer-live-p sql-buffer)]
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)]
1116 "--" 1156 "--"
1117 ["Start SQLi session" sql-product-interactive 1157 ["Start SQLi session" sql-product-interactive
1118 :visible (not sql-connection-alist) 1158 :visible (not sql-connection-alist)
1119 :enable (sql-get-product-feature sql-product :sqli-comint-func)] 1159 :enable (sql-get-product-feature sql-product :sqli-comint-func)]
1120 ("Start..." 1160 ("Start..."
1150 (easy-menu-define 1190 (easy-menu-define
1151 sql-interactive-mode-menu sql-interactive-mode-map 1191 sql-interactive-mode-menu sql-interactive-mode-map
1152 "Menu for `sql-interactive-mode'." 1192 "Menu for `sql-interactive-mode'."
1153 '("SQL" 1193 '("SQL"
1154 ["Rename Buffer" sql-rename-buffer t] 1194 ["Rename Buffer" sql-rename-buffer t]
1155 ["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]))
1156 1199
1157 ;; Abbreviations -- if you want more of them, define them in your 1200 ;; Abbreviations -- if you want more of them, define them in your
1158 ;; ~/.emacs file. Abbrevs have to be enabled in your ~/.emacs, too. 1201 ;; ~/.emacs file. Abbrevs have to be enabled in your ~/.emacs, too.
1159 1202
1160 (defvar sql-mode-abbrev-table nil 1203 (defvar sql-mode-abbrev-table nil
2133 2176
2134 2177
2135 2178
2136 ;;; SQL Product support functions 2179 ;;; SQL Product support functions
2137 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
2138 (defun sql-add-product (product display &rest plist) 2191 (defun sql-add-product (product display &rest plist)
2139 "Add support for a database product in `sql-mode'. 2192 "Add support for a database product in `sql-mode'.
2140 2193
2141 Add PRODUCT to `sql-product-alist' which enables `sql-mode' to 2194 Add PRODUCT to `sql-product-alist' which enables `sql-mode' to
2142 properly support syntax highlighting and interactive interaction. 2195 properly support syntax highlighting and interactive interaction.
2323 2376
2324 (delq nil 2377 (delq nil
2325 (mapcar 2378 (mapcar
2326 (lambda (param) 2379 (lambda (param)
2327 (let ((token (or (and (listp param) (car param)) param)) 2380 (let ((token (or (and (listp param) (car param)) param))
2328 (type (or (and (listp param) (nth 1 param)) nil)) 2381 (plist (or (and (listp param) (cdr param)) nil)))
2329 (arg (or (and (listp param) (nth 2 param)) nil))) 2382
2330 2383 (funcall body token plist)))
2331 (funcall body token type arg)))
2332 login-params))) 2384 login-params)))
2333 2385
2334 2386
2335 2387
2336 ;;; Functions to switch highlighting 2388 ;;; Functions to switch highlighting
2346 (symbol-name sql-product)) "]")))) 2398 (symbol-name sql-product)) "]"))))
2347 2399
2348 (defun sql-set-product (product) 2400 (defun sql-set-product (product)
2349 "Set `sql-product' to PRODUCT and enable appropriate highlighting." 2401 "Set `sql-product' to PRODUCT and enable appropriate highlighting."
2350 (interactive 2402 (interactive
2351 (list (completing-read "SQL product: " 2403 (list (sql-read-product "SQL product: ")))
2352 (mapcar (lambda (info) (symbol-name (car info)))
2353 sql-product-alist)
2354 nil 'require-match
2355 (or (and sql-product (symbol-name sql-product)) "ansi"))))
2356 (if (stringp product) (setq product (intern product))) 2404 (if (stringp product) (setq product (intern product)))
2357 (when (not (assoc product sql-product-alist)) 2405 (when (not (assoc product sql-product-alist))
2358 (error "SQL product %s is not supported; treated as ANSI" product) 2406 (error "SQL product %s is not supported; treated as ANSI" product)
2359 (setq product 'ansi)) 2407 (setq product 'ansi))
2360 2408
2490 2538
2491 (defun sql-read-passwd (prompt &optional default) 2539 (defun sql-read-passwd (prompt &optional default)
2492 "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."
2493 (read-passwd prompt nil default)) 2541 (read-passwd prompt nil default))
2494 2542
2495 (defun sql-get-login-ext (prompt last-value history-var type arg) 2543 (defun sql-get-login-ext (prompt last-value history-var plist)
2496 "Prompt user with extended login parameters. 2544 "Prompt user with extended login parameters.
2497 2545
2498 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
2499 value. 2547 value.
2500 2548
2501 If TYPE is `:file', then the user is prompted for a file 2549 The property `:default' specifies the default value. If the
2502 name that must match the regexp pattern specified in the ARG 2550 `:number' property is non-nil then ask for a number.
2503 argument. 2551
2504 2552 The `:file' property prompts for a file name that must match the
2505 If TYPE is `:completion', then the user is prompted for a string 2553 regexp pattern specified in its value.
2506 specified by ARG. (ARG is used as the PREDICATE argument to 2554
2555 The `:completion' property prompts for a string specified by its
2556 value. (The property value is used as the PREDICATE argument to
2507 `completing-read'.)" 2557 `completing-read'.)"
2508 (cond 2558 (let* ((default (plist-get plist :default))
2509 ((eq type nil) 2559 (prompt-def
2510 (read-from-minibuffer prompt last-value nil nil history-var)) 2560 (if default
2511 2561 (if (string-match "\\(\\):[ \t]*\\'" prompt)
2512 ((eq type :file) 2562 (replace-match (format " (default \"%s\")" default) t t prompt 1)
2513 (let ((use-dialog-box nil)) 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)
2514 (expand-file-name 2570 (expand-file-name
2515 (read-file-name prompt 2571 (read-file-name prompt
2516 (file-name-directory last-value) nil t 2572 (file-name-directory last-value) default t
2517 (file-name-nondirectory last-value) 2573 (file-name-nondirectory last-value)
2518 (if arg 2574 (when (plist-get plist :file)
2519 `(lambda (f) 2575 `(lambda (f)
2520 (string-match (concat "\\<" ,arg "\\>") 2576 (string-match
2521 (file-name-nondirectory f))) 2577 (concat "\\<" ,(plist-get plist :file) "\\>")
2522 nil))))) 2578 (file-name-nondirectory f)))))))
2523 2579
2524 ((eq type :completion) 2580 ((plist-member plist :completion)
2525 (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))))))
2526 2590
2527 (defun sql-get-login (&rest what) 2591 (defun sql-get-login (&rest what)
2528 "Get username, password and database from the user. 2592 "Get username, password and database from the user.
2529 2593
2530 The variables `sql-user', `sql-password', `sql-server', and 2594 The variables `sql-user', `sql-password', `sql-server', and
2539 symbol `password', for the server if it contains the symbol 2603 symbol `password', for the server if it contains the symbol
2540 `server', and for the database if it contains the symbol 2604 `server', and for the database if it contains the symbol
2541 `database'. The members of WHAT are processed in the order in 2605 `database'. The members of WHAT are processed in the order in
2542 which they are provided. 2606 which they are provided.
2543 2607
2544 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
2545 control or limit the values that can be supplied. These can be 2609 plist of options as the cdr. The following properties are
2546 of the form: 2610 supported:
2547 2611
2548 \(database :file \".+\\\\.EXT\") 2612 :file <filename-regexp>
2549 \(database :completion FUNCTION) 2613 :completion <list-of-strings-or-function>
2550 2614 :default <default-value>
2551 The `server' token supports the same forms. 2615 :number t
2552 2616
2553 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
2554 function like this: (sql-get-login 'user 'password 'database)." 2618 function like this: (sql-get-login 'user 'password 'database)."
2555 (interactive) 2619 (interactive)
2556 (mapcar 2620 (mapcar
2557 (lambda (w) 2621 (lambda (w)
2558 (let ((token (or (and (listp w) (car w)) w)) 2622 (let ((token (or (and (consp w) (car w)) w))
2559 (type (or (and (listp w) (nth 1 w)) nil)) 2623 (plist (or (and (consp w) (cdr w)) nil)))
2560 (arg (or (and (listp w) (nth 2 w)) nil))) 2624
2561 2625 (cond
2562 (cond 2626 ((eq token 'user) ; user
2563 ((eq token 'user) ; user 2627 (setq sql-user
2564 (setq sql-user 2628 (sql-get-login-ext "User: " sql-user
2565 (read-from-minibuffer "User: " sql-user nil nil 2629 'sql-user-history plist)))
2566 'sql-user-history))) 2630
2567 2631 ((eq token 'password) ; password
2568 ((eq token 'password) ; password 2632 (setq sql-password
2569 (setq sql-password 2633 (sql-read-passwd "Password: " sql-password)))
2570 (sql-read-passwd "Password: " sql-password))) 2634
2571 2635 ((eq token 'server) ; server
2572 ((eq token 'server) ; server 2636 (setq sql-server
2573 (setq sql-server 2637 (sql-get-login-ext "Server: " sql-server
2574 (sql-get-login-ext "Server: " sql-server 2638 'sql-server-history plist)))
2575 'sql-server-history type arg))) 2639
2576 2640 ((eq token 'database) ; database
2577 ((eq token 'database) ; database 2641 (setq sql-database
2578 (setq sql-database 2642 (sql-get-login-ext "Database: " sql-database
2579 (sql-get-login-ext "Database: " sql-database 2643 'sql-database-history plist)))
2580 'sql-database-history type arg))) 2644
2581 2645 ((eq token 'port) ; port
2582 ((eq token 'port) ; port 2646 (setq sql-port
2583 (setq sql-port 2647 (sql-get-login-ext "Port: " sql-port
2584 (read-number "Port: " (if (numberp sql-port) 2648 nil (append '(:number t) plist)))))))
2585 sql-port 2649 what))
2586 0))))))) 2650
2587 what)) 2651 (defun sql-find-sqli-buffer (&optional product)
2588
2589 (defun sql-find-sqli-buffer ()
2590 "Returns the name of the current default SQLi buffer or nil. 2652 "Returns the name of the current default SQLi buffer or nil.
2591 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
2592 `sql-interactive-mode' and have a process." 2654 `sql-interactive-mode' and have a process."
2593 (let ((buf sql-buffer) 2655 (let ((buf sql-buffer)
2594 (prod sql-product)) 2656 (prod (or product sql-product)))
2595 (or 2657 (or
2596 ;; Current sql-buffer, if there is one. 2658 ;; Current sql-buffer, if there is one.
2597 (and (sql-buffer-live-p buf prod) 2659 (and (sql-buffer-live-p buf prod)
2598 buf) 2660 buf)
2599 ;; Global sql-buffer 2661 ;; Global sql-buffer
2687 (apply 'concat 2749 (apply 'concat
2688 (cdr 2750 (cdr
2689 (apply 'append nil 2751 (apply 'append nil
2690 (sql-for-each-login 2752 (sql-for-each-login
2691 (sql-get-product-feature sql-product :sqli-login) 2753 (sql-get-product-feature sql-product :sqli-login)
2692 (lambda (token type arg) 2754 (lambda (token plist)
2693 (cond 2755 (cond
2694 ((eq token 'user) 2756 ((eq token 'user)
2695 (unless (string= "" sql-user) 2757 (unless (string= "" sql-user)
2696 (list "/" sql-user))) 2758 (list "/" sql-user)))
2697 ((eq token 'port) 2759 ((eq token 'port)
2699 (= 0 sql-port)) 2761 (= 0 sql-port))
2700 (list ":" (number-to-string sql-port)))) 2762 (list ":" (number-to-string sql-port))))
2701 ((eq token 'server) 2763 ((eq token 'server)
2702 (unless (string= "" sql-server) 2764 (unless (string= "" sql-server)
2703 (list "." 2765 (list "."
2704 (if (eq type :file) 2766 (if (plist-member plist :file)
2705 (file-name-nondirectory sql-server) 2767 (file-name-nondirectory sql-server)
2706 sql-server)))) 2768 sql-server))))
2707 ((eq token 'database) 2769 ((eq token 'database)
2708 (unless (string= "" sql-database) 2770 (unless (string= "" sql-database)
2709 (list "@" 2771 (list "@"
2710 (if (eq type :file) 2772 (if (plist-member plist :file)
2711 (file-name-nondirectory sql-database) 2773 (file-name-nondirectory sql-database)
2712 sql-database)))) 2774 sql-database))))
2713 2775
2714 ((eq token 'password) nil) 2776 ((eq token 'password) nil)
2715 (t nil)))))))) 2777 (t nil))))))))
3017 (proc (get-buffer-process (current-buffer))) 3079 (proc (get-buffer-process (current-buffer)))
3018 (comint-prompt-regexp (sql-get-product-feature sql-product 3080 (comint-prompt-regexp (sql-get-product-feature sql-product
3019 :prompt-regexp)) 3081 :prompt-regexp))
3020 (start nil)) 3082 (start nil))
3021 (with-current-buffer buf 3083 (with-current-buffer buf
3084 (toggle-read-only -1)
3022 (unless save-prior 3085 (unless save-prior
3023 (erase-buffer)) 3086 (erase-buffer))
3024 (goto-char (point-max)) 3087 (goto-char (point-max))
3088 (unless (zerop (buffer-size))
3089 (insert "\n"))
3025 (setq start (point))) 3090 (setq start (point)))
3026 3091
3027 ;; Run the command 3092 ;; Run the command
3093 (message "Executing SQL command...")
3028 (comint-redirect-send-command-to-process command buf proc nil t) 3094 (comint-redirect-send-command-to-process command buf proc nil t)
3029 (while (null comint-redirect-completed) 3095 (while (null comint-redirect-completed)
3030 (accept-process-output nil 1)) 3096 (accept-process-output nil 1))
3031 3097 (message "Executing SQL command...done")
3032 ;; Remove echo if there was one 3098
3099 ;; Clean up the output results
3033 (with-current-buffer buf 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
3034 (goto-char start) 3106 (goto-char start)
3035 (when (looking-at (concat "^" (regexp-quote command) "[\\n]")) 3107 (when (looking-at (concat "^" (regexp-quote command) "[\\n]"))
3036 (delete-region (match-beginning 0) (match-end 0))) 3108 (delete-region (match-beginning 0) (match-end 0)))
3037 (goto-char start))))) 3109 (goto-char start)))))
3038 3110
3062 (push (match-string i) r)) 3134 (push (match-string i) r))
3063 (nreverse r))) 3135 (nreverse r)))
3064 ;; one group specified 3136 ;; one group specified
3065 ((numberp regexp-groups) 3137 ((numberp regexp-groups)
3066 (match-string regexp-groups)) 3138 (match-string regexp-groups))
3067 ;; (buffer-substring-no-properties
3068 ;; (match-beginning regexp-groups)
3069 ;; (match-end regexp-groups)))
3070 ;; list of numbers; return the specified matches only 3139 ;; list of numbers; return the specified matches only
3071 ((consp regexp-groups) 3140 ((consp regexp-groups)
3072 (mapcar (lambda (c) 3141 (mapcar (lambda (c)
3073 (cond 3142 (cond
3074 ((numberp c) (match-string c)) 3143 ((numberp c) (match-string c))
3081 (t 3150 (t
3082 (error "sql-redirect-value: unknown REGEXP-GROUPS value - %s" 3151 (error "sql-redirect-value: unknown REGEXP-GROUPS value - %s"
3083 regexp-groups))) 3152 regexp-groups)))
3084 results))) 3153 results)))
3085 (nreverse 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)))
3086 3228
3087 3229
3088 3230
3089 ;;; SQL mode -- uses SQL interactive mode 3231 ;;; SQL mode -- uses SQL interactive mode
3090 3232
3311 3453
3312 3454
3313 3455
3314 ;;; Connection handling 3456 ;;; Connection handling
3315 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
3316 ;;;###autoload 3466 ;;;###autoload
3317 (defun sql-connect (connection) 3467 (defun sql-connect (connection)
3318 "Connect to an interactive session using CONNECTION settings. 3468 "Connect to an interactive session using CONNECTION settings.
3319 3469
3320 See `sql-connection-alist' to see how to define connections and 3470 See `sql-connection-alist' to see how to define connections and
3324 is specified in the connection settings." 3474 is specified in the connection settings."
3325 3475
3326 ;; Prompt for the connection from those defined in the alist 3476 ;; Prompt for the connection from those defined in the alist
3327 (interactive 3477 (interactive
3328 (if sql-connection-alist 3478 (if sql-connection-alist
3329 (list 3479 (list (sql-read-connection "Connection: " nil '(nil)))
3330 (let ((completion-ignore-case t))
3331 (completing-read "Connection: "
3332 (mapcar (lambda (c) (car c))
3333 sql-connection-alist)
3334 nil t nil nil '(()))))
3335 nil)) 3480 nil))
3336 3481
3337 ;; Are there connections defined 3482 ;; Are there connections defined
3338 (if sql-connection-alist 3483 (if sql-connection-alist
3339 ;; Was one selected 3484 ;; Was one selected
3363 (t (car v)))) 3508 (t (car v))))
3364 (cdr connect-set))) 3509 (cdr connect-set)))
3365 ;; the remaining params (w/o the connection params) 3510 ;; the remaining params (w/o the connection params)
3366 (rem-params (sql-for-each-login 3511 (rem-params (sql-for-each-login
3367 login-params 3512 login-params
3368 (lambda (token type arg) 3513 (lambda (token plist)
3369 (unless (member token set-params) 3514 (unless (member token set-params)
3370 (if (or type arg) 3515 (if plist
3371 (list token type arg) 3516 (cons token plist)
3372 token))))) 3517 token)))))
3373 ;; Remember the connection 3518 ;; Remember the connection
3374 (sql-connection connection)) 3519 (sql-connection connection))
3375 3520
3376 ;; Set the remaining parameters and start the 3521 ;; Set the remaining parameters and start the
3407 (message "Connection <%s> already exists" name) 3552 (message "Connection <%s> already exists" name)
3408 (setq connect 3553 (setq connect
3409 (append (list name) 3554 (append (list name)
3410 (sql-for-each-login 3555 (sql-for-each-login
3411 `(product ,@login) 3556 `(product ,@login)
3412 (lambda (token type arg) 3557 (lambda (token plist)
3413 (cond 3558 (cond
3414 ((eq token 'product) `(sql-product ',sql-product)) 3559 ((eq token 'product) `(sql-product ',sql-product))
3415 ((eq token 'user) `(sql-user ,sql-user)) 3560 ((eq token 'user) `(sql-user ,sql-user))
3416 ((eq token 'database) `(sql-database ,sql-database)) 3561 ((eq token 'database) `(sql-database ,sql-database))
3417 ((eq token 'server) `(sql-server ,sql-server)) 3562 ((eq token 'server) `(sql-server ,sql-server))
3458 ;; Handle universal arguments if specified 3603 ;; Handle universal arguments if specified
3459 (when (not (or executing-kbd-macro noninteractive)) 3604 (when (not (or executing-kbd-macro noninteractive))
3460 (when (and (consp product) 3605 (when (and (consp product)
3461 (not (cdr product)) 3606 (not (cdr product))
3462 (numberp (car product))) 3607 (numberp (car product)))
3463 (when (>= (car product) 16) 3608 (when (>= (prefix-numeric-value product) 16)
3464 (when (not new-name) 3609 (when (not new-name)
3465 (setq new-name '(4))) 3610 (setq new-name '(4)))
3466 (setq product '(4))))) 3611 (setq product '(4)))))
3467 3612
3468 ;; Get the value of product that we need 3613 ;; Get the value of product that we need
3469 (setq product 3614 (setq product
3470 (cond 3615 (cond
3471 ((equal product '(4)) ; C-u, prompt for product
3472 (intern (completing-read "SQL product: "
3473 (mapcar (lambda (info) (symbol-name (car info)))
3474 sql-product-alist)
3475 nil 'require-match
3476 (or (and sql-product
3477 (symbol-name sql-product))
3478 "ansi"))))
3479 ((and product ; Product specified 3616 ((and product ; Product specified
3480 (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))
3481 (t sql-product))) ; Default to sql-product 3620 (t sql-product))) ; Default to sql-product
3482 3621
3483 ;; If we have a product and it has a interactive mode 3622 ;; If we have a product and it has a interactive mode
3484 (if product 3623 (if product
3485 (when (sql-get-product-feature product :sqli-comint-func) 3624 (when (sql-get-product-feature product :sqli-comint-func)
3486 ;; 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
3487 ;; the same product 3626 ;; interactive for the same product
3488 (if (and (not new-name) 3627 (let ((buf (sql-find-sqli-buffer product)))
3489 (sql-buffer-live-p sql-buffer product)) 3628 (if (and (not new-name) buf)
3490 (pop-to-buffer sql-buffer) 3629 (pop-to-buffer buf)
3491 3630
3492 ;; We have a new name or sql-buffer doesn't exist or match 3631 ;; We have a new name or sql-buffer doesn't exist or match
3493 ;; Start by remembering where we start 3632 ;; Start by remembering where we start
3494 (let* ((start-buffer (current-buffer)) 3633 (let ((start-buffer (current-buffer))
3495 new-sqli-buffer) 3634 new-sqli-buffer)
3496 3635
3497 ;; Get credentials. 3636 ;; Get credentials.
3498 (apply 'sql-get-login (sql-get-product-feature product :sqli-login)) 3637 (apply 'sql-get-login (sql-get-product-feature product :sqli-login))
3499 3638
3500 ;; Connect to database. 3639 ;; Connect to database.
3501 (message "Login...") 3640 (message "Login...")
3502 (funcall (sql-get-product-feature product :sqli-comint-func) 3641 (funcall (sql-get-product-feature product :sqli-comint-func)
3503 product 3642 product
3504 (sql-get-product-feature product :sqli-options)) 3643 (sql-get-product-feature product :sqli-options))
3505 3644
3506 ;; Set SQLi mode. 3645 ;; Set SQLi mode.
3507 (setq new-sqli-buffer (current-buffer)) 3646 (setq new-sqli-buffer (current-buffer))
3508 (let ((sql-interactive-product product)) 3647 (let ((sql-interactive-product product))
3509 (sql-interactive-mode)) 3648 (sql-interactive-mode))
3510 3649
3511 ;; Set the new buffer name 3650 ;; Set the new buffer name
3512 (when new-name 3651 (when new-name
3513 (sql-rename-buffer new-name)) 3652 (sql-rename-buffer new-name))
3514 3653
3515 ;; Set `sql-buffer' in the new buffer and the start buffer 3654 ;; Set `sql-buffer' in the new buffer and the start buffer
3516 (setq sql-buffer (buffer-name new-sqli-buffer))
3517 (with-current-buffer start-buffer
3518 (setq sql-buffer (buffer-name new-sqli-buffer)) 3655 (setq sql-buffer (buffer-name new-sqli-buffer))
3519 (run-hooks 'sql-set-sqli-hook)) 3656 (with-current-buffer start-buffer
3520 3657 (setq sql-buffer (buffer-name new-sqli-buffer))
3521 ;; All done. 3658 (run-hooks 'sql-set-sqli-hook))
3522 (message "Login...done") 3659
3523 (pop-to-buffer sql-buffer)))) 3660 ;; All done.
3661 (message "Login...done")
3662 (pop-to-buffer sql-buffer)))))
3524 (message "No default SQL product defined. Set `sql-product'."))) 3663 (message "No default SQL product defined. Set `sql-product'.")))
3525 3664
3526 (defun sql-comint (product params) 3665 (defun sql-comint (product params)
3527 "Set up a comint buffer to run the SQL processor. 3666 "Set up a comint buffer to run the SQL processor.
3528 3667
3529 PRODUCT is the SQL product. PARAMS is a list of strings which are 3668 PRODUCT is the SQL product. PARAMS is a list of strings which are
3530 passed as command line arguments." 3669 passed as command line arguments."
3531 (let ((program (sql-get-product-feature product :sqli-program)) 3670 (let ((program (sql-get-product-feature product :sqli-program))
3532 (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))
3533 ;; Make sure buffer name is unique 3675 ;; Make sure buffer name is unique
3534 (when (get-buffer (format "*%s*" buf-name)) 3676 (when (sql-buffer-live-p (format "*%s*" buf-name))
3535 (setq buf-name (format "SQL-%s" product)) 3677 (setq buf-name (format "SQL-%s" product))
3536 (when (get-buffer (format "*%s*" buf-name)) 3678 (when (sql-buffer-live-p (format "*%s*" buf-name))
3537 (let ((i 1)) 3679 (let ((i 1))
3538 (while (get-buffer (format "*%s*" 3680 (while (sql-buffer-live-p
3539 (setq buf-name 3681 (format "*%s*"
3540 (format "SQL-%s%d" product i)))) 3682 (setq buf-name (format "SQL-%s%d" product i))))
3541 (setq i (1+ i)))))) 3683 (setq i (1+ i))))))
3542 (set-buffer 3684 (set-buffer
3543 (apply 'make-comint buf-name program nil params)))) 3685 (apply 'make-comint buf-name program nil params))))
3544 3686
3545 ;;;###autoload 3687 ;;;###autoload
3978 (setq params (append params (list sql-database)))) 4120 (setq params (append params (list sql-database))))
3979 (if (not (string= "" sql-server)) 4121 (if (not (string= "" sql-server))
3980 (setq params (append (list "-h" sql-server) params))) 4122 (setq params (append (list "-h" sql-server) params)))
3981 (if (not (string= "" sql-user)) 4123 (if (not (string= "" sql-user))
3982 (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)))
3983 (sql-comint product params))) 4127 (sql-comint product params)))
3984 4128
3985 4129
3986 4130
3987 ;;;###autoload 4131 ;;;###autoload