]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/sql.el
Merge from emacs--rel--22
[gnu-emacs] / lisp / progmodes / sql.el
index 420b5f226b0c0debd75b019ef65bdbe17334216d..a3401dccbcb1e5662f097d9eaf773915c48b015a 100644 (file)
@@ -1,10 +1,11 @@
 ;;; sql.el --- specialized comint.el for SQL interpreters
 
-;; Copyright (C) 1998,99,2000,01,02,03,04  Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+;; Free Software Foundation, Inc.
 
 ;; Author: Alex Schroeder <alex@gnu.org>
 ;; Maintainer: Michael Mauger <mmaug@yahoo.com>
-;; Version: 2.0.0
+;; Version: 2.0.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
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
 ;; Please send bug reports and bug fixes to the mailing list at
-;; sql.el@gnu.org.  If you want to subscribe to the mailing list, send
-;; mail to sql.el-request@gnu.org with `subscribe sql.el FIRSTNAME
-;; LASTNAME' in the mail body.
-
-;; This file provides a sql-mode and a sql-interactive-mode.  My goals
-;; were two simple modes providing syntactic hilighting.  The
-;; interactive mode had to provide a command-line history; the other
-;; mode had to provide "send region/buffer to SQL interpreter"
-;; functions.  "simple" in this context means easy to use, easy to
-;; maintain and little or no bells and whistles.
+;; help-gnu-emacs@gnu.org.  If you want to subscribe to the mailing
+;; list, see the web page at
+;; http://lists.gnu.org/mailman/listinfo/help-gnu-emacs for
+;; instructions.  I monitor this list actively.  If you send an e-mail
+;; to Alex Schroeder it usually makes it to me when Alex has a chance
+;; to forward them along (Thanks, Alex).
+
+;; This file provides a sql-mode and a sql-interactive-mode.  The
+;; original goals were two simple modes providing syntactic
+;; highlighting.  The interactive mode had to provide a command-line
+;; history; the other mode had to provide "send region/buffer to SQL
+;; interpreter" functions.  "simple" in this context means easy to
+;; use, easy to maintain and little or no bells and whistles.  This
+;; has changed somewhat as experience with the mode has accumulated.
+
+;; Support for different flavors of SQL and command interpreters was
+;; available in early versions of sql.el.  This support has been
+;; extended and formalized in later versions.  Part of the impetus for
+;; the improved support of SQL flavors was borne out of the current
+;; maintainer's consulting experience.  In the past fifteen years, I
+;; have used Oracle, Sybase, Informix, MySQL, Postgres, and SQLServer.
+;; On some assignments, I have used two or more of these concurrently.
 
 ;; If anybody feels like extending this sql mode, take a look at the
 ;; above mentioned modes and write a sqlx-mode on top of this one.  If
 ;; this proves to be difficult, please suggest changes that will
-;; facilitate your plans.
+;; facilitate your plans.  Facilities have been provided to add
+;; products and product-specific configuration.
 
 ;; sql-interactive-mode is used to interact with a SQL interpreter
 ;; process in a SQLi buffer (usually called `*SQL*').  The SQLi buffer
-;; is created by calling a SQL interpreter-specific entry function.  Do
-;; *not* call sql-interactive-mode by itself.
+;; is created by calling a SQL interpreter-specific entry function or
+;; sql-product-interactive.  Do *not* call sql-interactive-mode by
+;; itself.
 
 ;; The list of currently supported interpreters and the corresponding
 ;; entry function used to create the SQLi buffers is shown with
 ;; Gregor Zych <zych@pool.informatik.rwth-aachen.de>
 ;; nino <nino@inform.dk>
 ;; Berend de Boer <berend@pobox.com>
-;; Michael Mauger <mmaug@yahoo.com>
 ;; Adam Jenkins <adam@thejenkins.org>
+;; Michael Mauger <mmaug@yahoo.com> -- improved product support
+;; Drew Adams <drew.adams@oracle.com> -- Emacs 20 support
+;; Harald Maier <maierh@myself.com> -- sql-send-string
+;; Stefan Monnier <monnier@iro.umontreal.ca> -- font-lock corrections
 
 \f
 
 (eval-when-compile ;; needed in Emacs 19, 20
   (setq max-specpdl-size 2000))
 
