changeset 24050:e546776e7a76

Initial revision
author Richard M. Stallman <rms@gnu.org>
date Mon, 11 Jan 1999 15:26:36 +0000
parents a45f10911408
children 4307fe505e5f
files lisp/progmodes/sql.el
diffstat 1 files changed, 1060 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/progmodes/sql.el	Mon Jan 11 15:26:36 1999 +0000
@@ -0,0 +1,1060 @@
+;;; sql.el --- specialized comint.el for SQL interpreters
+
+;; Copyright (C) 1998  Free Software Foundation, Inc.
+
+;; Author: Alex Schroeder <a.schroeder@bsiag.ch>
+;; Maintainer: Alex Schroeder <a.schroeder@bsiag.ch>
+;; Version: 1.1.5
+;; Keywords: processes SQL
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; 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.
+
+;;; Commentary:
+
+;; Please send me bug reports and bug fixes so that I can merge them
+;; into the master source.
+
+;; You can get the latest version of this file from my homepage
+;; <URL:http://www.geocities.com/TimesSquare/6120/emacs.html>.
+
+;; 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.  
+
+;; 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.
+
+;; sql-interactive-mode is used to interact with a SQL interpreter
+;; process in the *SQL* buffer.  The *SQL* buffer is created by
+;; calling a SQL interpreter-specific entry function.  Do *not* call
+;; sql-interactive-mode by itself.
+
+;; The list of currently supported interpreters and the corresponding
+;; entry function used to create the *SQL* buffers is shown with
+;; `sql-help' (M-x sql-help).
+
+;; Since sql-interactive-mode is built on top of the general
+;; command-interpreter-in-a-buffer mode (comint mode), it shares a
+;; common base functionality, and a common set of bindings, with all
+;; modes derived from comint mode.  This makes these modes easier to
+;; use.
+
+;; sql-mode can be used to enable syntactic hilighting for SQL
+;; statements in another buffer.  SQL statements can then be sent to
+;; the SQL process in the *SQL* buffer.  sql-mode has already been
+;; used as a template to a simple PL/SQL mode.
+
+;; For documentation on the functionality provided by comint mode, and
+;; the hooks available for customising it, see the file `comint.el'.
+
+;; Hint for newbies: take a look at `dabbrev-expand' and `abbrev-mode'.
+
+;;; Requirements for Emacs 19.34:
+
+;; If you are using Emacs 19.34, you will have to get and install
+;; the file regexp-opt.el
+;; <URL:ftp://ftp.ifi.uio.no/pub/emacs/emacs-20.3/lisp/emacs-lisp/regexp-opt.el>
+;; and the custom package
+;; <URL:http://www.dina.kvl.dk/~abraham/custom/>.
+
+;;; Bugs:
+
+;; Using sql-ms (isql by Microsoft): When commands with syntax errors
+;; or execution errors are executed, there is no server feedback.
+;; This happens in stored procedures for example.  The server messages
+;; only appear after the process is exited.  This makes things
+;; somewhat unreliable.
+
+;;; To Do:
+
+;; Add better hilight support for other brands; there is a bias towards
+;; Oracle because that's what I use at work.  Anybody else just send in
+;; your lists of reserved words, keywords and builtin functions!
+
+;; Add different hilighting levels.
+
+;;; Thanks to all the people who helped me out:
+
+;; Kai Blauberg <kai.blauberg@metla.fi>
+;; <ibalaban@dalet.com>
+;; Yair Friedman <yfriedma@JohnBryce.Co.Il>
+;; Gregor Zych <zych@pool.informatik.rwth-aachen.de>
+
+
+;;; Code:
+
+(require 'comint)
+;; Need the following to allow GNU Emacs 19 to compile the file.
+(require 'regexp-opt)
+(require 'custom)
+
+;;; Allow customization
+
+(defgroup SQL nil
+  "Running a SQL interpreter from within Emacs buffers"
+  :group 'processes)
+
+;; These three variables will be used as defaults, if set.
+
+(defcustom sql-user ""
+  "*Default username."
+  :type 'string
+  :group 'SQL)
+
+(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)
+
+(defcustom sql-database ""
+  "*Default database."
+  :type 'string
+  :group 'SQL)
+
+(defcustom sql-server ""
+  "*Default server.
+
+Currently, this is only used by MS isql."
+  :type 'string
+  :group 'SQL)
+
+(defcustom sql-pop-to-buffer-after-send-region nil
+  "*If t, pop to the buffer SQL statements are sent to.
+
+After a call to `sql-send-region' or `sql-send-buffer',
+the window is split and the SQLi buffer is shown.  If this
+variable is not nil, that buffer's window will be selected."
+  :type 'string
+  :group 'SQL)
+
+;; The usual hooks
+
+(defcustom sql-interactive-mode-hook '()
+  "*Hook for customising `sql-interactive-mode'."
+  :type 'hook
+  :group 'SQL)
+
+(defcustom sql-mode-hook '()
+  "*Hook for customising `sql-mode'."
+  :type 'hook
+  :group 'SQL)
+
+;; Customisation for Oracle
+
+(defcustom sql-oracle-program "sqlplus"
+  "*Command to start sqlplus by Oracle.
+
+Starts `sql-interactive-mode' after doing some setup.
+
+Under NT, \"sqlplus\" usually starts the sqlplus \"GUI\".  In order to
+start the sqlplus console, use \"plus33\" or something similar.  You
+will find the file in your Orant\\bin directory.
+
+The program can also specify a TCP connection.  See `make-comint'."
+  :type 'file
+  :group 'SQL)
+
+;; Customisation for SyBase
+
+(defcustom sql-sybase-program "isql"
+  "*Command to start isql by SyBase.  
+
+Starts `sql-interactive-mode' after doing some setup.
+
+The program can also specify a TCP connection.  See `make-comint'."
+  :type 'file
+  :group 'SQL)
+
+;; Customisation for Informix
+
+(defcustom sql-informix-program "dbaccess"
+  "*Command to start dbaccess by Informix.  
+
+Starts `sql-interactive-mode' after doing some setup.
+
+The program can also specify a TCP connection.  See `make-comint'."
+  :type 'file
+  :group 'SQL)
+
+;; Customisation for Ingres
+
+(defcustom sql-ingres-program "sql"
+  "*Command to start sql by Ingres.  
+
+Starts `sql-interactive-mode' after doing some setup.
+
+The program can also specify a TCP connection.  See `make-comint'."
+  :type 'file
+  :group 'SQL)
+
+;; Customisation for Microsoft
+
+(defcustom sql-ms-program "isql"
+  "*Command to start isql by Microsoft.  
+
+Starts `sql-interactive-mode' after doing some setup.
+
+The program can also specify a TCP connection.  See `make-comint'."
+  :type 'file
+  :group 'SQL)
+
+;; Customisation for Postgres
+
+(defcustom sql-postgres-program "psql"
+  "Command to start psql by Postgres.  
+
+Starts `sql-interactive-mode' after doing some setup.
+
+The program can also specify a TCP connection.  See `make-comint'."
+  :type 'file
+  :group 'SQL)
+
+
+
+;;; Variables which do not need customization
+
+(defvar sql-user-history nil
+  "History of usernames used.")
+
+(defvar sql-database-history nil
+  "History of databases used.")
+
+(defvar sql-server-history nil
+  "History of servers used.")
+
+;; Passwords are not kept in a history.
+
+(defvar sql-buffer nil
+  "Current *SQL* buffer.")
+
+(defvar sql-prompt-regexp nil
+  "Prompt used to initialize `comint-prompt-regexp'.
+
+You can change `comint-prompt-regexp' on `sql-interactive-mode-hook'.")
+
+;; Keymap for sql-interactive-mode, based on comint-mode-map.
+
+(if (not (string-match "XEmacs\\|Lucid" emacs-version))
+    (defvar sql-interactive-mode-map 
+      (let ((map (nconc (make-sparse-keymap) comint-mode-map)))
+	(define-key map "\C-j" 'sql-accumulate-and-indent)
+	(define-key map "\C-c\C-w" 'sql-copy-column)
+	map)
+      "Mode map used for `sql-interactive-mode'.")
+  ;; XEmacs
+  (defvar sql-interactive-mode-map nil)
+  (if (not sql-interactive-mode-map)
+      (let ((map (make-keymap)))
+	(set-keymap-parents map (list comint-mode-map))
+	(set-keymap-name map 'sql-interactive-mode-map)
+	(define-key map "\C-j" 'sql-accumulate-and-indent)
+	(define-key map "\C-c\C-w" 'sql-copy-column)
+	(setq sql-interactive-mode-map map))))
+
+;; Keymap for sql-mode.
+
+(defvar sql-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-c\C-r" 'sql-send-region)
+    (define-key map "\C-c\C-b" 'sql-send-buffer)
+    (define-key map "\t" 'indent-relative)
+    map)
+  "Mode map used for `sql-mode'.")
+
+;; easy menu for sql-mode.
+
+(easy-menu-define 
+ sql-mode-menu sql-mode-map 
+ "Menu for `sql-mode'."
+ '("SQL"
+   ["Send Region" sql-send-region mark-active]
+   ["Send Buffer" sql-send-buffer t]
+   ["Pop to SQLi buffer after send" 
+    sql-toggle-pop-to-buffer-after-send-region
+    :style toggle
+    :selected sql-pop-to-buffer-after-send-region]))
+
+;; Abbreviations -- if you want more of them, define them in your
+;; ~/.emacs file.  Abbrevs have to be enabled in your ~/.emacs, too.
+
+(defvar sql-mode-abbrev-table nil
+  "Abbrev table used in `sql-mode' and `sql-interactive-mode'.")
+(if sql-mode-abbrev-table
+    ()
+  (let ((wrapper))
+    (define-abbrev-table 'sql-mode-abbrev-table ())
+    (define-abbrev sql-mode-abbrev-table  "ins" "insert" nil)
+    (define-abbrev sql-mode-abbrev-table  "upd" "update" nil)
+    (define-abbrev sql-mode-abbrev-table  "del" "delete" nil)
+    (define-abbrev sql-mode-abbrev-table  "sel" "select" nil)))
+
+;; Syntax Table
+
+(defvar sql-mode-syntax-table 
+  (let ((table (make-syntax-table)))
+    ;; C-style comments /**/ (see elisp manual "Syntax Flags"))
+    (modify-syntax-entry ?/ ". 14" table)
+    (modify-syntax-entry ?* ". 23" table)
+    ;; double-dash starts comment
+    (modify-syntax-entry ?- ". 12b" table)
+    ;; newline and formfeed end coments
+    (modify-syntax-entry ?\n "> b" table)
+    (modify-syntax-entry ?\f "> b" table)
+    table)
+  "Syntax table used in `sql-mode' and `sql-interactive-mode'.")
+
+;; Font lock support
+
+(defvar sql-mode-ansi-font-lock-keywords nil
+  "ANSI SQL keywords used by font-lock.
+
+This variable is used by `sql-mode' and `sql-interactive-mode'.  The
+regular expressions are created during compilation by calling the
+function `regexp-opt'.  Therefore, take a look at the source before
+you define your own sql-mode-ansi-font-lock-keywords.  You may want to
+add functions and PL/SQL keywords.")
+(if sql-mode-ansi-font-lock-keywords
+    ()
+  (let ((ansi-keywords (eval-when-compile
+			 (concat "\\b"
+				 (regexp-opt '(
+"authorization" "avg" "begin" "close" "cobol" "commit"
+"continue" "count" "declare" "double" "end" "escape"
+"exec" "fetch" "foreign" "fortran" "found" "go" "goto" "indicator" 
+"key" "language" "max" "min" "module" "numeric" "open" "pascal" "pli"
+"precision" "primary" "procedure" "references" "rollback"
+"schema" "section" "some" "sqlcode" "sqlerror" "sum" "work") t) "\\b")))
+	(ansi-reserved-words (eval-when-compile
+			       (concat "\\b"
+				       (regexp-opt '(
+"all" "and" "any" "as" "asc" "between" "by" "check" "create"
+"current" "default" "delete" "desc" "distinct" "exists" "float" "for"
+"from" "grant" "group" "having" "in" "insert" "into" "is"
+"like" "not" "null" "of" "on" "option" "or" "order" "privileges"
+"public" "select" "set" "table" "to" "union" "unique"
+"update" "user" "values" "view" "where" "with") t) "\\b")))
+	(ansi-types (eval-when-compile
+		      (concat "\\b"
+			      (regexp-opt '(
+;; ANSI Keywords that look like types					  
+"character" "cursor" "dec" "int" "real" 
+;; ANSI Reserved Word that look like types
+"char" "integer" "smallint" ) t) "\\b"))))
+    (setq sql-mode-ansi-font-lock-keywords
+	  (list (cons ansi-keywords font-lock-function-name-face)
+		(cons ansi-reserved-words font-lock-keyword-face)
+		(cons ansi-types font-lock-type-face)))))
+
+(defvar sql-mode-oracle-font-lock-keywords nil
+  "Oracle SQL keywords used by font-lock.
+
+This variable is used by `sql-mode' and `sql-interactive-mode'.  The
+regular expressions are created during compilation by calling the
+function `regexp-opt'.  Therefore, take a look at the source before
+you define your own sql-mode-oracle-font-lock-keywords.  You may want
+to add functions and PL/SQL keywords.")
+(if sql-mode-oracle-font-lock-keywords
+    ()
+  (let ((oracle-keywords (eval-when-compile
+			   (concat "\\b"
+				   (regexp-opt '(
+"admin" "after" "allocate" "analyze" "archive" "archivelog" "backup"
+"become" "before" "block" "body" "cache" "cancel" "cascade" "change"
+"checkpoint" "compile" "constraint" "constraints" "contents"
+"controlfile" "cycle" "database" "datafile" "dba" "disable" "dismount"
+"dump" "each" "enable" "events" "except" "exceptions" "execute"
+"explain" "extent" "externally" "flush" "force" "freelist" "freelists"
+"function" "groups" "including" "initrans" "instance" "layer" "link"
+"lists" "logfile" "manage" "manual" "maxdatafiles" "maxinistances"
+"maxlogfiles" "maxloghistory" "maxlogmembers" "maxtrans" "maxvalue"
+"minextents" "minvalue" "mount" "new" "next" "noarchivelog" "nocache"
+"nocycle" "nomaxvalue" "nominvalue" "none" "noorder" "noresetlogs"
+"normal" "nosort" "off" "old" "only" "optimal" "own" "package"
+"parallel" "pctincrease" "pctused" "plan" "private" "profile" "quota"
+"read" "recover" "referencing" "resetlogs" "restricted" "reuse" "role"
+"roles" "savepoint" "scn" "segment" "sequence" "shared" "snapshot"
+"sort" "statement_id" "statistics" "stop" "storage" "switch" "system"
+"tables" "tablespace" "temporary" "thread" "time" "tracing"
+"transaction" "triggers" "truncate" "under" "unlimited" "until" "use"
+"using" "when" "write") t) "\\b")))
+	(oracle-reserved-words (eval-when-compile
+				 (concat "\\b"
+					 (regexp-opt '(
+"access" "add" "alter" "audit" "cluster" "column" "comment" "compress"
+"connect" "drop" "else" "exclusive" "file" "grant"
+"identified" "immediate" "increment" "index" "initial" "intersect"
+"level" "lock" "long" "maxextents" "minus" "mode" "modify" "noaudit"
+"nocompress" "nowait" "number" "offline" "online" "pctfree" "prior"
+"raw" "rename" "resource" "revoke" "row" "rowlabel" "rownum"
+"rows" "session" "share" "size" "start" "successful" "synonym" "sysdate"
+"then" "trigger" "uid" "validate" "whenever") t) "\\b")))
+	(oracle-types (eval-when-compile
+			(concat "\\b"
+				(regexp-opt '(
+;; Oracle Keywords that look like types
+;; Oracle Reserved Words that look like types
+"date" "decimal" "rowid" "varchar" "varchar2") t) "\\b")))
+	(oracle-builtin-functions (eval-when-compile
+			(concat "\\b"
+				(regexp-opt '(
+;; Misc Oracle builtin functions
+"abs" "add_months" "ascii" "avg" "ceil" "chartorowid" "chr" "concat"
+"convert" "cos" "cosh" "count" "currval" "decode" "dump" "exp" "floor"
+"glb" "greatest" "greatest_lb" "hextoraw" "initcap" "instr" "instrb"
+"last_day" "least" "least_ub" "length" "lengthb" "ln" "log" "lower"
+"lpad" "ltrim" "lub" "max" "min" "mod" "months_between" "new_time"
+"next_day" "nextval" "nls_initcap" "nls_lower" "nls_upper" "nlssort"
+"nvl" "power" "rawtohex" "replace" "round" "rowidtochar" "rpad"
+"rtrim" "sign" "sin" "sinh" "soundex" "sqlcode" "sqlerrm" "sqrt"
+"stddev" "sum" "substr" "substrb" "tan" "tanh" "to_char"
+"to_date" "to_label" "to_multi_byte" "to_number" "to_single_byte"
+"translate" "trunc" "uid" "upper" "userenv" "variance" "vsize") t) "\\b"))))
+    (setq sql-mode-oracle-font-lock-keywords
+	  (append sql-mode-ansi-font-lock-keywords
+		  (list (cons oracle-keywords font-lock-function-name-face)
+			(cons oracle-reserved-words font-lock-keyword-face)
+			;; XEmacs doesn't have font-lock-builtin-face
+			(if (string-match "XEmacs\\|Lucid" emacs-version)
+			    (cons oracle-builtin-functions font-lock-preprocessor-face)
+			  ;; GNU Emacs 19 doesn't have it either
+			  (if (string-match "GNU Emacs 19" emacs-version)
+			      (cons oracle-builtin-functions font-lock-function-name-face)
+			    ;; Emacs
+			    (cons oracle-builtin-functions font-lock-builtin-face)))
+			(cons oracle-types font-lock-type-face))))))
+
+(defvar sql-mode-postgres-font-lock-keywords nil
+  "Postgres SQL keywords used by font-lock.
+
+This variable is used by `sql-mode' and `sql-interactive-mode'.  The
+regular expressions are created during compilation by calling the
+function `regexp-opt'.  Therefore, take a look at the source before
+you define your own sql-mode-postgres-font-lock-keywords.")
+
+(if sql-mode-postgres-font-lock-keywords
+    ()
+  (let ((postgres-reserved-words (eval-when-compile
+				 (concat "\\b"
+					 (regexp-opt '(
+"language"
+) t) "\\b")))
+	(postgres-types (eval-when-compile 
+			  (concat "\\b" 
+				  (regexp-opt '( 
+"bool" "box" "circle" "char" "char2" "char4" "char8" "char16" "date" 
+"float4" "float8" "int2" "int4" "int8" "line" "lseg" "money" "path" 
+"point" "polygon" "serial" "text" "time" "timespan" "timestamp" "varchar"
+) t)"\\b")))
+	(postgres-builtin-functions (eval-when-compile
+			(concat "\\b"
+				(regexp-opt '(
+;; Misc Postgres builtin functions
+"abstime" "age" "area" "box" "center" "date_part" "date_trunc"
+"datetime" "dexp" "diameter" "dpow" "float" "float4" "height"
+"initcap" "integer" "isclosed" "isfinite" "isoldpath" "isopen"
+"length" "lower" "lpad" "ltrim" "pclose" "point" "points" "popen"
+"position" "radius" "reltime" "revertpoly" "rpad" "rtrim" "substr"
+"substring" "text" "timespan" "translate" "trim" "upgradepath"
+"upgradepoly" "upper" "varchar" "width"
+) t) "\\b"))))
+    (setq sql-mode-postgres-font-lock-keywords
+	  (append sql-mode-ansi-font-lock-keywords
+		  (list (cons postgres-reserved-words font-lock-keyword-face)
+			;; XEmacs doesn't have font-lock-builtin-face
+			(if (string-match "XEmacs\\|Lucid" emacs-version)
+			    (cons postgres-builtin-functions font-lock-preprocessor-face)
+			  ;; Emacs
+			  (cons postgres-builtin-functions font-lock-builtin-face))
+			(cons postgres-types font-lock-type-face))))))
+
+
+(defvar sql-mode-font-lock-keywords sql-mode-ansi-font-lock-keywords
+  "SQL keywords used by font-lock.
+
+This variable defaults to `sql-mode-ansi-font-lock-keywords'.  This is
+used for the default `font-lock-defaults' value in `sql-mode'.  This
+can be changed by some entry functions to provide more hilighting.")
+
+
+
+;;; Small functions
+
+(defun sql-accumulate-and-indent ()
+  "Continue SQL statement on the next line."
+  (interactive)
+  ;; comint-accumulate is a Emacs 20.X thingie
+  (if (not (string-match "XEmacs\\|Lucid\\|GNU Emacs 19" emacs-version))
+      (comint-accumulate))
+  (indent-according-to-mode))
+
+;;;###autoload
+(defun sql-help ()
+  "Shows short help for the SQL modes.
+
+Use an entry function to open an interactive SQL buffer.  This buffer is
+usually named *SQL*.  The name of the major mode is SQLi.
+
+Use the following commands to start a specific SQL interpreter:
+
+psql by PostGres: \\[sql-postgres]
+SQL*Plus: \\[sql-oracle]
+dbaccess: \\[sql-informix]
+isql (Sybase): \\[sql-sybase]
+sql (Ingres): \\[sql-ingres]
+isql (Microsoft): \\[sql-ms]
+
+Once you have the SQLi buffer, you can enter SQL statements in the
+buffer.  The output generated is appended to the buffer and a new prompt
+is generated.  See the In/Out menu in the SQLi buffer for some functions
+that help you navigate through the buffer, the input history, etc.
+
+Put a line with a call to autoload into your `~/.emacs' file for each
+entry function you want to use regularly:
+
+\(autoload 'sql-postgres \"sql\" \"Interactive SQL mode.\" t)
+
+If you have a really complex SQL statement or if you are writing a
+procedure, you can do this in a separate buffer.  Put the new buffer in
+`sql-mode' by calling \\[sql-mode].  The name of this buffer can be
+anything.  The name of the major mode is SQL.
+
+In this SQL buffer (SQL mode), you can send the region or the entire
+buffer to the interactive SQL buffer (SQLi mode).  The results are
+appended to the SQLi buffer without disturbing your SQL buffer."
+  (interactive)
+  (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)))
+
+(defun sql-get-login (&rest what)
+  "Get username, password and database from the user.
+
+The variables `sql-user', `sql-password', `sql-server' and
+`sql-database' can be customised.  They are used as the default
+values.  Usernames, servers and databases are stored in
+`sql-user-history', `sql-server-history' and `database-history'.
+Passwords are not stored in a history.
+
+Parameter WHAT is a list of the arguments passed to this function.
+The function asks for the username if WHAT contains symbol `user', for
+the password if it contains symbol `password', for the server if it
+contains symbol `server', and for the database if it contains symbol
+`database'.
+
+In order to ask the user for username, password and database, call the
+function like this: (sql-get-login 'user 'password 'database)."
+  (interactive)
+  (if (memq 'user what)
+      (setq sql-user 
+	    (read-from-minibuffer "User: " sql-user nil nil
+				  sql-user-history)))
+  (if (memq 'password what)
+      (setq sql-password 
+	    (sql-read-passwd "Password: " sql-password)))
+  (if (memq 'server what)
+      (setq sql-server 
+	    (read-from-minibuffer "Server: " sql-server nil nil
+				  sql-server-history)))
+  (if (memq 'database what)
+      (setq sql-database 
+	    (read-from-minibuffer "Database: " sql-database nil nil
+				  sql-database-history))))
+
+(defun sql-copy-column ()
+  "Copy current column to the end of buffer.
+Inserts SELECT or commas if appropriate."
+  (interactive)
+  (let ((column))
+    (save-excursion
+      (setq column (buffer-substring
+		  (progn (forward-char 1) (backward-sexp 1) (point))
+		  (progn (forward-sexp 1) (point))))
+      (goto-char (point-max))
+      (cond
+       ;; if empty command line, insert SELECT
+       ((save-excursion (beginning-of-line) 
+			(looking-at (concat comint-prompt-regexp "$")))
+	(insert "SELECT "))
+       ;; else if appending to SELECT or ORDER BY, insert a comma
+       ((save-excursion 
+	  (re-search-backward "\\b\\(select\\|order by\\) .+"
+			      (save-excursion (beginning-of-line) (point)) t))
+	(insert ", "))
+       ;; else insert a space
+       (t
+	(if (eq (preceding-char) ? )
+	    nil
+	  (insert " "))))
+      ;; in any case, insert the column
+      (insert column)
+      (message "%s" column))))
+
+
+
+;;; Sending the region to the SQLi buffer.
+
+(defun sql-send-region (start end)
+  "Send a region to the SQL process."
+  (interactive "r")
+  (if (buffer-live-p sql-buffer)
+      (save-excursion
+	(comint-send-region sql-buffer start end)
+	(if (string-match "\n$" (buffer-substring start end))
+	    ()
+	  (comint-send-string sql-buffer "\n"))
+	(if sql-pop-to-buffer-after-send-region 
+	    (pop-to-buffer sql-buffer)
+	  (display-buffer sql-buffer)))
+    (message "No SQL process started.")))
+
+(defun sql-send-buffer ()
+  "Send the buffer contents to the SQL process."
+  (interactive)
+  (sql-send-region (point-min) (point-max)))
+
+(defun sql-toggle-pop-to-buffer-after-send-region (&optional value)
+  "Toggle `sql-pop-to-buffer-after-send-region'.
+
+If given the optional parameter VALUE, sets
+sql-toggle-pop-to-buffer-after-send-region to VALUE."
+  (interactive "P")
+  (if value
+      (setq sql-pop-to-buffer-after-send-region value)
+    (setq sql-pop-to-buffer-after-send-region 
+	  (null sql-pop-to-buffer-after-send-region ))))
+
+
+
+;;; SQL mode -- uses SQL interactive mode
+
+;;;###autoload
+(defun sql-mode ()
+  "Major mode to edit SQL.
+
+You can send SQL statements to the *SQL* buffer using
+\\[sql-send-region].  Such a buffer must exist before you can do this.
+See `sql-help'.
+
+\\{sql-mode-map} 
+Customization: Entry to this mode runs the `sql-mode-hook'.
+
+Here is an example for your .emacs file.  It opens every file ending in
+.sql with sql-mode.
+
+\(setq auto-mode-alist (append auto-mode-alist
+                              \(list '(\"\\\\.sql$\" . sql-mode))))"
+  (interactive)
+  (kill-all-local-variables)
+  (setq major-mode 'sql-mode)
+  (setq mode-name "SQL")
+  (use-local-map sql-mode-map)
+  (set-syntax-table sql-mode-syntax-table)
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '(sql-mode-font-lock-keywords 
+			     nil t ((95 . "w") (46 . "w"))))
+  (setq local-abbrev-table sql-mode-abbrev-table)
+  (setq abbrev-all-caps 1)
+  (run-hooks 'sql-mode-hook))
+
+
+
+;;; SQL interactive mode
+
+(put 'sql-interactive-mode 'mode-class 'special)
+
+(defun sql-interactive-mode ()
+  "Major mode to use a SQL interpreter interactively.
+
+Do not call this function by yourself.  The environment must be
+initialized by an entry function specific for the SQL interpreter.  See
+`sql-help' for a list of available entry functions.
+
+\\[comint-send-input] after the end of the process' output sends the
+text from the end of process to the end of the current line.
+\\[comint-send-input] before end of process output copies the current
+line minus the prompt to the end of the buffer and sends it.
+\\[comint-copy-old-input] just copies the current line.
+Use \\[sql-accumulate-and-indent] to enter multi-line statements.
+
+If you want to make multiple SQL buffers, rename the `*SQL*' buffer
+using \\[rename-buffer] or \\[rename-uniquely] and start a new process.
+
+If you accidentally suspend your process, use \\[comint-continue-subjob]
+to continue it.
+
+\\{sql-interactive-mode-map}
+Customization: Entry to this mode runs the hooks on `comint-mode-hook'
+and `sql-interactive-mode-hook' (in that order).  Before each input, the
+hooks on `comint-input-filter-functions' are run.  After each SQL
+interpreter output, the hooks on `comint-output-filter-functions' are
+run.
+
+Variable `comint-input-ring-file-name' controls the initialisation of
+the input ring history.
+
+Variables `comint-output-filter-functions', a hook, and
+`comint-scroll-to-bottom-on-input' and
+`comint-scroll-to-bottom-on-output' control whether input and output
+cause the window to scroll to the end of the buffer.
+
+If you want to make SQL buffers limited in length, add the function
+`comint-truncate-buffer' to `comint-output-filter-functions'.
+
+Here is an example for your .emacs file.  It keeps the *SQL* Buffer a
+certain length and stores all inputs in an input-ring file.
+
+\(add-hook 'sql-interactive-mode-hook
+    \(function (lambda ()
+        \(setq comint-input-ring-file-name \"~/.sql_history\")
+        \(setq comint-output-filter-functions 'comint-truncate-buffer))))
+
+Here is another example.  It will always put point back to the statement
+you entered, right above the output it created.
+
+\(setq comint-output-filter-functions 
+       \(function (lambda (STR) (comint-show-output))))"
+  (comint-mode)
+  (setq comint-prompt-regexp sql-prompt-regexp)
+  (setq major-mode 'sql-interactive-mode)
+  (setq mode-name "SQLi")
+  (use-local-map sql-interactive-mode-map)
+  (set-syntax-table sql-mode-syntax-table)
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '(sql-mode-font-lock-keywords t t ((95 . "w") (46 . "w"))))
+  (setq left-margin 5)
+  (setq local-abbrev-table sql-mode-abbrev-table)
+  (setq abbrev-all-caps 1)
+  (set-process-sentinel (get-buffer-process sql-buffer) 'sql-stop)
+  (run-hooks 'sql-interactive-mode-hook)
+  ;; calling the hook before calling comint-read-input-ring allows users
+  ;; to set comint-input-ring-file-name in sql-interactive-mode-hook.
+  (comint-read-input-ring t))
+
+(defun sql-stop (process event)
+  "Called when the SQL process is stopped.
+
+Writes the input history to a history file using `comint-write-input-ring'
+and inserts a short message in the SQL buffer.
+
+This function is a sentinel watching the SQL interpreter process.
+Sentinels will always get the two parameters PROCESS and EVENT."
+  (comint-write-input-ring)
+  (if (buffer-live-p sql-buffer)
+      (insert (format "\nProcess %s %s\n" process event))))
+
+
+
+;;; Entry functions for different SQL interpreters.
+
+(defun sql-oracle ()
+  "Run sqlplus by Oracle as an inferior process.
+
+If buffer *SQL* exists but no process is running, make a new process.
+If buffer exists and a process is running, just switch to buffer
+`*SQL*'.
+
+Interpreter used comes from variable `sql-oracle-program'.  Login
+uses the variables `sql-user', `sql-password' and `sql-database' as
+defaults, if set.
+
+The buffer is put in sql-interactive-mode, giving commands for sending
+input.  See `sql-interactive-mode'.
+
+To specify a coding system for converting non-ASCII characters
+in the input and output to the process, use \\[universal-coding-system-argument]
+before \\[sql-oracle].  You can also specify this with \\[set-buffer-process-coding-system]
+in the SQL buffer, after you start the process.
+The default comes from `process-coding-system-alist' and
+`default-process-coding-system'.
+
+\(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
+  (interactive)
+  (if (comint-check-proc "*SQL*")
+      (pop-to-buffer "*SQL*")
+    (sql-get-login 'user 'password 'database)
+    (message "Login...")
+    ;; Produce user/password@database construct.  Password without user
+    ;; is meaningless; database without user/password is meaningless,
+    ;; because "@param" will ask sqlplus to interpret the script
+    ;; "param".
+    (let ((parameter nil))
+      (if (not (string= "" sql-user))
+	  (if (not (string= "" sql-password))
+	      (setq parameter (concat sql-user "/" sql-password))
+	    (setq parameter sql-user)))
+      (if (and parameter (not (string= "" sql-database)))
+	  (setq parameter (concat parameter "@" sql-database)))
+      (if parameter
+	  (set-buffer (make-comint "SQL" sql-oracle-program nil parameter))
+	(set-buffer (make-comint "SQL" sql-oracle-program nil))))
+    (setq sql-prompt-regexp "^SQL> ")
+    (setq sql-buffer (current-buffer))
+    ;; set sql-mode-font-lock-keywords to something different before
+    ;; calling sql-interactive-mode.
+    (setq sql-mode-font-lock-keywords sql-mode-oracle-font-lock-keywords)
+    (sql-interactive-mode)
+    (message "Login...done")
+    (pop-to-buffer sql-buffer)))
+
+
+
+(defun sql-sybase ()
+  "Run isql by SyBase as an inferior process.
+
+If buffer *SQL* exists but no process is running, make a new process.
+If buffer exists and a process is running, just switch to buffer
+`*SQL*'.
+
+Interpreter used comes from variable `sql-sybase-program'.  Login uses
+the variables `sql-user', `sql-password' and `sql-database' as defaults,
+if set.
+
+The buffer is put in sql-interactive-mode, giving commands for sending
+input.  See `sql-interactive-mode'.
+
+To specify a coding system for converting non-ASCII characters
+in the input and output to the process, use \\[universal-coding-system-argument]
+before \\[sql-sybase].  You can also specify this with \\[set-buffer-process-coding-system]
+in the SQL buffer, after you start the process.
+The default comes from `process-coding-system-alist' and
+`default-process-coding-system'.
+
+\(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
+  (interactive)
+  (if (comint-check-proc "*SQL*")
+      (pop-to-buffer "*SQL*")
+    (sql-get-login 'user 'password 'database)
+    (message "Login...")
+    ;; Put all parameters to the program (if defined) in a list and call
+    ;; make-comint.
+    (let ((params '("-w" "2048" "-n")))
+      ;; I had a zillion versions of this using nconc and mapcar,
+      ;; mixtures of eval, list and quotes -- you have been warned.
+      (if (not (string= "" sql-database))
+	  (setq params (append (list "-S" sql-database) params)))
+      (if (not (string= "" sql-password))
+	  (setq params (append (list "-P" sql-password) params)))
+      (if (not (string= "" sql-user))
+	  (setq params (append (list "-U" sql-user) params)))
+      (set-buffer (apply 'make-comint "SQL" sql-sybase-program 
+			 nil params)))
+    (setq sql-prompt-regexp "^SQL> ")
+    (setq sql-buffer (current-buffer))
+    (sql-interactive-mode)
+    (message "Login...done")
+    (pop-to-buffer sql-buffer)))
+
+
+
+(defun sql-informix ()
+  "Run dbaccess by Informix as an inferior process.
+
+If buffer *SQL* exists but no process is running, make a new process.
+If buffer exists and a process is running, just switch to buffer
+`*SQL*'.
+
+Interpreter used comes from variable `sql-informix-program'.  Login uses
+the variable `sql-database' as default, if set.
+
+The buffer is put in sql-interactive-mode, giving commands for sending
+input.  See `sql-interactive-mode'.
+
+To specify a coding system for converting non-ASCII characters
+in the input and output to the process, use \\[universal-coding-system-argument]
+before \\[sql-informix].  You can also specify this with \\[set-buffer-process-coding-system]
+in the SQL buffer, after you start the process.
+The default comes from `process-coding-system-alist' and
+`default-process-coding-system'.
+
+\(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
+  (interactive)
+  (if (comint-check-proc "*SQL*")
+      (pop-to-buffer "*SQL*")
+    (sql-get-login 'database)
+    (message "Login...")
+    ;; username and password are ignored.
+    (if (string= "" sql-database)
+	(set-buffer (make-comint "SQL" sql-informix-program nil))
+      (set-buffer (make-comint "SQL" sql-informix-program nil sql-database)))
+    (setq sql-prompt-regexp "^SQL> ")
+    (setq sql-buffer (current-buffer))
+    (sql-interactive-mode)
+    (message "Login...done")
+    (pop-to-buffer sql-buffer)))
+
+
+
+(defun sql-ingres ()
+  "Run sql by Ingres as an inferior process.
+
+If buffer *SQL* exists but no process is running, make a new process.
+If buffer exists and a process is running, just switch to buffer
+`*SQL*'.
+
+Interpreter used comes from variable `sql-ingres-program'.  Login uses
+the variable `sql-database' as default, if set.
+
+The buffer is put in sql-interactive-mode, giving commands for sending
+input.  See `sql-interactive-mode'.
+
+To specify a coding system for converting non-ASCII characters
+in the input and output to the process, use \\[universal-coding-system-argument]
+before \\[sql-ingres].  You can also specify this with \\[set-buffer-process-coding-system]
+in the SQL buffer, after you start the process.
+The default comes from `process-coding-system-alist' and
+`default-process-coding-system'.
+
+\(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
+  (interactive)
+  (if (comint-check-proc "*SQL*")
+      (pop-to-buffer "*SQL*")
+    (sql-get-login 'database)
+    (message "Login...")
+    ;; username and password are ignored.
+    (if (string= "" sql-database)
+	(set-buffer (make-comint "SQL" sql-ingres-program nil))
+      (set-buffer (make-comint "SQL" sql-ingres-program nil sql-database)))
+    (setq sql-prompt-regexp "^\* ")
+    (setq sql-buffer (current-buffer))
+    (sql-interactive-mode)
+    (message "Login...done")
+    (pop-to-buffer sql-buffer)))
+
+
+
+(defun sql-ms ()
+  "Run isql by Microsoft as an inferior process.
+
+If buffer *SQL* exists but no process is running, make a new process.
+If buffer exists and a process is running, just switch to buffer
+`*SQL*'.
+
+Interpreter used comes from variable `sql-ms-program'.  Login uses the
+variables `sql-user', `sql-password', `sql-server' and `sql-database'
+as defaults, if set.
+
+The buffer is put in sql-interactive-mode, giving commands for sending
+input.  See `sql-interactive-mode'.
+
+To specify a coding system for converting non-ASCII characters
+in the input and output to the process, use \\[universal-coding-system-argument]
+before \\[sql-sybase].  You can also specify this with \\[set-buffer-process-coding-system]
+in the SQL buffer, after you start the process.
+The default comes from `process-coding-system-alist' and
+`default-process-coding-system'.
+
+\(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
+  (interactive)
+  (if (comint-check-proc "*SQL*")
+      (pop-to-buffer "*SQL*")
+    (sql-get-login 'user 'password 'database 'server)
+    (message "Login...")
+    ;; Put all parameters to the program (if defined) in a list and call
+    ;; make-comint.
+    (let ((params '("-w 300")))
+      (if (not (string= "" sql-server))
+        (setq params (append (list "-S" sql-server) params)))
+      (if (not (string= "" sql-database))
+        (setq params (append (list "-d" sql-database) params)))
+      (if (not (string= "" sql-user))
+	  (setq params (append (list "-U" sql-user) params)))
+      (if (not (string= "" sql-password))
+	  (setq params (append (list "-P" sql-password) params))
+	;; If -P is passed to ISQL as the last argument without a password,
+	;; it's considered null.
+	(setq params (append params (list "-P"))))
+      (set-buffer (apply 'make-comint "SQL" sql-ms-program
+			 nil params)))
+    (setq sql-prompt-regexp "^[0-9]*>")
+    (setq sql-buffer (current-buffer))
+    (sql-interactive-mode)
+    (message "Login...done")
+    (pop-to-buffer sql-buffer)))
+
+
+
+
+;;;###autoload
+(defun sql-postgres ()
+  "Run psql by Postgres as an inferior process.
+
+If buffer *SQL* exists but no process is running, make a new process.
+If buffer exists and a process is running, just switch to buffer
+`*SQL*'.
+
+Interpreter used comes from variable `sql-postgres-program'.  Login uses
+the variable `sql-database' as default, if set.
+
+The buffer is put in sql-interactive-mode, giving commands for sending
+input.  See `sql-interactive-mode'.
+
+To specify a coding system for converting non-ASCII characters
+in the input and output to the process, use \\[universal-coding-system-argument]
+before \\[sql-postgres].  You can also specify this with \\[set-buffer-process-coding-system]
+in the SQL buffer, after you start the process.
+The default comes from `process-coding-system-alist' and
+`default-process-coding-system'.  If your output lines end with ^M, 
+your might try undecided-dos as a coding system.  If this doesn't help,
+Try to set `comint-output-filter-functions' like this:
+
+\(setq comint-output-filter-functions (append comint-output-filter-functions
+					     '(comint-strip-ctrl-m)))
+
+\(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
+  (interactive)
+  (if (comint-check-proc "*SQL*")
+      (pop-to-buffer "*SQL*")
+    (sql-get-login 'database)
+    (message "Login...")
+    ;; username and password are ignored.
+    (if (string= "" sql-database)
+	(set-buffer (make-comint "SQL" sql-postgres-program nil))
+      (set-buffer (make-comint "SQL" sql-postgres-program nil sql-database)))
+    (setq sql-prompt-regexp "^.*> *")
+    ;; This is a lousy hack to prevent psql from truncating it's output
+    ;; and giving stupid warnings. If s.o. knows a way to prevent psql 
+    ;; from acting this way, then I would be very thankful to
+    ;; incorporate this (Gregor Zych <zych@pool.informatik.rwth-aachen.de>)
+    (comint-send-string "*SQL*" "\\o \| cat\n")
+    (setq sql-mode-font-lock-keywords sql-mode-postgres-font-lock-keywords)
+    (setq sql-buffer (current-buffer))
+    (sql-interactive-mode)
+    (message "Login...done")
+    (pop-to-buffer sql-buffer)))
+
+(provide 'sql)
+
+;;; sql.el ends here