;; Author: Alex Schroeder <alex@gnu.org>
;; Maintainer: Michael Mauger <mmaug@yahoo.com>
-;; Version: 2.1
+;; Version: 2.2
;; Keywords: comm languages processes
;; URL: http://savannah.gnu.org/cgi-bin/viewcvs/emacs/emacs/lisp/progmodes/sql.el
;; URL: http://www.emacswiki.org/cgi-bin/wiki.pl?SqlMode
;; (const user)
;; (const password)
;; (const server)
-;; (const database)))
+;; (const database)
+;; (const port)))
;; :group 'SQL)
;;
;; (sql-set-product-feature 'xyz
;; (sql-set-product-feature 'xyz
;; :sqli-options 'my-sql-xyz-options))
-;; (defun my-sql-connect-xyz (product options)
+;; (defun my-sql-comint-xyz (product options)
;; "Connect ti XyzDB in a comint buffer."
;;
;; ;; Do something with `sql-user', `sql-password',
;; (setq params (append (list "-P" sql-password) params)))
;; (if (not (string= "" sql-user))
;; (setq params (append (list "-U" sql-user) params)))
-;; (sql-connect product params)))
+;; (sql-comint product params)))
;;
;; (sql-set-product-feature 'xyz
-;; :sqli-connect-func 'my-sql-connect-xyz)
+;; :sqli-connect-func 'my-sql-comint-xyz)
;; 6) Define a convienence function to invoke the SQL interpreter.
(eval-when-compile
(require 'regexp-opt))
(require 'custom)
+(require 'assoc)
(eval-when-compile ;; needed in Emacs 19, 20
(setq max-specpdl-size 2000))
(defcustom sql-user ""
"Default username."
:type 'string
- :group 'SQL)
-(put 'sql-user 'safe-local-variable 'stringp)
+ :group 'SQL
+ :safe 'stringp)
(defcustom sql-password ""
"Default password.
Storing your password in a textfile such as ~/.emacs could be dangerous.
Customizing your password will store it in your ~/.emacs file."
:type 'string
- :group 'SQL)
-(put 'sql-password 'risky-local-variable t)
+ :group 'SQL
+ :risky t)
(defcustom sql-database ""
"Default database."
:type 'string
- :group 'SQL)
-(put 'sql-database 'safe-local-variable 'stringp)
+ :group 'SQL
+ :safe 'stringp)
(defcustom sql-server ""
"Default server or host."
:type 'string
- :group 'SQL)
-(put 'sql-server 'safe-local-variable 'stringp)
+ :group 'SQL
+ :safe 'stringp)
(defcustom sql-port nil
"Default server or host."
+ :version "24.1"
:type 'number
- :group 'SQL)
-(put 'sql-port 'safe-local-variable 'numberp)
+ :group 'SQL
+ :safe 'numberp)
;; SQL Product support
(defvar sql-interactive-product nil
"Product under `sql-interactive-mode'.")
+(defvar sql-connection nil
+ "Connection name if interactive session started by `sql-connect'.")
+
(defvar sql-product-alist
'((ansi
:name "ANSI"
:sqli-program sql-db2-program
:sqli-options sql-db2-options
:sqli-login sql-db2-login-params
- :sqli-connect-func sql-connect-db2
+ :sqli-comint-func sql-comint-db2
:prompt-regexp "^db2 => "
:prompt-length 7
:input-filter sql-escape-newlines-filter)
:sqli-program sql-informix-program
:sqli-options sql-informix-options
:sqli-login sql-informix-login-params
- :sqli-connect-func sql-connect-informix
+ :sqli-comint-func sql-comint-informix
:prompt-regexp "^> "
:prompt-length 2
:syntax-alist ((?{ . "<") (?} . ">")))
:sqli-program sql-ingres-program
:sqli-options sql-ingres-options
:sqli-login sql-ingres-login-params
- :sqli-connect-func sql-connect-ingres
+ :sqli-comint-func sql-comint-ingres
:prompt-regexp "^\* "
:prompt-length 2)
:sqli-program sql-interbase-program
:sqli-options sql-interbase-options
:sqli-login sql-interbase-login-params
- :sqli-connect-func sql-connect-interbase
+ :sqli-comint-func sql-comint-interbase
:prompt-regexp "^SQL> "
:prompt-length 5)
:sqli-program sql-linter-program
:sqli-options sql-linter-options
:sqli-login sql-linter-login-params
- :sqli-connect-func sql-connect-linter
+ :sqli-comint-func sql-comint-linter
:prompt-regexp "^SQL>"
:prompt-length 4)
:sqli-program sql-ms-program
:sqli-options sql-ms-options
:sqli-login sql-ms-login-params
- :sqli-connect-func sql-connect-ms
+ :sqli-comint-func sql-comint-ms
:prompt-regexp "^[0-9]*>"
:prompt-length 5
:syntax-alist ((?@ . "w"))
:sqli-program sql-mysql-program
:sqli-options sql-mysql-options
:sqli-login sql-mysql-login-params
- :sqli-connect-func sql-connect-mysql
+ :sqli-comint-func sql-comint-mysql
:prompt-regexp "^mysql> "
:prompt-length 6
:input-filter sql-remove-tabs-filter)
:sqli-program sql-oracle-program
:sqli-options sql-oracle-options
:sqli-login sql-oracle-login-params
- :sqli-connect-func sql-connect-oracle
+ :sqli-comint-func sql-comint-oracle
:prompt-regexp "^SQL> "
:prompt-length 5
:syntax-alist ((?$ . "w") (?# . "w"))
:sqli-program sql-postgres-program
:sqli-options sql-postgres-options
:sqli-login sql-postgres-login-params
- :sqli-connect-func sql-connect-postgres
+ :sqli-comint-func sql-comint-postgres
:prompt-regexp "^.*[#>] *"
:prompt-length 5
:input-filter sql-remove-tabs-filter
:sqli-program sql-solid-program
:sqli-options sql-solid-options
:sqli-login sql-solid-login-params
- :sqli-connect-func sql-connect-solid
+ :sqli-comint-func sql-comint-solid
:prompt-regexp "^"
:prompt-length 0)
:sqli-program sql-sqlite-program
:sqli-options sql-sqlite-options
:sqli-login sql-sqlite-login-params
- :sqli-connect-func sql-connect-sqlite
+ :sqli-comint-func sql-comint-sqlite
:prompt-regexp "^sqlite> "
:prompt-length 8)
:sqli-program sql-sybase-program
:sqli-options sql-sybase-options
:sqli-login sql-sybase-login-params
- :sqli-connect-func sql-connect-sybase
+ :sqli-comint-func sql-comint-sybase
:prompt-regexp "^SQL> "
:prompt-length 5
:syntax-alist ((?@ . "w"))
database and server) needed to connect to
the database.
- :sqli-connect-func name of a function which accepts no
+ :sqli-comint-func name of a function which accepts no
parameters that will use the values of
`sql-user', `sql-password',
`sql-database' and `sql-server' to open a
(defvar sql-indirect-features
'(:font-lock :sqli-program :sqli-options :sqli-login))
+;;;###autoload
+(defcustom sql-connection-alist nil
+ "An alist of connection parameters for interacting with a SQL
+ product.
+
+Each element of the alist is as follows:
+
+ \(CONNECTION \(SQL-VARIABLE VALUE) ...)
+
+Where CONNECTION is a symbol identifying the connection, SQL-VARIABLE
+is the symbol name of a SQL mode variable, and VALUE is the value to
+be assigned to the variable.
+
+The most common SQL-VARIABLE settings associated with a connection
+are:
+
+ `sql-product'
+ `sql-user'
+ `sql-password'
+ `sql-port'
+ `sql-server'
+ `sql-database'
+
+If a SQL-VARIABLE is part of the connection, it will not be
+prompted for during login."
+
+ :type `(alist :key-type (symbol :tag "Connection")
+ :value-type
+ (set
+ (group (const :tag "Product" sql-product)
+ (choice
+ ,@(mapcar (lambda (prod-info)
+ `(const :tag
+ ,(or (plist-get (cdr prod-info) :name)
+ (capitalize (symbol-name (car prod-info))))
+ (quote ,(car prod-info))))
+ sql-product-alist)))
+ (group (const :tag "Username" sql-user) string)
+ (group (const :tag "Password" sql-password) string)
+ (group (const :tag "Server" sql-server) string)
+ (group (const :tag "Database" sql-database) string)
+ (group (const :tag "Port" sql-port) integer)))
+ :version "24.1"
+ :group 'SQL)
+
;;;###autoload
(defcustom sql-product 'ansi
"Select the SQL database product used so that buffers can be
(capitalize (symbol-name (car prod-info))))
,(car prod-info)))
sql-product-alist))
- :group 'SQL)
-(put 'sql-product 'safe-local-variable 'symbolp)
-
-(defvar sql-interactive-product nil
- "Product under `sql-interactive-mode'.")
+ :group 'SQL
+ :safe 'symbolp)
;; misc customization of sql.el behaviour
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
(const user)
(const password)
(const server)
- (const database)))
+ (const database)
+ (const port)))
:version "24.1"
:group 'SQL)
["Send String" sql-send-string (and (buffer-live-p sql-buffer)
(get-buffer-process sql-buffer))]
["--" nil nil]
- ["Start SQLi session" sql-product-interactive (sql-get-product-feature sql-product :sqli-connect-func)]
+ ["Start SQLi session" sql-product-interactive (sql-get-product-feature sql-product :sqli-comint-func)]
["Show SQLi buffer" sql-show-sqli-buffer t]
["Set SQLi buffer" sql-set-sqli-buffer t]
["Pop to SQLi buffer after send"
(setcdr p (plist-put (cdr p) feature newvalue)))
(message "`%s' is not a known product; use `sql-add-product' to add it first." product))))
-(defun sql-get-product-feature (product feature &optional fallback)
+(defun sql-get-product-feature (product feature &optional fallback not-indirect)
"Lookup FEATURE associated with a SQL PRODUCT.
If the FEATURE is nil for PRODUCT, and FALLBACK is specified,
then the FEATURE associated with the FALLBACK product is
returned.
+If the FEATURE is in the list `sql-indirect-features', and the
+NOT-INDIRECT parameter is not set, then the value of the symbol
+stored in the connect alist is returned.
+
See `sql-product-alist' for a list of products and supported features."
(let* ((p (assoc product sql-product-alist))
(v (plist-get (cdr p) feature)))
(if (and
(member feature sql-indirect-features)
+ (not not-indirect)
(symbolp v))
(symbol-value v)
v))
(setq sql-database
(read-from-minibuffer "Database: " sql-database nil nil
'sql-database-history))))
+
(setq what (cdr what))))
(defun sql-find-sqli-buffer ()
(message "Buffer %s has no process." (buffer-name sql-buffer))
(message "Current SQLi buffer is %s." (buffer-name sql-buffer)))))
+(defun sql--alt-buffer-part (delim part)
+ (unless (string= "" part)
+ (list delim part)))
+
+(defun sql--alt-if-not-empty (s)
+ (if (string= "" s) nil s))
+
(defun sql-make-alternate-buffer-name ()
"Return a string that can be used to rename a SQLi buffer.
This is used to set `sql-alternate-buffer-name' within
-`sql-interactive-mode'."
- (concat (if (string= "" sql-user)
- (if (string= "" (user-login-name))
- ()
- (concat (user-login-name) "/"))
- (concat sql-user "/"))
- (if (string= "" sql-database)
- (if (string= "" sql-server)
- (system-name)
- sql-server)
- sql-database)))
+`sql-interactive-mode'.
+
+If the session was started with `sql-connect' then the alternate
+name would be the name of the connection.
+
+Otherwise, it uses the parameters identified by the :sqlilogin
+parameter.
+
+If all else fails, the alternate name would be the user and
+server/database name."
+
+ (or
+ ;; If started by sql-connect, use that
+ (sql--alt-if-not-empty
+ (when sql-connection (symbol-name sql-connection)))
+
+ ;; based on :sqli-login setting
+ (sql--alt-if-not-empty
+ (apply 'concat
+ (cdr
+ (apply 'append nil
+ (mapcar
+ (lambda (v)
+ (cond
+ ((eq v 'user) (sql--alt-buffer-part "/" sql-user))
+ ((eq v 'server) (sql--alt-buffer-part "@" sql-server))
+ ((eq v 'database) (sql--alt-buffer-part "@" sql-database))
+ ((eq v 'port) (sql--alt-buffer-part ":" sql-port))
+
+ ((eq v 'password) nil)
+ (t nil)))
+ (sql-get-product-feature sql-product :sqli-login))))))
+
+ ;; Default: username/server format
+ (sql--alt-if-not-empty
+ (concat (if (string= "" sql-user)
+ (if (string= "" (user-login-name))
+ ()
+ (concat (user-login-name) "/"))
+ (concat sql-user "/"))
+ (if (string= "" sql-database)
+ (if (string= "" sql-server)
+ (system-name)
+ sql-server)
+ sql-database)))))
(defun sql-rename-buffer ()
"Rename a SQLi buffer."
(setq abbrev-all-caps 1)
;; Exiting the process will call sql-stop.
(set-process-sentinel (get-buffer-process sql-buffer) 'sql-stop)
+ ;; Save the connection name
+ (make-local-variable 'sql-connection)
;; Create a usefull name for renaming this buffer later.
(make-local-variable 'sql-alternate-buffer-name)
(setq sql-alternate-buffer-name (sql-make-alternate-buffer-name))
((symbolp product) product) ; Product specified
(t sql-product))) ; Default to sql-product
- (when (sql-get-product-feature product :sqli-connect-func)
+ (when (sql-get-product-feature product :sqli-comint-func)
(if (and sql-buffer
(buffer-live-p sql-buffer)
(comint-check-proc sql-buffer))
;; Connect to database.
(message "Login...")
- (funcall (sql-get-product-feature product :sqli-connect-func)
+ (funcall (sql-get-product-feature product :sqli-comint-func)
product
(sql-get-product-feature product :sqli-options))
(message "Login...done")
(pop-to-buffer sql-buffer)))))
-(defun sql-connect (product params)
- "Set up a comint buffer to connect to the SQL processor.
+(defun sql-comint (product params)
+ "Set up a comint buffer to run the SQL processor.
PRODUCT is the SQL product. PARAMS is a list of strings which are
passed as command line arguments."
(let ((program (sql-get-product-feature product :sqli-program)))
(set-buffer
- (if params
- (apply 'make-comint "SQL" program nil params)
- (make-comint "SQL" program nil)))))
+ (apply 'make-comint "SQL" program nil params))))
+
+;;;###autoload
+(defun sql-connect (connection)
+ "Connect to an interactive session using CONNECTION settings.
+
+See `sql-connection-alist' to see how to define connections and
+their settings.
+
+The user will not be prompted for any login parameters if a value
+is specified in the connection settings."
+
+ ;; Prompt for the connection from those defined in the alist
+ (interactive
+ (if sql-connection-alist
+ (list
+ (intern
+ (completing-read "Connection: "
+ (mapcar (lambda (c) (symbol-name (car c)))
+ sql-connection-alist)
+ nil t)))
+ nil))
+
+ ;; Are there connections defined
+ (if sql-connection-alist
+ ;; Was one selected
+ (when connection
+ ;; Get connection settings
+ (let ((connect-set (aget sql-connection-alist connection)))
+ ;; Settings are defined
+ (if connect-set
+ ;; Set the desired parameters
+ (eval `(let*
+ (,@connect-set
+ ;; :sqli-login params variable
+ (param-var (sql-get-product-feature sql-product
+ :sqli-login nil t))
+ ;; :sqli-login params value
+ (login-params (sql-get-product-feature sql-product
+ :sqli-login))
+ ;; which params are in the connection
+ (set-params (mapcar
+ (lambda (v)
+ (cond
+ ((eq (car v) 'sql-user) 'user)
+ ((eq (car v) 'sql-password) 'password)
+ ((eq (car v) 'sql-server) 'server)
+ ((eq (car v) 'sql-database) 'database)
+ ((eq (car v) 'sql-port) 'port)
+ (t (car v))))
+ connect-set))
+ ;; the remaining params (w/o the connection params)
+ (rem-params (apply 'append nil
+ (mapcar
+ (lambda (l)
+ (unless (member l set-params)
+ (list l)))
+ login-params)))
+ ;; Remember the connection
+ (sql-connection connection))
+
+ ;; Set the remaining parameters and start the
+ ;; interactive session
+ (eval `(let ((,param-var ',rem-params))
+ (sql-product-interactive sql-product)))))
+ (message "SQL Connection \"%s\" does not exist" connection)
+ nil)))
+ (message "No SQL Connections defined")
+ nil))
;;;###autoload
(defun sql-oracle ()
(interactive)
(sql-product-interactive 'oracle))
-(defun sql-connect-oracle (product options)
+(defun sql-comint-oracle (product options)
"Create comint buffer and connect to Oracle."
;; Produce user/password@database construct. Password without user
;; is meaningless; database without user/password is meaningless,
(if parameter
(setq parameter (nconc (list parameter) options))
(setq parameter options))
- (sql-connect product parameter)))
+ (sql-comint product parameter)))
\f
(interactive)
(sql-product-interactive 'sybase))
-(defun sql-connect-sybase (product options)
+(defun sql-comint-sybase (product options)
"Create comint buffer and connect to Sybase."
;; Put all parameters to the program (if defined) in a list and call
;; make-comint.
(setq params (append (list "-P" sql-password) params)))
(if (not (string= "" sql-user))
(setq params (append (list "-U" sql-user) params)))
- (sql-connect product params)))
+ (sql-comint product params)))
\f
(interactive)
(sql-product-interactive 'informix))
-(defun sql-connect-informix (product options)
+(defun sql-comint-informix (product options)
"Create comint buffer and connect to Informix."
;; username and password are ignored.
(let ((db (if (string= "" sql-database)
(if (string= "" sql-server)
sql-database
(concat sql-database "@" sql-server)))))
- (sql-connect product (append `(,db "-") options))))
+ (sql-comint product (append `(,db "-") options))))
\f
(interactive)
(sql-product-interactive 'sqlite))
-(defun sql-connect-sqlite (product options)
+(defun sql-comint-sqlite (product options)
"Create comint buffer and connect to SQLite."
;; Put all parameters to the program (if defined) in a list and call
;; make-comint.
(if (not (string= "" sql-database))
(setq params (append (list sql-database) params)))
(setq params (append options params))
- (sql-connect product params)))
+ (sql-comint product params)))
\f
(interactive)
(sql-product-interactive 'mysql))
-(defun sql-connect-mysql (product options)
+(defun sql-comint-mysql (product options)
"Create comint buffer and connect to MySQL."
;; Put all parameters to the program (if defined) in a list and call
;; make-comint.
(if (not (string= "" sql-user))
(setq params (append (list (concat "--user=" sql-user)) params)))
(setq params (append options params))
- (sql-connect product params)))
+ (sql-comint product params)))
\f
(interactive)
(sql-product-interactive 'solid))
-(defun sql-connect-solid (product options)
+(defun sql-comint-solid (product options)
"Create comint buffer and connect to Solid."
;; Put all parameters to the program (if defined) in a list and call
;; make-comint.
(setq params (append (list sql-user sql-password) params)))
(if (not (string= "" sql-server))
(setq params (append (list sql-server) params)))
- (sql-connect product params)))
+ (sql-comint product params)))
\f
(interactive)
(sql-product-interactive 'ingres))
-(defun sql-connect-ingres (product options)
+(defun sql-comint-ingres (product options)
"Create comint buffer and connect to Ingres."
;; username and password are ignored.
- (sql-connect product
+ (sql-comint product
(append (if (string= "" sql-database)
nil
(list sql-database))
(interactive)
(sql-product-interactive 'ms))
-(defun sql-connect-ms (product options)
+(defun sql-comint-ms (product options)
"Create comint buffer and connect to Microsoft SQL Server."
;; Put all parameters to the program (if defined) in a list and call
;; make-comint.
;; If -P is passed to ISQL as the last argument without a
;; password, it's considered null.
(setq params (append params (list "-P")))))
- (sql-connect product params)))
+ (sql-comint product params)))
\f
(interactive)
(sql-product-interactive 'postgres))
-(defun sql-connect-postgres (product options)
+(defun sql-comint-postgres (product options)
"Create comint buffer and connect to Postgres."
;; username and password are ignored. Mark Stosberg suggest to add
;; the database at the end. Jason Beegan suggest using --pset and
(setq params (append (list "-h" sql-server) params)))
(if (not (string= "" sql-user))
(setq params (append (list "-U" sql-user) params)))
- (sql-connect product params)))
+ (sql-comint product params)))
\f
(interactive)
(sql-product-interactive 'interbase))
-(defun sql-connect-interbase (product options)
+(defun sql-comint-interbase (product options)
"Create comint buffer and connect to Interbase."
;; Put all parameters to the program (if defined) in a list and call
;; make-comint.
(setq params (append (list "-p" sql-password) params)))
(if (not (string= "" sql-database))
(setq params (cons sql-database params))) ; add to the front!
- (sql-connect product params)))
+ (sql-comint product params)))
\f
(interactive)
(sql-product-interactive 'db2))
-(defun sql-connect-db2 (product options)
+(defun sql-comint-db2 (product options)
"Create comint buffer and connect to DB2."
;; Put all parameters to the program (if defined) in a list and call
;; make-comint.
- (sql-connect product options)
+ (sql-comint product options)
)
;; ;; Properly escape newlines when DB2 is interactive.
;; (setq comint-input-sender 'sql-escape-newlines-and-send))
(interactive)
(sql-product-interactive 'linter))
-(defun sql-connect-linter (product options)
+(defun sql-comint-linter (product options)
"Create comint buffer and connect to Linter."
;; Put all parameters to the program (if defined) in a list and call
;; make-comint.
(if (string= "" sql-database)
(setenv "LINTER_MBX" nil)
(setenv "LINTER_MBX" sql-database))
- (sql-connect product params)
+ (sql-comint product params)
(setenv "LINTER_MBX" old-mbx)))
\f