+(defvar font-lock-keyword-face)
+(defvar font-lock-set-defaults)
+(defvar font-lock-string-face)
+
 ;;; Allow customization
 
 (defgroup SQL nil
-  "Running a SQL interpreter from within Emacs buffers"
+  "Running a SQL interpreter from within Emacs buffers."
   :version "20.4"
   :group 'processes)
 
@@ -614,7 +636,7 @@ The program can also specify a TCP connection.  See `make-comint'."
   ;; -w is the linesize
   "*List of additional options for `sql-ms-program'."
   :type '(repeat string)
-  :version "21.4"
+  :version "22.1"
   :group 'SQL)
 
 ;; Customization for Postgres
@@ -693,18 +715,6 @@ Starts `sql-interactive-mode' after doing some setup."
 
 ;;; Variables which do not need customization
 
-(defvar sql-xemacs-p
-  (string-match "XEmacs\\|Lucid" emacs-version)
-  "Is this a non-GNU Emacs?")
-
-(defvar sql-emacs19-p
-  (string-match "GNU Emacs 19" emacs-version)
-  "Is this a GNU Emacs 19?")
-
-(defvar sql-emacs20-p
-  (string-match "20" emacs-version)
-  "Is this a GNU Emacs 20?")
-
 (defvar sql-user-history nil
   "History of usernames used.")
 
@@ -744,10 +754,11 @@ Used by `sql-rename-buffer'.")
 
 (defvar sql-interactive-mode-map
   (let ((map (make-sparse-keymap)))
-    (if (functionp 'set-keymap-parent)
+    (if (fboundp 'set-keymap-parent)
        (set-keymap-parent map comint-mode-map); Emacs
-      (set-keymap-parents map (list comint-mode-map))); XEmacs
-    (if (functionp 'set-keymap-name)
+      (if (fboundp 'set-keymap-parents)
+         (set-keymap-parents map (list comint-mode-map)))); XEmacs
+    (if (fboundp 'set-keymap-name)
        (set-keymap-name map 'sql-interactive-mode-map)); XEmacs
     (define-key map (kbd "C-j") 'sql-accumulate-and-indent)
     (define-key map (kbd "C-c C-w") 'sql-copy-column)
@@ -850,23 +861,24 @@ Based on `comint-mode-map'.")
 (defvar sql-mode-abbrev-table nil
   "Abbrev table used in `sql-mode' and `sql-interactive-mode'.")
 (unless sql-mode-abbrev-table
-  (define-abbrev-table 'sql-mode-abbrev-table nil)
-  (mapcar
-    ;; In Emacs 21.3+, provide SYSTEM-FLAG to define-abbrev.
-   '(lambda (abbrev)
-      (let ((name (car abbrev))
-           (expansion (cdr abbrev)))
-       (condition-case nil
-           (define-abbrev sql-mode-abbrev-table name expansion nil 0 t)
-         (error
-          (define-abbrev sql-mode-abbrev-table name expansion)))))
-   '(("ins" "insert")
-    ("upd" "update")
-    ("del" "delete")
-    ("sel" "select")
-    ("proc" "procedure")
-    ("func" "function")
-    ("cr" "create"))))
+  (define-abbrev-table 'sql-mode-abbrev-table nil))
+
+(mapcar
+ ;; In Emacs 22+, provide SYSTEM-FLAG to define-abbrev.
+ '(lambda (abbrev)
+    (let ((name (car abbrev))
+          (expansion (cdr abbrev)))
+      (condition-case nil
+          (define-abbrev sql-mode-abbrev-table name expansion nil 0 t)
+        (error
+         (define-abbrev sql-mode-abbrev-table name expansion)))))
+ '(("ins"  . "insert")
+   ("upd"  . "update")
+   ("del"  . "delete")
+   ("sel"  . "select")
+   ("proc" . "procedure")
+   ("func" . "function")
+   ("cr"   . "create")))
 
 ;; Syntax Table
 
@@ -875,15 +887,15 @@ Based on `comint-mode-map'.")
     ;; C-style comments /**/ (see elisp manual "Syntax Flags"))
     (modify-syntax-entry ?/ ". 14" table)
     (modify-syntax-entry ?* ". 23" table)
-    ;; double-dash starts comment
-    (if sql-xemacs-p
-       (modify-syntax-entry ?- ". 56" table)
-      (modify-syntax-entry ?- ". 12b" table))
-    ;; newline and formfeed end coments
+    ;; double-dash starts comments
+    (modify-syntax-entry ?- ". 12b" table)
+    ;; newline and formfeed end comments
     (modify-syntax-entry ?\n "> b" table)
     (modify-syntax-entry ?\f "> b" table)
-    ;; single quotes (') quotes delimit strings
+    ;; single quotes (') delimit strings
     (modify-syntax-entry ?' "\"" table)
+    ;; double quotes (") don't delimit strings
+    (modify-syntax-entry ?\" "." table)
     ;; backslash is no escape character
     (modify-syntax-entry ?\\ "." table)
     table)
@@ -892,12 +904,13 @@ Based on `comint-mode-map'.")
 ;; Font lock support
 
 (defvar sql-mode-font-lock-object-name
-  (list (concat "^\\s-*\\(create\\|drop\\|alter\\)\\s-+" ;; lead off with CREATE, DROP or ALTER
-               "\\(\\w+\\s-+\\)*"  ;; optional intervening keywords
-               "\\(table\\|view\\|package\\(\\s-+body\\)?\\|proc\\(edure\\)?"
-               "\\|function\\|trigger\\|sequence\\|rule\\|default\\)\\s-+"
-               "\\(\\w+\\)")
-       6 'font-lock-function-name-face)
+  (eval-when-compile
+    (list (concat "^\\s-*\\(?:create\\|drop\\|alter\\)\\s-+" ;; lead off with CREATE, DROP or ALTER
+                 "\\(?:\\w+\\s-+\\)*"  ;; optional intervening keywords
+                 "\\(?:table\\|view\\|\\(?:package\\|type\\)\\(?:\\s-+body\\)?\\|proc\\(?:edure\\)?"
+                 "\\|function\\|trigger\\|sequence\\|rule\\|default\\)\\s-+"
+                 "\\(\\w+\\)")
+         1 'font-lock-function-name-face))
 
   "Pattern to match the names of top-level objects.
 
@@ -905,25 +918,6 @@ The pattern matches the name in a CREATE, DROP or ALTER
 statement.  The format of variable should be a valid
 `font-lock-keywords' entry.")
 
-(defvar sql-builtin-face
-  (if sql-xemacs-p
-      ;; XEmacs doesn't have the builtin face
-      'font-lock-preprocessor-face
-    ;; GNU Emacs 19 doesn't either
-    (if sql-emacs19-p
-       'font-lock-keyword-face
-      ;; Emacs 2x
-      'font-lock-builtin-face))
-  "Builtin face for font-lock in SQL mode.")
-
-(defvar sql-doc-face
-  (if (or sql-xemacs-p
-         sql-emacs19-p
-         sql-emacs20-p)
-      'font-lock-string-face
-    'font-lock-doc-face)
-  "Documentation face for font-lock in SQL mode.")
-
 (defmacro sql-keywords-re (&rest keywords)
   "Compile-time generation of regexp matching any one of KEYWORDS."
   `(eval-when-compile
@@ -1020,7 +1014,7 @@ statement.  The format of variable should be a valid
 
     `((,ansi-non-reserved . font-lock-keyword-face)
       (,ansi-reserved     . font-lock-keyword-face)
-      (,ansi-funcs        . ,sql-builtin-face)
+      (,ansi-funcs        . font-lock-builtin-face)
       (,ansi-types        . font-lock-type-face)))
 
   "ANSI SQL keywords used by font-lock.
@@ -1230,11 +1224,11 @@ add functions and PL/SQL keywords.")
    "\\b.*$"
    ))))
 
-    `((,sqlplus-commands . ,sql-doc-face)
-      (,oracle-functions . ,sql-builtin-face)
+    `((,sqlplus-commands . font-lock-doc-face)
+      (,oracle-functions . font-lock-builtin-face)
       (,oracle-keywords  . font-lock-keyword-face)
       (,oracle-types     . font-lock-type-face)
-      (,plsql-functions  . ,sql-builtin-face)
+      (,plsql-functions  . font-lock-builtin-face)
       (,plsql-keywords   . font-lock-keyword-face)
       (,plsql-type       . font-lock-type-face)
       (,plsql-warning    . font-lock-warning-face)))
@@ -1323,7 +1317,7 @@ to add functions and PL/SQL keywords.")
 "timestamp" "varchar" "varying" "void" "zone"
 )))
 
-  `((,pg-funcs    . ,sql-builtin-face)
+  `((,pg-funcs    . font-lock-builtin-face)
     (,pg-reserved . font-lock-keyword-face)
     (,pg-types    . font-lock-type-face)))
 
@@ -1404,7 +1398,7 @@ you define your own sql-mode-postgres-font-lock-keywords.")
 
     `((,linter-keywords  . font-lock-keyword-face)
       (,linter-reserved  . font-lock-keyword-face)
-      (,linter-functions . ,sql-builtin-face)
+      (,linter-functions . font-lock-builtin-face)
       (,linter-types     . font-lock-type-face)))
 
   "Linter SQL keywords used by font-lock.
@@ -1507,9 +1501,9 @@ function `regexp-opt'.")
 ) t)
                   "\\)\\)\\|go\\s-*\\|use\\s-+\\|setuser\\s-+\\|dbcc\\s-+\\).*$"))))
 
-    `((,ms-commands  . ,sql-doc-face)
+    `((,ms-commands  . font-lock-doc-face)
       (,ms-reserved  . font-lock-keyword-face)
-      (,ms-functions . ,sql-builtin-face)
+      (,ms-functions . font-lock-builtin-face)
       (,ms-vars      . font-lock-variable-name-face)
       (,ms-types     . font-lock-type-face)))
 
@@ -1626,7 +1620,7 @@ you define your own sql-mode-solid-font-lock-keywords.")
 "zerofill"
 )))
 
-    `((,mysql-funcs    . ,sql-builtin-face)
+    `((,mysql-funcs    . font-lock-builtin-face)
       (,mysql-keywords . font-lock-keyword-face)
       (,mysql-types    . font-lock-type-face)))
 
@@ -1687,17 +1681,36 @@ the product-specific keywords and syntax-alists defined in
     ;; Get the product-specific keywords.
     (setq sql-mode-font-lock-keywords
          (append
-          (eval (sql-product-feature :font-lock))
+          (unless (eq sql-product 'ansi)
+            (eval (sql-product-feature :font-lock)))
+          ;; Always highlight ANSI keywords
           (eval (sql-product-feature :font-lock 'ansi))
+          ;; Fontify object names in CREATE, DROP and ALTER DDL
+          ;; statements
           (list sql-mode-font-lock-object-name)))
 
-    ;; Setup font-lock.  (What is the minimum we should have to do
-    ;; here?)
-    (setq font-lock-set-defaults nil
-         font-lock-keywords sql-mode-font-lock-keywords
-         font-lock-defaults (list 'sql-mode-font-lock-keywords
+    ;; Setup font-lock.  Force re-parsing of `font-lock-defaults'.
+    (set (make-local-variable 'font-lock-set-defaults) nil)
+    (setq font-lock-defaults (list 'sql-mode-font-lock-keywords
                                   keywords-only t syntax-alist))
 
+    ;; Force font lock to reinitialize if it is already on
+    ;; Otherwise, we can wait until it can be started.
+    (when (and (fboundp 'font-lock-mode)
+              font-lock-mode)
+      (font-lock-mode-internal nil)
+      (font-lock-mode-internal t))
+
+    (add-hook 'font-lock-mode-hook
+             (lambda ()
+               ;; Provide defaults for new font-lock faces.
+               (defvar font-lock-builtin-face
+                 (if (boundp 'font-lock-preprocessor-face)
+                     font-lock-preprocessor-face
+                   font-lock-keyword-face))
+               (defvar font-lock-doc-face font-lock-string-face))
+             nil t)
+
     ;; Setup imenu; it needs the same syntax-alist.
     (when imenu
        (setq imenu-syntax-alist syntax-alist))))
@@ -1744,11 +1757,6 @@ selected."
     ;; Setup font-lock
     (sql-product-font-lock nil t)
 
-    ;; Force fontification, if its enabled.
-    (if (and (boundp 'font-lock-mode)
-            font-lock-mode)
-       (font-lock-fontify-buffer))
-
     ;; Set the mode name to include the product.
     (setq mode-name (concat "SQL[" (prin1-to-string sql-product) "]"))))
 
@@ -1916,16 +1924,8 @@ appended to the SQLi buffer without disturbing your SQL buffer."
   (describe-function 'sql-help))
 
 (defun sql-read-passwd (prompt &optional default)
-  "Read a password using PROMPT.
-Optional DEFAULT is password to start with.  This function calls
-`read-passwd' if it is available.  If not, function
-`ange-ftp-read-passwd' is called.  This should always be available,
-even in old versions of Emacs."
-  (if (fboundp 'read-passwd)
-      (read-passwd prompt nil default)
-    (unless (fboundp 'ange-ftp-read-passwd)
-      (autoload 'ange-ftp-read-passwd "ange-ftp"))
-    (ange-ftp-read-passwd prompt default)))
+  "Read a password using PROMPT.  Optional DEFAULT is password to start with."
+  (read-passwd prompt nil default))
 
 (defun sql-get-login (&rest what)
   "Get username, password and database from the user.
@@ -2093,7 +2093,7 @@ Inserts SELECT or commas if appropriate."
          (insert ", "))
         ;; else insert a space
         (t
-         (if (eq (preceding-char) ? )
+         (if (eq (preceding-char) ?\s)
              nil
            (insert " ")))))
       ;; in any case, insert the column
@@ -2265,7 +2265,7 @@ you must tell Emacs.  Here's how to do that in your `~/.emacs' file:
   (setq local-abbrev-table sql-mode-abbrev-table)
   (setq abbrev-all-caps 1)
   ;; Run hook
-  (run-hooks 'sql-mode-hook)
+  (run-mode-hooks 'sql-mode-hook)
   ;; Catch changes to sql-product and highlight accordingly
   (sql-highlight-product)
   (add-hook 'hack-local-variables-hook 'sql-highlight-product t t))
@@ -2321,7 +2321,7 @@ hooks on `comint-input-filter-functions' are run.  After each SQL
 interpreter output, the hooks on `comint-output-filter-functions' are
 run.
 
-Variable `sql-input-ring-file-name' controls the initialisation of the
+Variable `sql-input-ring-file-name' controls the initialization of the
 input ring history.
 
 Variables `comint-output-filter-functions', a hook, and
@@ -2344,7 +2344,7 @@ you entered, right above the output it created.
 
 \(setq comint-output-filter-functions
        \(function (lambda (STR) (comint-show-output))))"
-  (comint-mode)
+  (delay-mode-hooks (comint-mode))
   ;; Get the `sql-product' for this interactive session.
   (set (make-local-variable 'sql-product)
        (or sql-interactive-product
@@ -2383,7 +2383,7 @@ you entered, right above the output it created.
   (make-local-variable 'sql-input-ring-separator)
   (make-local-variable 'sql-input-ring-file-name)
   ;; Run hook.
-  (run-hooks 'sql-interactive-mode-hook)
+  (run-mode-hooks 'sql-interactive-mode-hook)
   ;; Set comint based on user overrides.
   (setq comint-prompt-regexp sql-prompt-regexp)
   (setq left-margin sql-prompt-length)