* internals.texi (Stack-allocated Objects): Describe this feature.
[emacs.git] / lisp / progmodes / sql.el
1 ;;; sql.el --- specialized comint.el for SQL interpreters  -*- lexical-binding: t -*-
2
3 ;; Copyright (C) 1998-2014 Free Software Foundation, Inc.
4
5 ;; Author: Alex Schroeder <alex@gnu.org>
6 ;; Maintainer: Michael Mauger <michael@mauger.com>
7 ;; Version: 3.4
8 ;; Keywords: comm languages processes
9 ;; URL: http://savannah.gnu.org/projects/emacs/
10
11 ;; This file is part of GNU Emacs.
12
13 ;; GNU Emacs is free software: you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation, either version 3 of the License, or
16 ;; (at your option) any later version.
17
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 ;; GNU General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
25
26 ;;; Commentary:
27
28 ;; Please send bug reports and bug fixes to the mailing list at
29 ;; help-gnu-emacs@gnu.org.  If you want to subscribe to the mailing
30 ;; list, see the web page at
31 ;; http://lists.gnu.org/mailman/listinfo/help-gnu-emacs for
32 ;; instructions.  I monitor this list actively.  If you send an e-mail
33 ;; to Alex Schroeder it usually makes it to me when Alex has a chance
34 ;; to forward them along (Thanks, Alex).
35
36 ;; This file provides a sql-mode and a sql-interactive-mode.  The
37 ;; original goals were two simple modes providing syntactic
38 ;; highlighting.  The interactive mode had to provide a command-line
39 ;; history; the other mode had to provide "send region/buffer to SQL
40 ;; interpreter" functions.  "simple" in this context means easy to
41 ;; use, easy to maintain and little or no bells and whistles.  This
42 ;; has changed somewhat as experience with the mode has accumulated.
43
44 ;; Support for different flavors of SQL and command interpreters was
45 ;; available in early versions of sql.el.  This support has been
46 ;; extended and formalized in later versions.  Part of the impetus for
47 ;; the improved support of SQL flavors was borne out of the current
48 ;; maintainers consulting experience.  In the past twenty years, I
49 ;; have used Oracle, Sybase, Informix, MySQL, Postgres, and SQLServer.
50 ;; On some assignments, I have used two or more of these concurrently.
51
52 ;; If anybody feels like extending this sql mode, take a look at the
53 ;; above mentioned modes and write a sqlx-mode on top of this one.  If
54 ;; this proves to be difficult, please suggest changes that will
55 ;; facilitate your plans.  Facilities have been provided to add
56 ;; products and product-specific configuration.
57
58 ;; sql-interactive-mode is used to interact with a SQL interpreter
59 ;; process in a SQLi buffer (usually called `*SQL*').  The SQLi buffer
60 ;; is created by calling a SQL interpreter-specific entry function or
61 ;; sql-product-interactive.  Do *not* call sql-interactive-mode by
62 ;; itself.
63
64 ;; The list of currently supported interpreters and the corresponding
65 ;; entry function used to create the SQLi buffers is shown with
66 ;; `sql-help' (M-x sql-help).
67
68 ;; Since sql-interactive-mode is built on top of the general
69 ;; command-interpreter-in-a-buffer mode (comint mode), it shares a
70 ;; common base functionality, and a common set of bindings, with all
71 ;; modes derived from comint mode.  This makes these modes easier to
72 ;; use.
73
74 ;; sql-mode can be used to keep editing SQL statements.  The SQL
75 ;; statements can be sent to the SQL process in the SQLi buffer.
76
77 ;; For documentation on the functionality provided by comint mode, and
78 ;; the hooks available for customizing it, see the file `comint.el'.
79
80 ;; Hint for newbies: take a look at `dabbrev-expand', `abbrev-mode', and
81 ;; `imenu-add-menubar-index'.
82
83 ;;; Bugs:
84
85 ;; sql-ms now uses osql instead of isql.  Osql flushes its error
86 ;; stream more frequently than isql so that error messages are
87 ;; available.  There is no prompt and some output still is buffered.
88 ;; This improves the interaction under Emacs but it still is somewhat
89 ;; awkward.
90
91 ;; Quoted identifiers are not supported for highlighting.  Most
92 ;; databases support the use of double quoted strings in place of
93 ;; identifiers; ms (Microsoft SQLServer) also supports identifiers
94 ;; enclosed within brackets [].
95
96 ;;; Product Support:
97
98 ;; To add support for additional SQL products the following steps
99 ;; must be followed ("xyz" is the name of the product in the examples
100 ;; below):
101
102 ;; 1) Add the product to the list of known products.
103
104 ;;     (sql-add-product 'xyz "XyzDB"
105 ;;                      '(:free-software t))
106
107 ;; 2) Define font lock settings.  All ANSI keywords will be
108 ;;    highlighted automatically, so only product specific keywords
109 ;;    need to be defined here.
110
111 ;;     (defvar my-sql-mode-xyz-font-lock-keywords
112 ;;       '(("\\b\\(red\\|orange\\|yellow\\)\\b"
113 ;;          . font-lock-keyword-face))
114 ;;       "XyzDB SQL keywords used by font-lock.")
115
116 ;;     (sql-set-product-feature 'xyz
117 ;;                              :font-lock
118 ;;                              'my-sql-mode-xyz-font-lock-keywords)
119
120 ;; 3) Define any special syntax characters including comments and
121 ;;    identifier characters.
122
123 ;;     (sql-set-product-feature 'xyz
124 ;;                              :syntax-alist ((?# . "_")))
125
126 ;; 4) Define the interactive command interpreter for the database
127 ;;    product.
128
129 ;;     (defcustom my-sql-xyz-program "ixyz"
130 ;;       "Command to start ixyz by XyzDB."
131 ;;       :type 'file
132 ;;       :group 'SQL)
133 ;;
134 ;;     (sql-set-product-feature 'xyz
135 ;;                              :sqli-program 'my-sql-xyz-program)
136 ;;     (sql-set-product-feature 'xyz
137 ;;                              :prompt-regexp "^xyzdb> ")
138 ;;     (sql-set-product-feature 'xyz
139 ;;                              :prompt-length 7)
140
141 ;; 5) Define login parameters and command line formatting.
142
143 ;;     (defcustom my-sql-xyz-login-params '(user password server database)
144 ;;       "Login parameters to needed to connect to XyzDB."
145 ;;       :type 'sql-login-params
146 ;;       :group 'SQL)
147 ;;
148 ;;     (sql-set-product-feature 'xyz
149 ;;                              :sqli-login 'my-sql-xyz-login-params)
150
151 ;;     (defcustom my-sql-xyz-options '("-X" "-Y" "-Z")
152 ;;       "List of additional options for `sql-xyz-program'."
153 ;;       :type '(repeat string)
154 ;;       :group 'SQL)
155 ;;
156 ;;     (sql-set-product-feature 'xyz
157 ;;                              :sqli-options 'my-sql-xyz-options))
158
159 ;;     (defun my-sql-comint-xyz (product options)
160 ;;       "Connect ti XyzDB in a comint buffer."
161 ;;
162 ;;         ;; Do something with `sql-user', `sql-password',
163 ;;         ;; `sql-database', and `sql-server'.
164 ;;         (let ((params
165 ;;                (append
166 ;;           (if (not (string= "" sql-user))
167 ;;                     (list "-U" sql-user))
168 ;;                 (if (not (string= "" sql-password))
169 ;;                     (list "-P" sql-password))
170 ;;                 (if (not (string= "" sql-database))
171 ;;                     (list "-D" sql-database))
172 ;;                 (if (not (string= "" sql-server))
173 ;;                     (list "-S" sql-server))
174 ;;                 options)))
175 ;;           (sql-comint product params)))
176 ;;
177 ;;     (sql-set-product-feature 'xyz
178 ;;                              :sqli-comint-func 'my-sql-comint-xyz)
179
180 ;; 6) Define a convenience function to invoke the SQL interpreter.
181
182 ;;     (defun my-sql-xyz (&optional buffer)
183 ;;       "Run ixyz by XyzDB as an inferior process."
184 ;;       (interactive "P")
185 ;;       (sql-product-interactive 'xyz buffer))
186
187 ;;; To Do:
188
189 ;; Improve keyword highlighting for individual products.  I have tried
190 ;; to update those database that I use.  Feel free to send me updates,
191 ;; or direct me to the reference manuals for your favorite database.
192
193 ;; When there are no keywords defined, the ANSI keywords are
194 ;; highlighted.  ANSI keywords are highlighted even if the keyword is
195 ;; not used for your current product.  This should help identify
196 ;; portability concerns.
197
198 ;; Add different highlighting levels.
199
200 ;; Add support for listing available tables or the columns in a table.
201
202 ;;; Thanks to all the people who helped me out:
203
204 ;; Alex Schroeder <alex@gnu.org> -- the original author
205 ;; Kai Blauberg <kai.blauberg@metla.fi>
206 ;; <ibalaban@dalet.com>
207 ;; Yair Friedman <yfriedma@JohnBryce.Co.Il>
208 ;; Gregor Zych <zych@pool.informatik.rwth-aachen.de>
209 ;; nino <nino@inform.dk>
210 ;; Berend de Boer <berend@pobox.com>
211 ;; Adam Jenkins <adam@thejenkins.org>
212 ;; Michael Mauger <michael@mauger.com> -- improved product support
213 ;; Drew Adams <drew.adams@oracle.com> -- Emacs 20 support
214 ;; Harald Maier <maierh@myself.com> -- sql-send-string
215 ;; Stefan Monnier <monnier@iro.umontreal.ca> -- font-lock corrections;
216 ;;      code polish
217 ;; Paul Sleigh <bat@flurf.net> -- MySQL keyword enhancement
218 ;; Andrew Schein <andrew@andrewschein.com> -- sql-port bug
219 ;; Ian Bjorhovde <idbjorh@dataproxy.com> -- db2 escape newlines
220 ;;      incorrectly enabled by default
221 ;; Roman Scherer <roman.scherer@nugg.ad> -- Connection documentation
222 ;; Mark Wilkinson <wilkinsonmr@gmail.com> -- file-local variables ignored
223 ;;
224
225 \f
226
227 ;;; Code:
228
229 (require 'cl-lib)
230 (require 'comint)
231 ;; Need the following to allow GNU Emacs 19 to compile the file.
232 (eval-when-compile
233   (require 'regexp-opt))
234 (require 'custom)
235 (require 'thingatpt)
236 (require 'view)
237
238 (defvar font-lock-keyword-face)
239 (defvar font-lock-set-defaults)
240 (defvar font-lock-string-face)
241
242 ;;; Allow customization
243
244 (defgroup SQL nil
245   "Running a SQL interpreter from within Emacs buffers."
246   :version "20.4"
247   :group 'languages
248   :group 'processes)
249
250 ;; These five variables will be used as defaults, if set.
251
252 (defcustom sql-user ""
253   "Default username."
254   :type 'string
255   :group 'SQL
256   :safe 'stringp)
257
258 (defcustom sql-password ""
259   "Default password.
260 If you customize this, the value will be stored in your init
261 file.  Since that is a plaintext file, this could be dangerous."
262   :type 'string
263   :group 'SQL
264   :risky t)
265
266 (defcustom sql-database ""
267   "Default database."
268   :type 'string
269   :group 'SQL
270   :safe 'stringp)
271
272 (defcustom sql-server ""
273   "Default server or host."
274   :type 'string
275   :group 'SQL
276   :safe 'stringp)
277
278 (defcustom sql-port 0
279   "Default port for connecting to a MySQL or Postgres server."
280   :version "24.1"
281   :type 'number
282   :group 'SQL
283   :safe 'numberp)
284
285 (defcustom sql-default-directory nil
286   "Default directory for SQL processes."
287   :version "25.1"
288   :type '(choice (const nil) string)
289   :group 'SQL
290   :safe 'stringp)
291
292 ;; Login parameter type
293
294 (define-widget 'sql-login-params 'lazy
295   "Widget definition of the login parameters list"
296   :tag "Login Parameters"
297   :type '(set :tag "Login Parameters"
298               (choice :tag "user"
299                       :value user
300                       (const user)
301                       (list :tag "Specify a default"
302                             (const user)
303                             (list :tag "Default"
304                                   :inline t (const :default) string)))
305               (const password)
306               (choice :tag "server"
307                       :value server
308                       (const server)
309                       (list :tag "Specify a default"
310                             (const server)
311                             (list :tag "Default"
312                                   :inline t (const :default) string))
313                       (list :tag "file"
314                             (const :format "" server)
315                             (const :format "" :file)
316                             regexp)
317                       (list :tag "completion"
318                             (const :format "" server)
319                             (const :format "" :completion)
320                             (restricted-sexp
321                              :match-alternatives (listp stringp))))
322               (choice :tag "database"
323                       :value database
324                       (const database)
325                       (list :tag "Specify a default"
326                             (const database)
327                             (list :tag "Default"
328                                   :inline t (const :default) string))
329                       (list :tag "file"
330                             (const :format "" database)
331                             (const :format "" :file)
332                             regexp)
333                       (list :tag "completion"
334                             (const :format "" database)
335                                 (const :format "" :completion)
336                                 (restricted-sexp
337                                  :match-alternatives (listp stringp))))
338               (const port)))
339
340 ;; SQL Product support
341
342 (defvar sql-interactive-product nil
343   "Product under `sql-interactive-mode'.")
344
345 (defvar sql-connection nil
346   "Connection name if interactive session started by `sql-connect'.")
347
348 (defvar sql-product-alist
349   '((ansi
350      :name "ANSI"
351      :font-lock sql-mode-ansi-font-lock-keywords
352      :statement sql-ansi-statement-starters)
353
354     (db2
355      :name "DB2"
356      :font-lock sql-mode-db2-font-lock-keywords
357      :sqli-program sql-db2-program
358      :sqli-options sql-db2-options
359      :sqli-login sql-db2-login-params
360      :sqli-comint-func sql-comint-db2
361      :prompt-regexp "^db2 => "
362      :prompt-length 7
363      :prompt-cont-regexp "^db2 (cont\.) => "
364      :input-filter sql-escape-newlines-filter)
365
366     (informix
367      :name "Informix"
368      :font-lock sql-mode-informix-font-lock-keywords
369      :sqli-program sql-informix-program
370      :sqli-options sql-informix-options
371      :sqli-login sql-informix-login-params
372      :sqli-comint-func sql-comint-informix
373      :prompt-regexp "^> "
374      :prompt-length 2
375      :syntax-alist ((?{ . "<") (?} . ">")))
376
377     (ingres
378      :name "Ingres"
379      :font-lock sql-mode-ingres-font-lock-keywords
380      :sqli-program sql-ingres-program
381      :sqli-options sql-ingres-options
382      :sqli-login sql-ingres-login-params
383      :sqli-comint-func sql-comint-ingres
384      :prompt-regexp "^\* "
385      :prompt-length 2
386      :prompt-cont-regexp "^\* ")
387
388     (interbase
389      :name "Interbase"
390      :font-lock sql-mode-interbase-font-lock-keywords
391      :sqli-program sql-interbase-program
392      :sqli-options sql-interbase-options
393      :sqli-login sql-interbase-login-params
394      :sqli-comint-func sql-comint-interbase
395      :prompt-regexp "^SQL> "
396      :prompt-length 5)
397
398     (linter
399      :name "Linter"
400      :font-lock sql-mode-linter-font-lock-keywords
401      :sqli-program sql-linter-program
402      :sqli-options sql-linter-options
403      :sqli-login sql-linter-login-params
404      :sqli-comint-func sql-comint-linter
405      :prompt-regexp "^SQL>"
406      :prompt-length 4)
407
408     (ms
409      :name "Microsoft"
410      :font-lock sql-mode-ms-font-lock-keywords
411      :sqli-program sql-ms-program
412      :sqli-options sql-ms-options
413      :sqli-login sql-ms-login-params
414      :sqli-comint-func sql-comint-ms
415      :prompt-regexp "^[0-9]*>"
416      :prompt-length 5
417      :syntax-alist ((?@ . "_"))
418      :terminator ("^go" . "go"))
419
420     (mysql
421      :name "MySQL"
422      :free-software t
423      :font-lock sql-mode-mysql-font-lock-keywords
424      :sqli-program sql-mysql-program
425      :sqli-options sql-mysql-options
426      :sqli-login sql-mysql-login-params
427      :sqli-comint-func sql-comint-mysql
428      :list-all "SHOW TABLES;"
429      :list-table "DESCRIBE %s;"
430      :prompt-regexp "^mysql> "
431      :prompt-length 6
432      :prompt-cont-regexp "^    -> "
433      :syntax-alist ((?# . "< b"))
434      :input-filter sql-remove-tabs-filter)
435
436     (oracle
437      :name "Oracle"
438      :font-lock sql-mode-oracle-font-lock-keywords
439      :sqli-program sql-oracle-program
440      :sqli-options sql-oracle-options
441      :sqli-login sql-oracle-login-params
442      :sqli-comint-func sql-comint-oracle
443      :list-all sql-oracle-list-all
444      :list-table sql-oracle-list-table
445      :completion-object sql-oracle-completion-object
446      :prompt-regexp "^SQL> "
447      :prompt-length 5
448      :prompt-cont-regexp "^\\(?:[ ][ ][1-9]\\|[ ][1-9][0-9]\\|[1-9][0-9]\\{2\\}\\)[ ]\\{2\\}"
449      :statement sql-oracle-statement-starters
450      :syntax-alist ((?$ . "_") (?# . "_"))
451      :terminator ("\\(^/\\|;\\)$" . "/")
452      :input-filter sql-placeholders-filter)
453
454     (postgres
455      :name "Postgres"
456      :free-software t
457      :font-lock sql-mode-postgres-font-lock-keywords
458      :sqli-program sql-postgres-program
459      :sqli-options sql-postgres-options
460      :sqli-login sql-postgres-login-params
461      :sqli-comint-func sql-comint-postgres
462      :list-all ("\\d+" . "\\dS+")
463      :list-table ("\\d+ %s" . "\\dS+ %s")
464      :completion-object sql-postgres-completion-object
465      :prompt-regexp "^\\w*=[#>] "
466      :prompt-length 5
467      :prompt-cont-regexp "^\\w*[-(][#>] "
468      :input-filter sql-remove-tabs-filter
469      :terminator ("\\(^\\s-*\\\\g$\\|;\\)" . "\\g"))
470
471     (solid
472      :name "Solid"
473      :font-lock sql-mode-solid-font-lock-keywords
474      :sqli-program sql-solid-program
475      :sqli-options sql-solid-options
476      :sqli-login sql-solid-login-params
477      :sqli-comint-func sql-comint-solid
478      :prompt-regexp "^"
479      :prompt-length 0)
480
481     (sqlite
482      :name "SQLite"
483      :free-software t
484      :font-lock sql-mode-sqlite-font-lock-keywords
485      :sqli-program sql-sqlite-program
486      :sqli-options sql-sqlite-options
487      :sqli-login sql-sqlite-login-params
488      :sqli-comint-func sql-comint-sqlite
489      :list-all ".tables"
490      :list-table ".schema %s"
491      :completion-object sql-sqlite-completion-object
492      :prompt-regexp "^sqlite> "
493      :prompt-length 8
494      :prompt-cont-regexp "^   \.\.\.> "
495      :terminator ";")
496
497     (sybase
498      :name "Sybase"
499      :font-lock sql-mode-sybase-font-lock-keywords
500      :sqli-program sql-sybase-program
501      :sqli-options sql-sybase-options
502      :sqli-login sql-sybase-login-params
503      :sqli-comint-func sql-comint-sybase
504      :prompt-regexp "^SQL> "
505      :prompt-length 5
506      :syntax-alist ((?@ . "_"))
507      :terminator ("^go" . "go"))
508
509     (vertica
510      :name "Vertica"
511      :sqli-program sql-vertica-program
512      :sqli-options sql-vertica-options
513      :sqli-login sql-vertica-login-params
514      :sqli-comint-func sql-comint-vertica
515      :list-all ("\\d" . "\\dS")
516      :list-table "\\d %s"
517      :prompt-regexp "^\\w*=[#>] "
518      :prompt-length 5
519      :prompt-cont-regexp "^\\w*[-(][#>] ")
520     )
521   "An alist of product specific configuration settings.
522
523 Without an entry in this list a product will not be properly
524 highlighted and will not support `sql-interactive-mode'.
525
526 Each element in the list is in the following format:
527
528  \(PRODUCT FEATURE VALUE ...)
529
530 where PRODUCT is the appropriate value of `sql-product'.  The
531 product name is then followed by FEATURE-VALUE pairs.  If a
532 FEATURE is not specified, its VALUE is treated as nil.  FEATURE
533 may be any one of the following:
534
535  :name                  string containing the displayable name of
536                         the product.
537
538  :free-software         is the product Free (as in Freedom) software?
539
540  :font-lock             name of the variable containing the product
541                         specific font lock highlighting patterns.
542
543  :sqli-program          name of the variable containing the product
544                         specific interactive program name.
545
546  :sqli-options          name of the variable containing the list
547                         of product specific options.
548
549  :sqli-login            name of the variable containing the list of
550                         login parameters (i.e., user, password,
551                         database and server) needed to connect to
552                         the database.
553
554  :sqli-comint-func      name of a function which accepts no
555                         parameters that will use the values of
556                         `sql-user', `sql-password',
557                         `sql-database', `sql-server' and
558                         `sql-port' to open a comint buffer and
559                         connect to the database.  Do product
560                         specific configuration of comint in this
561                         function.
562
563  :list-all              Command string or function which produces
564                         a listing of all objects in the database.
565                         If it's a cons cell, then the car
566                         produces the standard list of objects and
567                         the cdr produces an enhanced list of
568                         objects.  What \"enhanced\" means is
569                         dependent on the SQL product and may not
570                         exist.  In general though, the
571                         \"enhanced\" list should include visible
572                         objects from other schemas.
573
574  :list-table            Command string or function which produces
575                         a detailed listing of a specific database
576                         table.  If its a cons cell, then the car
577                         produces the standard list and the cdr
578                         produces an enhanced list.
579
580  :completion-object     A function that returns a list of
581                         objects.  Called with a single
582                         parameter--if nil then list objects
583                         accessible in the current schema, if
584                         not-nil it is the name of a schema whose
585                         objects should be listed.
586
587  :completion-column     A function that returns a list of
588                         columns.  Called with a single
589                         parameter--if nil then list objects
590                         accessible in the current schema, if
591                         not-nil it is the name of a schema whose
592                         objects should be listed.
593
594  :prompt-regexp         regular expression string that matches
595                         the prompt issued by the product
596                         interpreter.
597
598  :prompt-length         length of the prompt on the line.
599
600  :prompt-cont-regexp    regular expression string that matches
601                         the continuation prompt issued by the
602                         product interpreter.
603
604  :input-filter          function which can filter strings sent to
605                         the command interpreter.  It is also used
606                         by the `sql-send-string',
607                         `sql-send-region', `sql-send-paragraph'
608                         and `sql-send-buffer' functions.  The
609                         function is passed the string sent to the
610                         command interpreter and must return the
611                         filtered string.  May also be a list of
612                         such functions.
613
614  :statement             name of a variable containing a regexp that
615                         matches the beginning of SQL statements.
616
617  :terminator            the terminator to be sent after a
618                         `sql-send-string', `sql-send-region',
619                         `sql-send-paragraph' and
620                         `sql-send-buffer' command.  May be the
621                         literal string or a cons of a regexp to
622                         match an existing terminator in the
623                         string and the terminator to be used if
624                         its absent.  By default \";\".
625
626  :syntax-alist          alist of syntax table entries to enable
627                         special character treatment by font-lock
628                         and imenu.
629
630 Other features can be stored but they will be ignored.  However,
631 you can develop new functionality which is product independent by
632 using `sql-get-product-feature' to lookup the product specific
633 settings.")
634
635 (defvar sql-indirect-features
636   '(:font-lock :sqli-program :sqli-options :sqli-login :statement))
637
638 (defcustom sql-connection-alist nil
639   "An alist of connection parameters for interacting with a SQL product.
640 Each element of the alist is as follows:
641
642   \(CONNECTION \(SQL-VARIABLE VALUE) ...)
643
644 Where CONNECTION is a case-insensitive string identifying the
645 connection, SQL-VARIABLE is the symbol name of a SQL mode
646 variable, and VALUE is the value to be assigned to the variable.
647 The most common SQL-VARIABLE settings associated with a
648 connection are: `sql-product', `sql-user', `sql-password',
649 `sql-port', `sql-server', and `sql-database'.
650
651 If a SQL-VARIABLE is part of the connection, it will not be
652 prompted for during login.  The command `sql-connect' starts a
653 predefined SQLi session using the parameters from this list.
654 Connections defined here appear in the submenu SQL->Start...  for
655 making new SQLi sessions."
656   :type `(alist :key-type (string :tag "Connection")
657                 :value-type
658                 (set
659                  (group (const :tag "Product"  sql-product)
660                         (choice
661                          ,@(mapcar
662                             (lambda (prod-info)
663                               `(const :tag
664                                       ,(or (plist-get (cdr prod-info) :name)
665                                            (capitalize
666                                             (symbol-name (car prod-info))))
667                                       (quote ,(car prod-info))))
668                             sql-product-alist)))
669                  (group (const :tag "Username" sql-user)     string)
670                  (group (const :tag "Password" sql-password) string)
671                  (group (const :tag "Server"   sql-server)   string)
672                  (group (const :tag "Database" sql-database) string)
673                  (group (const :tag "Port"     sql-port)     integer)
674                  (repeat :inline t
675                          (list :tab "Other"
676                                (symbol :tag " Variable Symbol")
677                                (sexp   :tag "Value Expression")))))
678   :version "24.1"
679   :group 'SQL)
680
681 (defcustom sql-product 'ansi
682   "Select the SQL database product used.
683 This allows highlighting buffers properly when you open them."
684   :type `(choice
685           ,@(mapcar (lambda (prod-info)
686                       `(const :tag
687                               ,(or (plist-get (cdr prod-info) :name)
688                                    (capitalize (symbol-name (car prod-info))))
689                               ,(car prod-info)))
690                     sql-product-alist))
691   :group 'SQL
692   :safe 'symbolp)
693 (defvaralias 'sql-dialect 'sql-product)
694
695 ;; misc customization of sql.el behavior
696
697 (defcustom sql-electric-stuff nil
698   "Treat some input as electric.
699 If set to the symbol `semicolon', then hitting `;' will send current
700 input in the SQLi buffer to the process.
701 If set to the symbol `go', then hitting `go' on a line by itself will
702 send current input in the SQLi buffer to the process.
703 If set to nil, then you must use \\[comint-send-input] in order to send
704 current input in the SQLi buffer to the process."
705   :type '(choice (const :tag "Nothing" nil)
706                  (const :tag "The semicolon `;'" semicolon)
707                  (const :tag "The string `go' by itself" go))
708   :version "20.8"
709   :group 'SQL)
710
711 (defcustom sql-send-terminator nil
712   "When non-nil, add a terminator to text sent to the SQL interpreter.
713
714 When text is sent to the SQL interpreter (via `sql-send-string',
715 `sql-send-region', `sql-send-paragraph' or `sql-send-buffer'), a
716 command terminator can be automatically sent as well.  The
717 terminator is not sent, if the string sent already ends with the
718 terminator.
719
720 If this value is t, then the default command terminator for the
721 SQL interpreter is sent.  If this value is a string, then the
722 string is sent.
723
724 If the value is a cons cell of the form (PAT . TERM), then PAT is
725 a regexp used to match the terminator in the string and TERM is
726 the terminator to be sent.  This form is useful if the SQL
727 interpreter has more than one way of submitting a SQL command.
728 The PAT regexp can match any of them, and TERM is the way we do
729 it automatically."
730
731   :type '(choice (const  :tag "No Terminator" nil)
732                  (const  :tag "Default Terminator" t)
733                  (string :tag "Terminator String")
734                  (cons   :tag "Terminator Pattern and String"
735                          (string :tag "Terminator Pattern")
736                          (string :tag "Terminator String")))
737   :version "22.2"
738   :group 'SQL)
739
740 (defvar sql-contains-names nil
741   "When non-nil, the current buffer contains database names.
742
743 Globally should be set to nil; it will be non-nil in `sql-mode',
744 `sql-interactive-mode' and list all buffers.")
745
746 (defvar sql-login-delay 7.5 ;; Secs
747   "Maximum number of seconds you are willing to wait for a login connection.")
748
749 (defcustom sql-pop-to-buffer-after-send-region nil
750   "When non-nil, pop to the buffer SQL statements are sent to.
751
752 After a call to `sql-sent-string', `sql-send-region',
753 `sql-send-paragraph' or `sql-send-buffer', the window is split
754 and the SQLi buffer is shown.  If this variable is not nil, that
755 buffer's window will be selected by calling `pop-to-buffer'.  If
756 this variable is nil, that buffer is shown using
757 `display-buffer'."
758   :type 'boolean
759   :group 'SQL)
760
761 ;; imenu support for sql-mode.
762
763 (defvar sql-imenu-generic-expression
764   ;; Items are in reverse order because they are rendered in reverse.
765   '(("Rules/Defaults" "^\\s-*create\\s-+\\(?:\\w+\\s-+\\)*\\(?:rule\\|default\\)\\(?:if\\s-+not\\s-+exists\\s-+\\)?\\s-+\\(\\(?:\\w+\\s-*[.]\\s-*\\)*\\w+\\)" 1)
766     ("Sequences" "^\\s-*create\\s-+\\(?:\\w+\\s-+\\)*sequence\\s-+\\(?:if\\s-+not\\s-+exists\\s-+\\)?\\(\\(?:\\w+\\s-*[.]\\s-*\\)*\\w+\\)" 1)
767     ("Triggers" "^\\s-*create\\s-+\\(?:\\w+\\s-+\\)*trigger\\s-+\\(?:if\\s-+not\\s-+exists\\s-+\\)?\\(\\(?:\\w+\\s-*[.]\\s-*\\)*\\w+\\)" 1)
768     ("Functions" "^\\s-*\\(?:create\\s-+\\(?:\\w+\\s-+\\)*\\)?function\\s-+\\(?:if\\s-+not\\s-+exists\\s-+\\)?\\(\\(?:\\w+\\s-*[.]\\s-*\\)*\\w+\\)" 1)
769     ("Procedures" "^\\s-*\\(?:create\\s-+\\(?:\\w+\\s-+\\)*\\)?proc\\(?:edure\\)?\\s-+\\(?:if\\s-+not\\s-+exists\\s-+\\)?\\(\\(?:\\w+\\s-*[.]\\s-*\\)*\\w+\\)" 1)
770     ("Packages" "^\\s-*create\\s-+\\(?:\\w+\\s-+\\)*package\\s-+\\(?:body\\s-+\\)?\\(?:if\\s-+not\\s-+exists\\s-+\\)?\\(\\(?:\\w+\\s-*[.]\\s-*\\)*\\w+\\)" 1)
771     ("Types" "^\\s-*create\\s-+\\(?:\\w+\\s-+\\)*type\\s-+\\(?:body\\s-+\\)?\\(?:if\\s-+not\\s-+exists\\s-+\\)?\\(\\(?:\\w+\\s-*[.]\\s-*\\)*\\w+\\)" 1)
772     ("Indexes" "^\\s-*create\\s-+\\(?:\\w+\\s-+\\)*index\\s-+\\(?:if\\s-+not\\s-+exists\\s-+\\)?\\(\\(?:\\w+\\s-*[.]\\s-*\\)*\\w+\\)" 1)
773     ("Tables/Views" "^\\s-*create\\s-+\\(?:\\w+\\s-+\\)*\\(?:table\\|view\\)\\s-+\\(?:if\\s-+not\\s-+exists\\s-+\\)?\\(\\(?:\\w+\\s-*[.]\\s-*\\)*\\w+\\)" 1))
774   "Define interesting points in the SQL buffer for `imenu'.
775
776 This is used to set `imenu-generic-expression' when SQL mode is
777 entered.  Subsequent changes to `sql-imenu-generic-expression' will
778 not affect existing SQL buffers because imenu-generic-expression is
779 a local variable.")
780
781 ;; history file
782
783 (defcustom sql-input-ring-file-name nil
784   "If non-nil, name of the file to read/write input history.
785
786 You have to set this variable if you want the history of your commands
787 saved from one Emacs session to the next.  If this variable is set,
788 exiting the SQL interpreter in an SQLi buffer will write the input
789 history to the specified file.  Starting a new process in a SQLi buffer
790 will read the input history from the specified file.
791
792 This is used to initialize `comint-input-ring-file-name'.
793
794 Note that the size of the input history is determined by the variable
795 `comint-input-ring-size'."
796   :type '(choice (const :tag "none" nil)
797                  (file))
798   :group 'SQL)
799
800 (defcustom sql-input-ring-separator "\n--\n"
801   "Separator between commands in the history file.
802
803 If set to \"\\n\", each line in the history file will be interpreted as
804 one command.  Multi-line commands are split into several commands when
805 the input ring is initialized from a history file.
806
807 This variable used to initialize `comint-input-ring-separator'.
808 `comint-input-ring-separator' is part of Emacs 21; if your Emacs
809 does not have it, setting `sql-input-ring-separator' will have no
810 effect.  In that case multiline commands will be split into several
811 commands when the input history is read, as if you had set
812 `sql-input-ring-separator' to \"\\n\"."
813   :type 'string
814   :group 'SQL)
815
816 ;; The usual hooks
817
818 (defcustom sql-interactive-mode-hook '()
819   "Hook for customizing `sql-interactive-mode'."
820   :type 'hook
821   :group 'SQL)
822
823 (defcustom sql-mode-hook '()
824   "Hook for customizing `sql-mode'."
825   :type 'hook
826   :group 'SQL)
827
828 (defcustom sql-set-sqli-hook '()
829   "Hook for reacting to changes of `sql-buffer'.
830
831 This is called by `sql-set-sqli-buffer' when the value of `sql-buffer'
832 is changed."
833   :type 'hook
834   :group 'SQL)
835
836 (defcustom sql-login-hook '()
837   "Hook for interacting with a buffer in `sql-interactive-mode'.
838
839 This hook is invoked in a buffer once it is ready to accept input
840 for the first time."
841   :version "24.1"
842   :type 'hook
843   :group 'SQL)
844
845 ;; Customization for ANSI
846
847 (defcustom sql-ansi-statement-starters
848   (regexp-opt '("create" "alter" "drop"
849                 "select" "insert" "update" "delete" "merge"
850                 "grant" "revoke"))
851   "Regexp of keywords that start SQL commands.
852
853 All products share this list; products should define a regexp to
854 identify additional keywords in a variable defined by
855 the :statement feature."
856   :version "24.1"
857   :type 'string
858   :group 'SQL)
859
860 ;; Customization for Oracle
861
862 (defcustom sql-oracle-program "sqlplus"
863   "Command to start sqlplus by Oracle.
864
865 Starts `sql-interactive-mode' after doing some setup.
866
867 On Windows, \"sqlplus\" usually starts the sqlplus \"GUI\".  In order
868 to start the sqlplus console, use \"plus33\" or something similar.
869 You will find the file in your Orant\\bin directory."
870   :type 'file
871   :group 'SQL)
872
873 (defcustom sql-oracle-options '("-L")
874   "List of additional options for `sql-oracle-program'."
875   :type '(repeat string)
876   :version "24.4"
877   :group 'SQL)
878
879 (defcustom sql-oracle-login-params '(user password database)
880   "List of login parameters needed to connect to Oracle."
881   :type 'sql-login-params
882   :version "24.1"
883   :group 'SQL)
884
885 (defcustom sql-oracle-statement-starters
886   (regexp-opt '("declare" "begin" "with"))
887   "Additional statement starting keywords in Oracle."
888   :version "24.1"
889   :type 'string
890   :group 'SQL)
891
892 (defcustom sql-oracle-scan-on t
893   "Non-nil if placeholders should be replaced in Oracle SQLi.
894
895 When non-nil, Emacs will scan text sent to sqlplus and prompt
896 for replacement text for & placeholders as sqlplus does.  This
897 is needed on Windows where SQL*Plus output is buffered and the
898 prompts are not shown until after the text is entered.
899
900 You need to issue the following command in SQL*Plus to be safe:
901
902     SET DEFINE OFF
903
904 In older versions of SQL*Plus, this was the SET SCAN OFF command."
905   :version "24.1"
906   :type 'boolean
907   :group 'SQL)
908
909 (defcustom sql-db2-escape-newlines nil
910   "Non-nil if newlines should be escaped by a backslash in DB2 SQLi.
911
912 When non-nil, Emacs will automatically insert a space and
913 backslash prior to every newline in multi-line SQL statements as
914 they are submitted to an interactive DB2 session."
915   :version "24.3"
916   :type 'boolean
917   :group 'SQL)
918
919 ;; Customization for SQLite
920
921 (defcustom sql-sqlite-program (or (executable-find "sqlite3")
922                                   (executable-find "sqlite")
923                                   "sqlite")
924   "Command to start SQLite.
925
926 Starts `sql-interactive-mode' after doing some setup."
927   :type 'file
928   :group 'SQL)
929
930 (defcustom sql-sqlite-options nil
931   "List of additional options for `sql-sqlite-program'."
932   :type '(repeat string)
933   :version "20.8"
934   :group 'SQL)
935
936 (defcustom sql-sqlite-login-params '((database :file ".*\\.\\(db\\|sqlite[23]?\\)"))
937   "List of login parameters needed to connect to SQLite."
938   :type 'sql-login-params
939   :version "24.1"
940   :group 'SQL)
941
942 ;; Customization for MySQL
943
944 (defcustom sql-mysql-program "mysql"
945   "Command to start mysql by TcX.
946
947 Starts `sql-interactive-mode' after doing some setup."
948   :type 'file
949   :group 'SQL)
950
951 (defcustom sql-mysql-options nil
952   "List of additional options for `sql-mysql-program'.
953 The following list of options is reported to make things work
954 on Windows: \"-C\" \"-t\" \"-f\" \"-n\"."
955   :type '(repeat string)
956   :version "20.8"
957   :group 'SQL)
958
959 (defcustom sql-mysql-login-params '(user password database server)
960   "List of login parameters needed to connect to MySQL."
961   :type 'sql-login-params
962   :version "24.1"
963   :group 'SQL)
964
965 ;; Customization for Solid
966
967 (defcustom sql-solid-program "solsql"
968   "Command to start SOLID SQL Editor.
969
970 Starts `sql-interactive-mode' after doing some setup."
971   :type 'file
972   :group 'SQL)
973
974 (defcustom sql-solid-login-params '(user password server)
975   "List of login parameters needed to connect to Solid."
976   :type 'sql-login-params
977   :version "24.1"
978   :group 'SQL)
979
980 ;; Customization for Sybase
981
982 (defcustom sql-sybase-program "isql"
983   "Command to start isql by Sybase.
984
985 Starts `sql-interactive-mode' after doing some setup."
986   :type 'file
987   :group 'SQL)
988
989 (defcustom sql-sybase-options nil
990   "List of additional options for `sql-sybase-program'.
991 Some versions of isql might require the -n option in order to work."
992   :type '(repeat string)
993   :version "20.8"
994   :group 'SQL)
995
996 (defcustom sql-sybase-login-params '(server user password database)
997   "List of login parameters needed to connect to Sybase."
998   :type 'sql-login-params
999   :version "24.1"
1000   :group 'SQL)
1001
1002 ;; Customization for Informix
1003
1004 (defcustom sql-informix-program "dbaccess"
1005   "Command to start dbaccess by Informix.
1006
1007 Starts `sql-interactive-mode' after doing some setup."
1008   :type 'file
1009   :group 'SQL)
1010
1011 (defcustom sql-informix-login-params '(database)
1012   "List of login parameters needed to connect to Informix."
1013   :type 'sql-login-params
1014   :version "24.1"
1015   :group 'SQL)
1016
1017 ;; Customization for Ingres
1018
1019 (defcustom sql-ingres-program "sql"
1020   "Command to start sql by Ingres.
1021
1022 Starts `sql-interactive-mode' after doing some setup."
1023   :type 'file
1024   :group 'SQL)
1025
1026 (defcustom sql-ingres-login-params '(database)
1027   "List of login parameters needed to connect to Ingres."
1028   :type 'sql-login-params
1029   :version "24.1"
1030   :group 'SQL)
1031
1032 ;; Customization for Microsoft
1033
1034 (defcustom sql-ms-program "osql"
1035   "Command to start osql by Microsoft.
1036
1037 Starts `sql-interactive-mode' after doing some setup."
1038   :type 'file
1039   :group 'SQL)
1040
1041 (defcustom sql-ms-options '("-w" "300" "-n")
1042   ;; -w is the linesize
1043   "List of additional options for `sql-ms-program'."
1044   :type '(repeat string)
1045   :version "22.1"
1046   :group 'SQL)
1047
1048 (defcustom sql-ms-login-params '(user password server database)
1049   "List of login parameters needed to connect to Microsoft."
1050   :type 'sql-login-params
1051   :version "24.1"
1052   :group 'SQL)
1053
1054 ;; Customization for Postgres
1055
1056 (defcustom sql-postgres-program "psql"
1057   "Command to start psql by Postgres.
1058
1059 Starts `sql-interactive-mode' after doing some setup."
1060   :type 'file
1061   :group 'SQL)
1062
1063 (defcustom sql-postgres-options '("-P" "pager=off")
1064   "List of additional options for `sql-postgres-program'.
1065 The default setting includes the -P option which breaks older versions
1066 of the psql client (such as version 6.5.3).  The -P option is equivalent
1067 to the --pset option.  If you want the psql to prompt you for a user
1068 name, add the string \"-u\" to the list of options.  If you want to
1069 provide a user name on the command line (newer versions such as 7.1),
1070 add your name with a \"-U\" prefix (such as \"-Umark\") to the list."
1071   :type '(repeat string)
1072   :version "20.8"
1073   :group 'SQL)
1074
1075 (defcustom sql-postgres-login-params `((user :default ,(user-login-name))
1076                                        (database :default ,(user-login-name))
1077                                        server)
1078   "List of login parameters needed to connect to Postgres."
1079   :type 'sql-login-params
1080   :version "24.1"
1081   :group 'SQL)
1082
1083 ;; Customization for Interbase
1084
1085 (defcustom sql-interbase-program "isql"
1086   "Command to start isql by Interbase.
1087
1088 Starts `sql-interactive-mode' after doing some setup."
1089   :type 'file
1090   :group 'SQL)
1091
1092 (defcustom sql-interbase-options nil
1093   "List of additional options for `sql-interbase-program'."
1094   :type '(repeat string)
1095   :version "20.8"
1096   :group 'SQL)
1097
1098 (defcustom sql-interbase-login-params '(user password database)
1099   "List of login parameters needed to connect to Interbase."
1100   :type 'sql-login-params
1101   :version "24.1"
1102   :group 'SQL)
1103
1104 ;; Customization for DB2
1105
1106 (defcustom sql-db2-program "db2"
1107   "Command to start db2 by IBM.
1108
1109 Starts `sql-interactive-mode' after doing some setup."
1110   :type 'file
1111   :group 'SQL)
1112
1113 (defcustom sql-db2-options nil
1114   "List of additional options for `sql-db2-program'."
1115   :type '(repeat string)
1116   :version "20.8"
1117   :group 'SQL)
1118
1119 (defcustom sql-db2-login-params nil
1120   "List of login parameters needed to connect to DB2."
1121   :type 'sql-login-params
1122   :version "24.1"
1123   :group 'SQL)
1124
1125 ;; Customization for Linter
1126
1127 (defcustom sql-linter-program "inl"
1128   "Command to start inl by RELEX.
1129
1130 Starts `sql-interactive-mode' after doing some setup."
1131   :type 'file
1132   :group 'SQL)
1133
1134 (defcustom sql-linter-options nil
1135   "List of additional options for `sql-linter-program'."
1136   :type '(repeat string)
1137   :version "21.3"
1138   :group 'SQL)
1139
1140 (defcustom sql-linter-login-params '(user password database server)
1141   "Login parameters to needed to connect to Linter."
1142   :type 'sql-login-params
1143   :version "24.1"
1144   :group 'SQL)
1145
1146 \f
1147
1148 ;;; Variables which do not need customization
1149
1150 (defvar sql-user-history nil
1151   "History of usernames used.")
1152
1153 (defvar sql-database-history nil
1154   "History of databases used.")
1155
1156 (defvar sql-server-history nil
1157   "History of servers used.")
1158
1159 ;; Passwords are not kept in a history.
1160
1161 (defvar sql-product-history nil
1162   "History of products used.")
1163
1164 (defvar sql-connection-history nil
1165   "History of connections used.")
1166
1167 (defvar sql-buffer nil
1168   "Current SQLi buffer.
1169
1170 The global value of `sql-buffer' is the name of the latest SQLi buffer
1171 created.  Any SQL buffer created will make a local copy of this value.
1172 See `sql-interactive-mode' for more on multiple sessions.  If you want
1173 to change the SQLi buffer a SQL mode sends its SQL strings to, change
1174 the local value of `sql-buffer' using \\[sql-set-sqli-buffer].")
1175
1176 (defvar sql-prompt-regexp nil
1177   "Prompt used to initialize `comint-prompt-regexp'.
1178
1179 You can change `sql-prompt-regexp' on `sql-interactive-mode-hook'.")
1180
1181 (defvar sql-prompt-length 0
1182   "Prompt used to set `left-margin' in `sql-interactive-mode'.
1183
1184 You can change `sql-prompt-length' on `sql-interactive-mode-hook'.")
1185
1186 (defvar sql-prompt-cont-regexp nil
1187   "Prompt pattern of statement continuation prompts.")
1188
1189 (defvar sql-alternate-buffer-name nil
1190   "Buffer-local string used to possibly rename the SQLi buffer.
1191
1192 Used by `sql-rename-buffer'.")
1193
1194 (defun sql-buffer-live-p (buffer &optional product connection)
1195   "Return non-nil if the process associated with buffer is live.
1196
1197 BUFFER can be a buffer object or a buffer name.  The buffer must
1198 be a live buffer, have a running process attached to it, be in
1199 `sql-interactive-mode', and, if PRODUCT or CONNECTION are
1200 specified, it's `sql-product' or `sql-connection' must match."
1201
1202   (when buffer
1203     (setq buffer (get-buffer buffer))
1204     (and buffer
1205          (buffer-live-p buffer)
1206          (comint-check-proc buffer)
1207          (with-current-buffer buffer
1208            (and (derived-mode-p 'sql-interactive-mode)
1209                 (or (not product)
1210                     (eq product sql-product))
1211                 (or (not connection)
1212                     (eq connection sql-connection)))))))
1213
1214 ;; Keymap for sql-interactive-mode.
1215
1216 (defvar sql-interactive-mode-map
1217   (let ((map (make-sparse-keymap)))
1218     (if (fboundp 'set-keymap-parent)
1219         (set-keymap-parent map comint-mode-map); Emacs
1220       (if (fboundp 'set-keymap-parents)
1221           (set-keymap-parents map (list comint-mode-map)))); XEmacs
1222     (if (fboundp 'set-keymap-name)
1223         (set-keymap-name map 'sql-interactive-mode-map)); XEmacs
1224     (define-key map (kbd "C-j") 'sql-accumulate-and-indent)
1225     (define-key map (kbd "C-c C-w") 'sql-copy-column)
1226     (define-key map (kbd "O") 'sql-magic-go)
1227     (define-key map (kbd "o") 'sql-magic-go)
1228     (define-key map (kbd ";") 'sql-magic-semicolon)
1229     (define-key map (kbd "C-c C-l a") 'sql-list-all)
1230     (define-key map (kbd "C-c C-l t") 'sql-list-table)
1231     map)
1232   "Mode map used for `sql-interactive-mode'.
1233 Based on `comint-mode-map'.")
1234
1235 ;; Keymap for sql-mode.
1236
1237 (defvar sql-mode-map
1238   (let ((map (make-sparse-keymap)))
1239     (define-key map (kbd "C-c C-c") 'sql-send-paragraph)
1240     (define-key map (kbd "C-c C-r") 'sql-send-region)
1241     (define-key map (kbd "C-c C-s") 'sql-send-string)
1242     (define-key map (kbd "C-c C-b") 'sql-send-buffer)
1243     (define-key map (kbd "C-c C-n") 'sql-send-line-and-next)
1244     (define-key map (kbd "C-c C-i") 'sql-product-interactive)
1245     (define-key map (kbd "C-c C-z") 'sql-show-sqli-buffer)
1246     (define-key map (kbd "C-c C-l a") 'sql-list-all)
1247     (define-key map (kbd "C-c C-l t") 'sql-list-table)
1248     (define-key map [remap beginning-of-defun] 'sql-beginning-of-statement)
1249     (define-key map [remap end-of-defun] 'sql-end-of-statement)
1250     map)
1251   "Mode map used for `sql-mode'.")
1252
1253 ;; easy menu for sql-mode.
1254
1255 (easy-menu-define
1256  sql-mode-menu sql-mode-map
1257  "Menu for `sql-mode'."
1258  `("SQL"
1259    ["Send Paragraph" sql-send-paragraph (sql-buffer-live-p sql-buffer)]
1260    ["Send Region" sql-send-region (and mark-active
1261                                        (sql-buffer-live-p sql-buffer))]
1262    ["Send Buffer" sql-send-buffer (sql-buffer-live-p sql-buffer)]
1263    ["Send String" sql-send-string (sql-buffer-live-p sql-buffer)]
1264    "--"
1265    ["List all objects" sql-list-all (and (sql-buffer-live-p sql-buffer)
1266                                          (sql-get-product-feature sql-product :list-all))]
1267    ["List table details" sql-list-table (and (sql-buffer-live-p sql-buffer)
1268                                              (sql-get-product-feature sql-product :list-table))]
1269    "--"
1270    ["Start SQLi session" sql-product-interactive
1271     :visible (not sql-connection-alist)
1272     :enable (sql-get-product-feature sql-product :sqli-comint-func)]
1273    ("Start..."
1274     :visible sql-connection-alist
1275     :filter sql-connection-menu-filter
1276     "--"
1277     ["New SQLi Session" sql-product-interactive (sql-get-product-feature sql-product :sqli-comint-func)])
1278    ["--"
1279     :visible sql-connection-alist]
1280    ["Show SQLi buffer" sql-show-sqli-buffer t]
1281    ["Set SQLi buffer" sql-set-sqli-buffer t]
1282    ["Pop to SQLi buffer after send"
1283     sql-toggle-pop-to-buffer-after-send-region
1284     :style toggle
1285     :selected sql-pop-to-buffer-after-send-region]
1286    ["--" nil nil]
1287    ("Product"
1288     ,@(mapcar (lambda (prod-info)
1289                 (let* ((prod (pop prod-info))
1290                        (name (or (plist-get prod-info :name)
1291                                  (capitalize (symbol-name prod))))
1292                        (cmd (intern (format "sql-highlight-%s-keywords" prod))))
1293                   (fset cmd `(lambda () ,(format "Highlight %s SQL keywords." name)
1294                                (interactive)
1295                                (sql-set-product ',prod)))
1296                   (vector name cmd
1297                           :style 'radio
1298                           :selected `(eq sql-product ',prod))))
1299               sql-product-alist))))
1300
1301 ;; easy menu for sql-interactive-mode.
1302
1303 (easy-menu-define
1304  sql-interactive-mode-menu sql-interactive-mode-map
1305  "Menu for `sql-interactive-mode'."
1306  '("SQL"
1307    ["Rename Buffer" sql-rename-buffer t]
1308    ["Save Connection" sql-save-connection (not sql-connection)]
1309    "--"
1310    ["List all objects" sql-list-all (sql-get-product-feature sql-product :list-all)]
1311    ["List table details" sql-list-table (sql-get-product-feature sql-product :list-table)]))
1312
1313 ;; Abbreviations -- if you want more of them, define them in your init
1314 ;; file.  Abbrevs have to be enabled in your init file, too.
1315
1316 (define-abbrev-table 'sql-mode-abbrev-table
1317   '(("ins" "insert" nil nil t)
1318     ("upd" "update" nil nil t)
1319     ("del" "delete" nil nil t)
1320     ("sel" "select" nil nil t)
1321     ("proc" "procedure" nil nil t)
1322     ("func" "function" nil nil t)
1323     ("cr" "create" nil nil t))
1324   "Abbrev table used in `sql-mode' and `sql-interactive-mode'.")
1325
1326 ;; Syntax Table
1327
1328 (defvar sql-mode-syntax-table
1329   (let ((table (make-syntax-table)))
1330     ;; C-style comments /**/ (see elisp manual "Syntax Flags"))
1331     (modify-syntax-entry ?/ ". 14" table)
1332     (modify-syntax-entry ?* ". 23" table)
1333     ;; double-dash starts comments
1334     (modify-syntax-entry ?- ". 12b" table)
1335     ;; newline and formfeed end comments
1336     (modify-syntax-entry ?\n "> b" table)
1337     (modify-syntax-entry ?\f "> b" table)
1338     ;; single quotes (') delimit strings
1339     (modify-syntax-entry ?' "\"" table)
1340     ;; double quotes (") don't delimit strings
1341     (modify-syntax-entry ?\" "." table)
1342     ;; Make these all punctuation
1343     (mapc #'(lambda (c) (modify-syntax-entry c "." table))
1344           (string-to-list "!#$%&+,.:;<=>?@\\|"))
1345     table)
1346   "Syntax table used in `sql-mode' and `sql-interactive-mode'.")
1347
1348 ;; Font lock support
1349
1350 (defvar sql-mode-font-lock-object-name
1351   (eval-when-compile
1352     (list (concat "^\\s-*\\(?:create\\|drop\\|alter\\)\\s-+" ;; lead off with CREATE, DROP or ALTER
1353                   "\\(?:\\w+\\s-+\\)*"  ;; optional intervening keywords
1354                   "\\(?:table\\|view\\|\\(?:package\\|type\\)\\(?:\\s-+body\\)?\\|proc\\(?:edure\\)?"
1355                   "\\|function\\|trigger\\|sequence\\|rule\\|default\\)\\s-+"
1356                   "\\(?:if\\s-+not\\s-+exists\\s-+\\)?" ;; IF NOT EXISTS
1357                   "\\(\\w+\\(?:\\s-*[.]\\s-*\\w+\\)*\\)")
1358           1 'font-lock-function-name-face))
1359
1360   "Pattern to match the names of top-level objects.
1361
1362 The pattern matches the name in a CREATE, DROP or ALTER
1363 statement.  The format of variable should be a valid
1364 `font-lock-keywords' entry.")
1365
1366 ;; While there are international and American standards for SQL, they
1367 ;; are not followed closely, and most vendors offer significant
1368 ;; capabilities beyond those defined in the standard specifications.
1369
1370 ;; SQL mode provides support for highlighting based on the product.  In
1371 ;; addition to highlighting the product keywords, any ANSI keywords not
1372 ;; used by the product are also highlighted.  This will help identify
1373 ;; keywords that could be restricted in future versions of the product
1374 ;; or might be a problem if ported to another product.
1375
1376 ;; To reduce the complexity and size of the regular expressions
1377 ;; generated to match keywords, ANSI keywords are filtered out of
1378 ;; product keywords if they are equivalent.  To do this, we define a
1379 ;; function `sql-font-lock-keywords-builder' that removes any keywords
1380 ;; that are matched by the ANSI patterns and results in the same face
1381 ;; being applied.  For this to work properly, we must play some games
1382 ;; with the execution and compile time behavior.  This code is a
1383 ;; little tricky but works properly.
1384
1385 ;; When defining the keywords for individual products you should
1386 ;; include all of the keywords that you want matched.  The filtering
1387 ;; against the ANSI keywords will be automatic if you use the
1388 ;; `sql-font-lock-keywords-builder' function and follow the
1389 ;; implementation pattern used for the other products in this file.
1390
1391 (eval-when-compile
1392   (defvar sql-mode-ansi-font-lock-keywords)
1393   (setq sql-mode-ansi-font-lock-keywords nil))
1394
1395 (eval-and-compile
1396   (defun sql-font-lock-keywords-builder (face boundaries &rest keywords)
1397     "Generation of regexp matching any one of KEYWORDS."
1398
1399     (let ((bdy (or boundaries '("\\b" . "\\b")))
1400           kwd)
1401
1402       ;; Remove keywords that are defined in ANSI
1403       (setq kwd keywords)
1404       ;; (dolist (k keywords)
1405       ;;   (catch 'next
1406       ;;     (dolist (a sql-mode-ansi-font-lock-keywords)
1407       ;;       (when (and (eq face (cdr a))
1408       ;;               (eq (string-match (car a) k 0) 0)
1409       ;;               (eq (match-end 0) (length k)))
1410       ;;         (setq kwd (delq k kwd))
1411       ;;         (throw 'next nil)))))
1412
1413       ;; Create a properly formed font-lock-keywords item
1414       (cons (concat (car bdy)
1415                     (regexp-opt kwd t)
1416                     (cdr bdy))
1417             face)))
1418
1419   (defun sql-regexp-abbrev (keyword)
1420     (let ((brk   (string-match "[~]" keyword))
1421           (len   (length keyword))
1422           (sep   "\\(?:")
1423           re i)
1424       (if (not brk)
1425           keyword
1426         (setq re  (substring keyword 0 brk)
1427               i   (+ 2 brk)
1428               brk (1+ brk))
1429         (while (<= i len)
1430           (setq re  (concat re sep (substring keyword brk i))
1431                 sep "\\|"
1432                 i   (1+ i)))
1433         (concat re "\\)?"))))
1434
1435   (defun sql-regexp-abbrev-list (&rest keyw-list)
1436     (let ((re nil)
1437           (sep "\\<\\(?:"))
1438       (while keyw-list
1439         (setq re (concat re sep (sql-regexp-abbrev (car keyw-list)))
1440               sep "\\|"
1441               keyw-list (cdr keyw-list)))
1442       (concat re "\\)\\>"))))
1443
1444 (eval-when-compile
1445   (setq sql-mode-ansi-font-lock-keywords
1446         (list
1447          ;; ANSI Non Reserved keywords
1448          (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
1449 "ada" "asensitive" "assignment" "asymmetric" "atomic" "between"
1450 "bitvar" "called" "catalog_name" "chain" "character_set_catalog"
1451 "character_set_name" "character_set_schema" "checked" "class_origin"
1452 "cobol" "collation_catalog" "collation_name" "collation_schema"
1453 "column_name" "command_function" "command_function_code" "committed"
1454 "condition_number" "connection_name" "constraint_catalog"
1455 "constraint_name" "constraint_schema" "contains" "cursor_name"
1456 "datetime_interval_code" "datetime_interval_precision" "defined"
1457 "definer" "dispatch" "dynamic_function" "dynamic_function_code"
1458 "existing" "exists" "final" "fortran" "generated" "granted"
1459 "hierarchy" "hold" "implementation" "infix" "insensitive" "instance"
1460 "instantiable" "invoker" "key_member" "key_type" "length" "m"
1461 "message_length" "message_octet_length" "message_text" "method" "more"
1462 "mumps" "name" "nullable" "number" "options" "overlaps" "overriding"
1463 "parameter_mode" "parameter_name" "parameter_ordinal_position"
1464 "parameter_specific_catalog" "parameter_specific_name"
1465 "parameter_specific_schema" "pascal" "pli" "position" "repeatable"
1466 "returned_length" "returned_octet_length" "returned_sqlstate"
1467 "routine_catalog" "routine_name" "routine_schema" "row_count" "scale"
1468 "schema_name" "security" "self" "sensitive" "serializable"
1469 "server_name" "similar" "simple" "source" "specific_name" "style"
1470 "subclass_origin" "sublist" "symmetric" "system" "table_name"
1471 "transaction_active" "transactions_committed"
1472 "transactions_rolled_back" "transform" "transforms" "trigger_catalog"
1473 "trigger_name" "trigger_schema" "type" "uncommitted" "unnamed"
1474 "user_defined_type_catalog" "user_defined_type_name"
1475 "user_defined_type_schema"
1476 )
1477
1478          ;; ANSI Reserved keywords
1479          (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
1480 "absolute" "action" "add" "admin" "after" "aggregate" "alias" "all"
1481 "allocate" "alter" "and" "any" "are" "as" "asc" "assertion" "at"
1482 "authorization" "before" "begin" "both" "breadth" "by" "call"
1483 "cascade" "cascaded" "case" "catalog" "check" "class" "close"
1484 "collate" "collation" "column" "commit" "completion" "connect"
1485 "connection" "constraint" "constraints" "constructor" "continue"
1486 "corresponding" "create" "cross" "cube" "current" "cursor" "cycle"
1487 "data" "day" "deallocate" "declare" "default" "deferrable" "deferred"
1488 "delete" "depth" "deref" "desc" "describe" "descriptor" "destroy"
1489 "destructor" "deterministic" "diagnostics" "dictionary" "disconnect"
1490 "distinct" "domain" "drop" "dynamic" "each" "else" "end" "equals"
1491 "escape" "every" "except" "exception" "exec" "execute" "external"
1492 "false" "fetch" "first" "for" "foreign" "found" "free" "from" "full"
1493 "function" "general" "get" "global" "go" "goto" "grant" "group"
1494 "grouping" "having" "host" "hour" "identity" "ignore" "immediate" "in"
1495 "indicator" "initialize" "initially" "inner" "inout" "input" "insert"
1496 "intersect" "into" "is" "isolation" "iterate" "join" "key" "language"
1497 "last" "lateral" "leading" "left" "less" "level" "like" "limit"
1498 "local" "locator" "map" "match" "minute" "modifies" "modify" "module"
1499 "month" "names" "natural" "new" "next" "no" "none" "not" "null" "of"
1500 "off" "old" "on" "only" "open" "operation" "option" "or" "order"
1501 "ordinality" "out" "outer" "output" "pad" "parameter" "parameters"
1502 "partial" "path" "postfix" "prefix" "preorder" "prepare" "preserve"
1503 "primary" "prior" "privileges" "procedure" "public" "read" "reads"
1504 "recursive" "references" "referencing" "relative" "restrict" "result"
1505 "return" "returns" "revoke" "right" "role" "rollback" "rollup"
1506 "routine" "rows" "savepoint" "schema" "scroll" "search" "second"
1507 "section" "select" "sequence" "session" "set" "sets" "size" "some"
1508 "space" "specific" "specifictype" "sql" "sqlexception" "sqlstate"
1509 "sqlwarning" "start" "state" "statement" "static" "structure" "table"
1510 "temporary" "terminate" "than" "then" "timezone_hour"
1511 "timezone_minute" "to" "trailing" "transaction" "translation"
1512 "trigger" "true" "under" "union" "unique" "unknown" "unnest" "update"
1513 "usage" "using" "value" "values" "variable" "view" "when" "whenever"
1514 "where" "with" "without" "work" "write" "year"
1515 )
1516
1517          ;; ANSI Functions
1518          (sql-font-lock-keywords-builder 'font-lock-builtin-face nil
1519 "abs" "avg" "bit_length" "cardinality" "cast" "char_length"
1520 "character_length" "coalesce" "convert" "count" "current_date"
1521 "current_path" "current_role" "current_time" "current_timestamp"
1522 "current_user" "extract" "localtime" "localtimestamp" "lower" "max"
1523 "min" "mod" "nullif" "octet_length" "overlay" "placing" "session_user"
1524 "substring" "sum" "system_user" "translate" "treat" "trim" "upper"
1525 "user"
1526 )
1527
1528          ;; ANSI Data Types
1529          (sql-font-lock-keywords-builder 'font-lock-type-face nil
1530 "array" "binary" "bit" "blob" "boolean" "char" "character" "clob"
1531 "date" "dec" "decimal" "double" "float" "int" "integer" "interval"
1532 "large" "national" "nchar" "nclob" "numeric" "object" "precision"
1533 "real" "ref" "row" "scope" "smallint" "time" "timestamp" "varchar"
1534 "varying" "zone"
1535 ))))
1536
1537 (defvar sql-mode-ansi-font-lock-keywords
1538   (eval-when-compile sql-mode-ansi-font-lock-keywords)
1539   "ANSI SQL keywords used by font-lock.
1540
1541 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
1542 regular expressions are created during compilation by calling the
1543 function `regexp-opt'.  Therefore, take a look at the source before
1544 you define your own `sql-mode-ansi-font-lock-keywords'.  You may want
1545 to add functions and PL/SQL keywords.")
1546
1547 (defun sql--oracle-show-reserved-words ()
1548   ;; This function is for use by the maintainer of SQL.EL only.
1549   (if (or (and (not (derived-mode-p 'sql-mode))
1550                (not (derived-mode-p 'sql-interactive-mode)))
1551           (not sql-buffer)
1552           (not (eq sql-product 'oracle)))
1553       (user-error "Not an Oracle buffer")
1554
1555     (let ((b "*RESERVED WORDS*"))
1556       (sql-execute sql-buffer b
1557                    (concat "SELECT "
1558                            "  keyword "
1559                            ", reserved AS \"Res\" "
1560                            ", res_type AS \"Type\" "
1561                            ", res_attr AS \"Attr\" "
1562                            ", res_semi AS \"Semi\" "
1563                            ", duplicate AS \"Dup\" "
1564                            "FROM V$RESERVED_WORDS "
1565                            "WHERE length > 1 "
1566                            "AND SUBSTR(keyword, 1, 1) BETWEEN 'A' AND 'Z' "
1567                            "ORDER BY 2 DESC, 3 DESC, 4 DESC, 5 DESC, 6 DESC, 1;")
1568                    nil nil)
1569       (with-current-buffer b
1570         (set (make-local-variable 'sql-product) 'oracle)
1571         (sql-product-font-lock t nil)
1572         (font-lock-mode +1)))))
1573
1574 (defvar sql-mode-oracle-font-lock-keywords
1575   (eval-when-compile
1576     (list
1577      ;; Oracle SQL*Plus Commands
1578      ;;   Only recognized in they start in column 1 and the
1579      ;;   abbreviation is followed by a space or the end of line.
1580
1581      "\\|"
1582      (list (concat "^" (sql-regexp-abbrev "rem~ark") "\\(?:\\s-.*\\)?$")
1583            0 'font-lock-comment-face t)
1584
1585      (list
1586       (concat
1587        "^\\(?:"
1588        (sql-regexp-abbrev-list
1589         "[@]\\{1,2\\}" "acc~ept" "a~ppend" "archive" "attribute"
1590         "bre~ak" "bti~tle" "c~hange" "cl~ear" "col~umn" "conn~ect"
1591         "copy" "def~ine" "del" "desc~ribe" "disc~onnect" "ed~it"
1592         "exec~ute" "exit" "get" "help" "ho~st" "[$]" "i~nput" "l~ist"
1593         "passw~ord" "pau~se" "pri~nt" "pro~mpt" "quit" "recover"
1594         "repf~ooter" "reph~eader" "r~un" "sav~e" "sho~w" "shutdown"
1595         "spo~ol" "sta~rt" "startup" "store" "tim~ing" "tti~tle"
1596         "undef~ine" "var~iable" "whenever")
1597        "\\|"
1598        (concat "\\(?:"
1599                (sql-regexp-abbrev "comp~ute")
1600                "\\s-+"
1601                (sql-regexp-abbrev-list
1602                 "avg" "cou~nt" "min~imum" "max~imum" "num~ber" "sum"
1603                 "std" "var~iance")
1604                "\\)")
1605        "\\|"
1606        (concat "\\(?:set\\s-+"
1607                (sql-regexp-abbrev-list
1608                 "appi~nfo" "array~size" "auto~commit" "autop~rint"
1609                 "autorecovery" "autot~race" "blo~ckterminator"
1610                 "cmds~ep" "colsep" "com~patibility" "con~cat"
1611                 "copyc~ommit" "copytypecheck" "def~ine" "describe"
1612                 "echo" "editf~ile" "emb~edded" "esc~ape" "feed~back"
1613                 "flagger" "flu~sh" "hea~ding" "heads~ep" "instance"
1614                 "lin~esize" "lobof~fset" "long" "longc~hunksize"
1615                 "mark~up" "newp~age" "null" "numf~ormat" "num~width"
1616                 "pages~ize" "pau~se" "recsep" "recsepchar"
1617                 "scan" "serverout~put" "shift~inout" "show~mode"
1618                 "sqlbl~anklines" "sqlc~ase" "sqlco~ntinue"
1619                 "sqln~umber" "sqlpluscompat~ibility" "sqlpre~fix"
1620                 "sqlp~rompt" "sqlt~erminator" "suf~fix" "tab"
1621                 "term~out" "ti~me" "timi~ng" "trim~out" "trims~pool"
1622                 "und~erline" "ver~ify" "wra~p")
1623                "\\)")
1624
1625        "\\)\\(?:\\s-.*\\)?\\(?:[-]\n.*\\)*$")
1626       0 'font-lock-doc-face t)
1627      '("&?&\\(?:\\sw\\|\\s_\\)+[.]?" 0 font-lock-preprocessor-face t)
1628
1629      ;; Oracle Functions
1630      (sql-font-lock-keywords-builder 'font-lock-builtin-face nil
1631 "abs" "acos" "add_months" "appendchildxml" "ascii" "asciistr" "asin"
1632 "atan" "atan2" "avg" "bfilename" "bin_to_num" "bitand" "cardinality"
1633 "cast" "ceil" "chartorowid" "chr" "cluster_id" "cluster_probability"
1634 "cluster_set" "coalesce" "collect" "compose" "concat" "convert" "corr"
1635 "connect_by_root" "connect_by_iscycle" "connect_by_isleaf"
1636 "corr_k" "corr_s" "cos" "cosh" "count" "covar_pop" "covar_samp"
1637 "cube_table" "cume_dist" "current_date" "current_timestamp" "cv"
1638 "dataobj_to_partition" "dbtimezone" "decode" "decompose" "deletexml"
1639 "dense_rank" "depth" "deref" "dump" "empty_blob" "empty_clob"
1640 "existsnode" "exp" "extract" "extractvalue" "feature_id" "feature_set"
1641 "feature_value" "first" "first_value" "floor" "from_tz" "greatest"
1642 "grouping" "grouping_id" "group_id" "hextoraw" "initcap"
1643 "insertchildxml" "insertchildxmlafter" "insertchildxmlbefore"
1644 "insertxmlafter" "insertxmlbefore" "instr" "instr2" "instr4" "instrb"
1645 "instrc" "iteration_number" "lag" "last" "last_day" "last_value"
1646 "lead" "least" "length" "length2" "length4" "lengthb" "lengthc"
1647 "listagg" "ln" "lnnvl" "localtimestamp" "log" "lower" "lpad" "ltrim"
1648 "make_ref" "max" "median" "min" "mod" "months_between" "nanvl" "nchr"
1649 "new_time" "next_day" "nlssort" "nls_charset_decl_len"
1650 "nls_charset_id" "nls_charset_name" "nls_initcap" "nls_lower"
1651 "nls_upper" "nth_value" "ntile" "nullif" "numtodsinterval"
1652 "numtoyminterval" "nvl" "nvl2" "ora_dst_affected" "ora_dst_convert"
1653 "ora_dst_error" "ora_hash" "path" "percentile_cont" "percentile_disc"
1654 "percent_rank" "power" "powermultiset" "powermultiset_by_cardinality"
1655 "prediction" "prediction_bounds" "prediction_cost"
1656 "prediction_details" "prediction_probability" "prediction_set"
1657 "presentnnv" "presentv" "previous" "rank" "ratio_to_report" "rawtohex"
1658 "rawtonhex" "ref" "reftohex" "regexp_count" "regexp_instr"
1659 "regexp_replace" "regexp_substr" "regr_avgx" "regr_avgy" "regr_count"
1660 "regr_intercept" "regr_r2" "regr_slope" "regr_sxx" "regr_sxy"
1661 "regr_syy" "remainder" "replace" "round" "rowidtochar" "rowidtonchar"
1662 "row_number" "rpad" "rtrim" "scn_to_timestamp" "sessiontimezone" "set"
1663 "sign" "sin" "sinh" "soundex" "sqrt" "stats_binomial_test"
1664 "stats_crosstab" "stats_f_test" "stats_ks_test" "stats_mode"
1665 "stats_mw_test" "stats_one_way_anova" "stats_t_test_indep"
1666 "stats_t_test_indepu" "stats_t_test_one" "stats_t_test_paired"
1667 "stats_wsr_test" "stddev" "stddev_pop" "stddev_samp" "substr"
1668 "substr2" "substr4" "substrb" "substrc" "sum" "sysdate" "systimestamp"
1669 "sys_connect_by_path" "sys_context" "sys_dburigen" "sys_extract_utc"
1670 "sys_guid" "sys_typeid" "sys_xmlagg" "sys_xmlgen" "tan" "tanh"
1671 "timestamp_to_scn" "to_binary_double" "to_binary_float" "to_blob"
1672 "to_char" "to_clob" "to_date" "to_dsinterval" "to_lob" "to_multi_byte"
1673 "to_nchar" "to_nclob" "to_number" "to_single_byte" "to_timestamp"
1674 "to_timestamp_tz" "to_yminterval" "translate" "treat" "trim" "trunc"
1675 "tz_offset" "uid" "unistr" "updatexml" "upper" "user" "userenv"
1676 "value" "variance" "var_pop" "var_samp" "vsize" "width_bucket"
1677 "xmlagg" "xmlcast" "xmlcdata" "xmlcolattval" "xmlcomment" "xmlconcat"
1678 "xmldiff" "xmlelement" "xmlexists" "xmlforest" "xmlisvalid" "xmlparse"
1679 "xmlpatch" "xmlpi" "xmlquery" "xmlroot" "xmlsequence" "xmlserialize"
1680 "xmltable" "xmltransform"
1681 )
1682
1683      ;; See the table V$RESERVED_WORDS
1684      ;; Oracle Keywords
1685      (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
1686 "abort" "access" "accessed" "account" "activate" "add" "admin"
1687 "advise" "after" "agent" "aggregate" "all" "allocate" "allow" "alter"
1688 "always" "analyze" "ancillary" "and" "any" "apply" "archive"
1689 "archivelog" "array" "as" "asc" "associate" "at" "attribute"
1690 "attributes" "audit" "authenticated" "authid" "authorization" "auto"
1691 "autoallocate" "automatic" "availability" "backup" "before" "begin"
1692 "behalf" "between" "binding" "bitmap" "block" "blocksize" "body"
1693 "both" "buffer_pool" "build" "by"  "cache" "call" "cancel"
1694 "cascade" "case" "category" "certificate" "chained" "change" "check"
1695 "checkpoint" "child" "chunk" "class" "clear" "clone" "close" "cluster"
1696 "column" "column_value" "columns" "comment" "commit" "committed"
1697 "compatibility" "compile" "complete" "composite_limit" "compress"
1698 "compute" "connect" "connect_time" "consider" "consistent"
1699 "constraint" "constraints" "constructor" "contents" "context"
1700 "continue" "controlfile" "corruption" "cost" "cpu_per_call"
1701 "cpu_per_session" "create" "cross" "cube" "current" "currval" "cycle"
1702 "dangling" "data" "database" "datafile" "datafiles" "day" "ddl"
1703 "deallocate" "debug" "default" "deferrable" "deferred" "definer"
1704 "delay" "delete" "demand" "desc" "determines" "deterministic"
1705 "dictionary" "dimension" "directory" "disable" "disassociate"
1706 "disconnect" "distinct" "distinguished" "distributed" "dml" "drop"
1707 "each" "element" "else" "enable" "end" "equals_path" "escape"
1708 "estimate" "except" "exceptions" "exchange" "excluding" "exists"
1709 "expire" "explain" "extent" "external" "externally"
1710 "failed_login_attempts" "fast" "file" "final" "finish" "flush" "for"
1711 "force" "foreign" "freelist" "freelists" "freepools" "fresh" "from"
1712 "full" "function" "functions" "generated" "global" "global_name"
1713 "globally" "grant" "group" "grouping" "groups" "guard" "hash"
1714 "hashkeys" "having" "heap" "hierarchy" "id" "identified" "identifier"
1715 "idle_time" "immediate" "in" "including" "increment" "index" "indexed"
1716 "indexes" "indextype" "indextypes" "indicator" "initial" "initialized"
1717 "initially" "initrans" "inner" "insert" "instance" "instantiable"
1718 "instead" "intersect" "into" "invalidate" "is" "isolation" "java"
1719 "join"  "keep" "key" "kill" "language" "left" "less" "level"
1720 "levels" "library" "like" "like2" "like4" "likec" "limit" "link"
1721 "list" "lob" "local" "location" "locator" "lock" "log" "logfile"
1722 "logging" "logical" "logical_reads_per_call"
1723 "logical_reads_per_session"  "managed" "management" "manual" "map"
1724 "mapping" "master" "matched" "materialized" "maxdatafiles"
1725 "maxextents" "maximize" "maxinstances" "maxlogfiles" "maxloghistory"
1726 "maxlogmembers" "maxsize" "maxtrans" "maxvalue" "member" "memory"
1727 "merge" "migrate" "minextents" "minimize" "minimum" "minus" "minvalue"
1728 "mode" "modify" "monitoring" "month" "mount" "move" "movement" "name"
1729 "named" "natural" "nested" "never" "new" "next" "nextval" "no"
1730 "noarchivelog" "noaudit" "nocache" "nocompress" "nocopy" "nocycle"
1731 "nodelay" "noforce" "nologging" "nomapping" "nomaxvalue" "nominimize"
1732 "nominvalue" "nomonitoring" "none" "noorder" "noparallel" "norely"
1733 "noresetlogs" "noreverse" "normal" "norowdependencies" "nosort"
1734 "noswitch" "not" "nothing" "notimeout" "novalidate" "nowait" "null"
1735 "nulls" "object" "of" "off" "offline" "oidindex" "old" "on" "online"
1736 "only" "open" "operator" "optimal" "option" "or" "order"
1737 "organization" "out" "outer" "outline" "over" "overflow" "overriding"
1738 "package" "packages" "parallel" "parallel_enable" "parameters"
1739 "parent" "partition" "partitions" "password" "password_grace_time"
1740 "password_life_time" "password_lock_time" "password_reuse_max"
1741 "password_reuse_time" "password_verify_function" "pctfree"
1742 "pctincrease" "pctthreshold" "pctused" "pctversion" "percent"
1743 "performance" "permanent" "pfile" "physical" "pipelined" "plan"
1744 "post_transaction" "pragma" "prebuilt" "preserve" "primary" "private"
1745 "private_sga" "privileges" "procedure" "profile" "protection" "public"
1746 "purge" "query" "quiesce" "quota" "range" "read" "reads" "rebuild"
1747 "records_per_block" "recover" "recovery" "recycle" "reduced" "ref"
1748 "references" "referencing" "refresh" "register" "reject" "relational"
1749 "rely" "rename" "reset" "resetlogs" "resize" "resolve" "resolver"
1750 "resource" "restrict" "restrict_references" "restricted" "result"
1751 "resumable" "resume" "retention" "return" "returning" "reuse"
1752 "reverse" "revoke" "rewrite" "right" "rnds" "rnps" "role" "roles"
1753 "rollback" "rollup" "row" "rowdependencies" "rownum" "rows" "sample"
1754 "savepoint" "scan" "schema" "scn" "scope" "segment" "select"
1755 "selectivity" "self" "sequence" "serializable" "session"
1756 "sessions_per_user" "set" "sets" "settings" "shared" "shared_pool"
1757 "shrink" "shutdown" "siblings" "sid" "single" "size" "skip" "some"
1758 "sort" "source" "space" "specification" "spfile" "split" "standby"
1759 "start" "statement_id" "static" "statistics" "stop" "storage" "store"
1760 "structure" "subpartition" "subpartitions" "substitutable"
1761 "successful" "supplemental" "suspend" "switch" "switchover" "synonym"
1762 "sys" "system" "table" "tables" "tablespace" "tempfile" "template"
1763 "temporary" "test" "than" "then" "thread" "through" "time_zone"
1764 "timeout" "to" "trace" "transaction" "trigger" "triggers" "truncate"
1765 "trust" "type" "types" "unarchived" "under" "under_path" "undo"
1766 "uniform" "union" "unique" "unlimited" "unlock" "unquiesce"
1767 "unrecoverable" "until" "unusable" "unused" "update" "upgrade" "usage"
1768 "use" "using" "validate" "validation" "value" "values" "variable"
1769 "varray" "version" "view" "wait" "when" "whenever" "where" "with"
1770 "without" "wnds" "wnps" "work" "write" "xmldata" "xmlschema" "xmltype"
1771 )
1772
1773      ;; Oracle Data Types
1774      (sql-font-lock-keywords-builder 'font-lock-type-face nil
1775 "bfile" "binary_double" "binary_float" "blob" "byte" "char" "charbyte"
1776 "clob" "date" "day" "float" "interval" "local" "long" "longraw"
1777 "minute" "month" "nchar" "nclob" "number" "nvarchar2" "raw" "rowid" "second"
1778 "time" "timestamp" "urowid" "varchar2" "with" "year" "zone"
1779 )
1780
1781      ;; Oracle PL/SQL Attributes
1782      (sql-font-lock-keywords-builder 'font-lock-builtin-face '("%" . "\\b")
1783 "bulk_exceptions" "bulk_rowcount" "found" "isopen" "notfound"
1784 "rowcount" "rowtype" "type"
1785 )
1786
1787      ;; Oracle PL/SQL Functions
1788      (sql-font-lock-keywords-builder 'font-lock-builtin-face nil
1789 "delete" "trim" "extend" "exists" "first" "last" "count" "limit"
1790 "prior" "next" "sqlcode" "sqlerrm"
1791 )
1792
1793      ;; Oracle PL/SQL Reserved words
1794      (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
1795 "all" "alter" "and" "any" "as" "asc" "at" "begin" "between" "by"
1796 "case" "check" "clusters" "cluster" "colauth" "columns" "compress"
1797 "connect" "crash" "create" "cursor" "declare" "default" "desc"
1798 "distinct" "drop" "else" "end" "exception" "exclusive" "fetch" "for"
1799 "from" "function" "goto" "grant" "group" "having" "identified" "if"
1800 "in" "index" "indexes" "insert" "intersect" "into" "is" "like" "lock"
1801 "minus" "mode" "nocompress" "not" "nowait" "null" "of" "on" "option"
1802 "or" "order" "overlaps" "procedure" "public" "resource" "revoke"
1803 "select" "share" "size" "sql" "start" "subtype" "tabauth" "table"
1804 "then" "to" "type" "union" "unique" "update" "values" "view" "views"
1805 "when" "where" "with"
1806
1807 "true" "false"
1808 "raise_application_error"
1809 )
1810
1811      ;; Oracle PL/SQL Keywords
1812      (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
1813 "a" "add" "agent" "aggregate" "array" "attribute" "authid" "avg"
1814 "bfile_base" "binary" "blob_base" "block" "body" "both" "bound" "bulk"
1815 "byte" "c" "call" "calling" "cascade" "char" "char_base" "character"
1816 "charset" "charsetform" "charsetid" "clob_base" "close" "collect"
1817 "comment" "commit" "committed" "compiled" "constant" "constructor"
1818 "context" "continue" "convert" "count" "current" "customdatum"
1819 "dangling" "data" "date" "date_base" "day" "define" "delete"
1820 "deterministic" "double" "duration" "element" "elsif" "empty" "escape"
1821 "except" "exceptions" "execute" "exists" "exit" "external" "final"
1822 "fixed" "float" "forall" "force" "general" "hash" "heap" "hidden"
1823 "hour" "immediate" "including" "indicator" "indices" "infinite"
1824 "instantiable" "int" "interface" "interval" "invalidate" "isolation"
1825 "java" "language" "large" "leading" "length" "level" "library" "like2"
1826 "like4" "likec" "limit" "limited" "local" "long" "loop" "map" "max"
1827 "maxlen" "member" "merge" "min" "minute" "mod" "modify" "month"
1828 "multiset" "name" "nan" "national" "native" "nchar" "new" "nocopy"
1829 "number_base" "object" "ocicoll" "ocidate" "ocidatetime" "ociduration"
1830 "ociinterval" "ociloblocator" "ocinumber" "ociraw" "ociref"
1831 "ocirefcursor" "ocirowid" "ocistring" "ocitype" "old" "only" "opaque"
1832 "open" "operator" "oracle" "oradata" "organization" "orlany" "orlvary"
1833 "others" "out" "overriding" "package" "parallel_enable" "parameter"
1834 "parameters" "parent" "partition" "pascal" "pipe" "pipelined" "pragma"
1835 "precision" "prior" "private" "raise" "range" "raw" "read" "record"
1836 "ref" "reference" "relies_on" "rem" "remainder" "rename" "result"
1837 "result_cache" "return" "returning" "reverse" "rollback" "row"
1838 "sample" "save" "savepoint" "sb1" "sb2" "sb4" "second" "segment"
1839 "self" "separate" "sequence" "serializable" "set" "short" "size_t"
1840 "some" "sparse" "sqlcode" "sqldata" "sqlname" "sqlstate" "standard"
1841 "static" "stddev" "stored" "string" "struct" "style" "submultiset"
1842 "subpartition" "substitutable" "sum" "synonym" "tdo" "the" "time"
1843 "timestamp" "timezone_abbr" "timezone_hour" "timezone_minute"
1844 "timezone_region" "trailing" "transaction" "transactional" "trusted"
1845 "ub1" "ub2" "ub4" "under" "unsigned" "untrusted" "use" "using"
1846 "valist" "value" "variable" "variance" "varray" "varying" "void"
1847 "while" "work" "wrapped" "write" "year" "zone"
1848 ;; Pragma
1849 "autonomous_transaction" "exception_init" "inline"
1850 "restrict_references" "serially_reusable"
1851 )
1852
1853      ;; Oracle PL/SQL Data Types
1854      (sql-font-lock-keywords-builder 'font-lock-type-face nil
1855 "\"BINARY LARGE OBJECT\"" "\"CHAR LARGE OBJECT\"" "\"CHAR VARYING\""
1856 "\"CHARACTER LARGE OBJECT\"" "\"CHARACTER VARYING\""
1857 "\"DOUBLE PRECISION\"" "\"INTERVAL DAY TO SECOND\""
1858 "\"INTERVAL YEAR TO MONTH\"" "\"LONG RAW\"" "\"NATIONAL CHAR\""
1859 "\"NATIONAL CHARACTER LARGE OBJECT\"" "\"NATIONAL CHARACTER\""
1860 "\"NCHAR LARGE OBJECT\"" "\"NCHAR\"" "\"NCLOB\"" "\"NVARCHAR2\""
1861 "\"TIME WITH TIME ZONE\"" "\"TIMESTAMP WITH LOCAL TIME ZONE\""
1862 "\"TIMESTAMP WITH TIME ZONE\""
1863 "bfile" "bfile_base" "binary_double" "binary_float" "binary_integer"
1864 "blob" "blob_base" "boolean" "char" "character" "char_base" "clob"
1865 "clob_base" "cursor" "date" "day" "dec" "decimal"
1866 "dsinterval_unconstrained" "float" "int" "integer" "interval" "local"
1867 "long" "mlslabel" "month" "natural" "naturaln" "nchar_cs" "number"
1868 "number_base" "numeric" "pls_integer" "positive" "positiven" "raw"
1869 "real" "ref" "rowid" "second" "signtype" "simple_double"
1870 "simple_float" "simple_integer" "smallint" "string" "time" "timestamp"
1871 "timestamp_ltz_unconstrained" "timestamp_tz_unconstrained"
1872 "timestamp_unconstrained" "time_tz_unconstrained" "time_unconstrained"
1873 "to" "urowid" "varchar" "varchar2" "with" "year"
1874 "yminterval_unconstrained" "zone"
1875 )
1876
1877      ;; Oracle PL/SQL Exceptions
1878      (sql-font-lock-keywords-builder 'font-lock-warning-face nil
1879 "access_into_null" "case_not_found" "collection_is_null"
1880 "cursor_already_open" "dup_val_on_index" "invalid_cursor"
1881 "invalid_number" "login_denied" "no_data_found" "no_data_needed"
1882 "not_logged_on" "program_error" "rowtype_mismatch" "self_is_null"
1883 "storage_error" "subscript_beyond_count" "subscript_outside_limit"
1884 "sys_invalid_rowid" "timeout_on_resource" "too_many_rows"
1885 "value_error" "zero_divide"
1886 )))
1887
1888   "Oracle SQL keywords used by font-lock.
1889
1890 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
1891 regular expressions are created during compilation by calling the
1892 function `regexp-opt'.  Therefore, take a look at the source before
1893 you define your own `sql-mode-oracle-font-lock-keywords'.  You may want
1894 to add functions and PL/SQL keywords.")
1895
1896 (defvar sql-mode-postgres-font-lock-keywords
1897   (eval-when-compile
1898     (list
1899      ;; Postgres psql commands
1900      '("^\\s-*\\\\.*$" . font-lock-doc-face)
1901
1902      ;; Postgres unreserved words but may have meaning
1903      (sql-font-lock-keywords-builder 'font-lock-builtin-face nil "a"
1904 "abs" "absent" "according" "ada" "alias" "allocate" "are" "array_agg"
1905 "asensitive" "atomic" "attribute" "attributes" "avg" "base64"
1906 "bernoulli" "bit_length" "bitvar" "blob" "blocked" "bom" "breadth" "c"
1907 "call" "cardinality" "catalog_name" "ceil" "ceiling" "char_length"
1908 "character_length" "character_set_catalog" "character_set_name"
1909 "character_set_schema" "characters" "checked" "class_origin" "clob"
1910 "cobol" "collation" "collation_catalog" "collation_name"
1911 "collation_schema" "collect" "column_name" "columns"
1912 "command_function" "command_function_code" "completion" "condition"
1913 "condition_number" "connect" "connection_name" "constraint_catalog"
1914 "constraint_name" "constraint_schema" "constructor" "contains"
1915 "control" "convert" "corr" "corresponding" "count" "covar_pop"
1916 "covar_samp" "cube" "cume_dist" "current_default_transform_group"
1917 "current_path" "current_transform_group_for_type" "cursor_name"
1918 "datalink" "datetime_interval_code" "datetime_interval_precision" "db"
1919 "defined" "degree" "dense_rank" "depth" "deref" "derived" "describe"
1920 "descriptor" "destroy" "destructor" "deterministic" "diagnostics"
1921 "disconnect" "dispatch" "dlnewcopy" "dlpreviouscopy" "dlurlcomplete"
1922 "dlurlcompleteonly" "dlurlcompletewrite" "dlurlpath" "dlurlpathonly"
1923 "dlurlpathwrite" "dlurlscheme" "dlurlserver" "dlvalue" "dynamic"
1924 "dynamic_function" "dynamic_function_code" "element" "empty"
1925 "end-exec" "equals" "every" "exception" "exec" "existing" "exp" "file"
1926 "filter" "final" "first_value" "flag" "floor" "fortran" "found" "free"
1927 "fs" "fusion" "g" "general" "generated" "get" "go" "goto" "grouping"
1928 "hex" "hierarchy" "host" "id" "ignore" "implementation" "import"
1929 "indent" "indicator" "infix" "initialize" "instance" "instantiable"
1930 "integrity" "intersection" "iterate" "k" "key_member" "key_type" "lag"
1931 "last_value" "lateral" "lead" "length" "less" "library" "like_regex"
1932 "link" "ln" "locator" "lower" "m" "map" "matched" "max"
1933 "max_cardinality" "member" "merge" "message_length"
1934 "message_octet_length" "message_text" "method" "min" "mod" "modifies"
1935 "modify" "module" "more" "multiset" "mumps" "namespace" "nclob"
1936 "nesting" "new" "nfc" "nfd" "nfkc" "nfkd" "nil" "normalize"
1937 "normalized" "nth_value" "ntile" "nullable" "number"
1938 "occurrences_regex" "octet_length" "octets" "old" "open" "operation"
1939 "ordering" "ordinality" "others" "output" "overriding" "p" "pad"
1940 "parameter" "parameter_mode" "parameter_name"
1941 "parameter_ordinal_position" "parameter_specific_catalog"
1942 "parameter_specific_name" "parameter_specific_schema" "parameters"
1943 "pascal" "passing" "passthrough" "percent_rank" "percentile_cont"
1944 "percentile_disc" "permission" "pli" "position_regex" "postfix"
1945 "power" "prefix" "preorder" "public" "rank" "reads" "recovery" "ref"
1946 "referencing" "regr_avgx" "regr_avgy" "regr_count" "regr_intercept"
1947 "regr_r2" "regr_slope" "regr_sxx" "regr_sxy" "regr_syy" "requiring"
1948 "respect" "restore" "result" "return" "returned_cardinality"
1949 "returned_length" "returned_octet_length" "returned_sqlstate" "rollup"
1950 "routine" "routine_catalog" "routine_name" "routine_schema"
1951 "row_count" "row_number" "scale" "schema_name" "scope" "scope_catalog"
1952 "scope_name" "scope_schema" "section" "selective" "self" "sensitive"
1953 "server_name" "sets" "size" "source" "space" "specific"
1954 "specific_name" "specifictype" "sql" "sqlcode" "sqlerror"
1955 "sqlexception" "sqlstate" "sqlwarning" "sqrt" "state" "static"
1956 "stddev_pop" "stddev_samp" "structure" "style" "subclass_origin"
1957 "sublist" "submultiset" "substring_regex" "sum" "system_user" "t"
1958 "table_name" "tablesample" "terminate" "than" "ties" "timezone_hour"
1959 "timezone_minute" "token" "top_level_count" "transaction_active"
1960 "transactions_committed" "transactions_rolled_back" "transform"
1961 "transforms" "translate" "translate_regex" "translation"
1962 "trigger_catalog" "trigger_name" "trigger_schema" "trim_array"
1963 "uescape" "under" "unlink" "unnamed" "unnest" "untyped" "upper" "uri"
1964 "usage" "user_defined_type_catalog" "user_defined_type_code"
1965 "user_defined_type_name" "user_defined_type_schema" "var_pop"
1966 "var_samp" "varbinary" "variable" "whenever" "width_bucket" "within"
1967 "xmlagg" "xmlbinary" "xmlcast" "xmlcomment" "xmldeclaration"
1968 "xmldocument" "xmlexists" "xmliterate" "xmlnamespaces" "xmlquery"
1969 "xmlschema" "xmltable" "xmltext" "xmlvalidate"
1970 )
1971
1972      ;; Postgres non-reserved words
1973      (sql-font-lock-keywords-builder 'font-lock-builtin-face nil
1974 "abort" "absolute" "access" "action" "add" "admin" "after" "aggregate"
1975 "also" "alter" "always" "assertion" "assignment" "at" "attribute" "backward"
1976 "before" "begin" "between" "by" "cache" "called" "cascade" "cascaded"
1977 "catalog" "chain" "characteristics" "checkpoint" "class" "close"
1978 "cluster" "coalesce" "comment" "comments" "commit" "committed"
1979 "configuration" "connection" "constraints" "content" "continue"
1980 "conversion" "copy" "cost" "createdb" "createrole" "createuser" "csv"
1981 "current" "cursor" "cycle" "data" "database" "day" "deallocate" "dec"
1982 "declare" "defaults" "deferred" "definer" "delete" "delimiter"
1983 "delimiters" "dictionary" "disable" "discard" "document" "domain"
1984 "drop" "each" "enable" "encoding" "encrypted" "enum" "escape"
1985 "exclude" "excluding" "exclusive" "execute" "exists" "explain"
1986 "extension" "external" "extract" "family" "first" "float" "following" "force"
1987 "forward" "function" "functions" "global" "granted" "greatest"
1988 "handler" "header" "hold" "hour" "identity" "if" "immediate"
1989 "immutable" "implicit" "including" "increment" "index" "indexes"
1990 "inherit" "inherits" "inline" "inout" "input" "insensitive" "insert"
1991 "instead" "invoker" "isolation" "key" "label" "language" "large" "last"
1992 "lc_collate" "lc_ctype" "leakproof" "least" "level" "listen" "load" "local"
1993 "location" "lock" "login" "mapping" "match" "maxvalue" "minute"
1994 "minvalue" "mode" "month" "move" "names" "national" "nchar"
1995 "next" "no" "nocreatedb" "nocreaterole" "nocreateuser" "noinherit"
1996 "nologin" "none"  "noreplication" "nosuperuser" "nothing" "notify" "nowait" "nullif"
1997 "nulls" "object" "of" "off" "oids" "operator" "option" "options" "out"
1998 "overlay" "owned" "owner" "parser" "partial" "partition" "passing" "password"
1999 "plans" "position" "preceding" "precision" "prepare" "prepared" "preserve" "prior"
2000 "privileges" "procedural" "procedure" "quote" "range" "read"
2001 "reassign" "recheck" "recursive" "ref" "reindex" "relative" "release"
2002 "rename" "repeatable" "replace" "replica" "replication" "reset" "restart" "restrict"
2003 "returns" "revoke" "role" "rollback" "row" "rows" "rule" "savepoint"
2004 "schema" "scroll" "search" "second" "security" "sequence"
2005 "serializable" "server" "session" "set" "setof" "share" "show"
2006 "simple" "snapshot" "stable" "standalone" "start" "statement" "statistics"
2007 "stdin" "stdout" "storage" "strict" "strip" "substring" "superuser"
2008 "sysid" "system" "tables" "tablespace" "temp" "template" "temporary"
2009 "transaction" "treat" "trim" "truncate" "trusted" "type" "types"
2010 "unbounded" "uncommitted" "unencrypted" "unlisten" "unlogged" "until"
2011 "update" "vacuum" "valid" "validate" "validator" "value" "values" "varying" "version"
2012 "view" "volatile" "whitespace" "without" "work" "wrapper" "write"
2013 "xmlattributes" "xmlconcat" "xmlelement" "xmlexists" "xmlforest" "xmlparse"
2014 "xmlpi" "xmlroot" "xmlserialize" "year" "yes" "zone"
2015 )
2016
2017      ;; Postgres Reserved
2018      (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
2019 "all" "analyse" "analyze" "and" "array" "asc" "as" "asymmetric"
2020 "authorization" "binary" "both" "case" "cast" "check" "collate"
2021 "column" "concurrently" "constraint" "create" "cross"
2022 "current_catalog" "current_date" "current_role" "current_schema"
2023 "current_time" "current_timestamp" "current_user" "default"
2024 "deferrable" "desc" "distinct" "do" "else" "end" "except" "false"
2025 "fetch" "foreign" "for" "freeze" "from" "full" "grant" "group"
2026 "having" "ilike" "initially" "inner" "in" "intersect" "into" "isnull"
2027 "is" "join" "leading" "left" "like" "limit" "localtime"
2028 "localtimestamp" "natural" "notnull" "not" "null" "offset"
2029 "only" "on" "order" "or" "outer" "overlaps" "over" "placing" "primary"
2030 "references" "returning" "right" "select" "session_user" "similar"
2031 "some" "symmetric" "table" "then" "to" "trailing" "true" "union"
2032 "unique" "user" "using" "variadic" "verbose" "when" "where" "window"
2033 "with"
2034 )
2035
2036      ;; Postgres PL/pgSQL
2037      (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
2038 "assign" "if" "case" "loop" "while" "for" "foreach" "exit" "elsif" "return"
2039 "raise" "execsql" "dynexecute" "perform" "getdiag" "open" "fetch" "move" "close"
2040 )
2041
2042      ;; Postgres Data Types
2043      (sql-font-lock-keywords-builder 'font-lock-type-face nil
2044 "bigint" "bigserial" "bit" "bool" "boolean" "box" "bytea" "char"
2045 "character" "cidr" "circle" "date" "decimal" "double" "float4"
2046 "float8" "inet" "int" "int2" "int4" "int8" "integer" "interval" "line"
2047 "lseg" "macaddr" "money" "name" "numeric" "path" "point" "polygon"
2048 "precision" "real" "serial" "serial4" "serial8" "sequences" "smallint" "text"
2049 "time" "timestamp" "timestamptz" "timetz" "tsquery" "tsvector"
2050 "txid_snapshot" "unknown" "uuid" "varbit" "varchar" "varying" "without"
2051 "xml" "zone"
2052 )))
2053
2054   "Postgres SQL keywords used by font-lock.
2055
2056 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2057 regular expressions are created during compilation by calling the
2058 function `regexp-opt'.  Therefore, take a look at the source before
2059 you define your own `sql-mode-postgres-font-lock-keywords'.")
2060
2061 (defvar sql-mode-linter-font-lock-keywords
2062   (eval-when-compile
2063     (list
2064      ;; Linter Keywords
2065      (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
2066 "autocommit" "autoinc" "autorowid" "cancel" "cascade" "channel"
2067 "committed" "count" "countblob" "cross" "current" "data" "database"
2068 "datafile" "datafiles" "datesplit" "dba" "dbname" "default" "deferred"
2069 "denied" "description" "device" "difference" "directory" "error"
2070 "escape" "euc" "exclusive" "external" "extfile" "false" "file"
2071 "filename" "filesize" "filetime" "filter" "findblob" "first" "foreign"
2072 "full" "fuzzy" "global" "granted" "ignore" "immediate" "increment"
2073 "indexes" "indexfile" "indexfiles" "indextime" "initial" "integrity"
2074 "internal" "key" "last_autoinc" "last_rowid" "limit" "linter"
2075 "linter_file_device" "linter_file_size" "linter_name_length" "ln"
2076 "local" "login" "maxisn" "maxrow" "maxrowid" "maxvalue" "message"
2077 "minvalue" "module" "names" "national" "natural" "new" "new_table"
2078 "no" "node" "noneuc" "nulliferror" "numbers" "off" "old" "old_table"
2079 "only" "operation" "optimistic" "option" "page" "partially" "password"
2080 "phrase" "plan" "precision" "primary" "priority" "privileges"
2081 "proc_info_size" "proc_par_name_len" "protocol" "quant" "range" "raw"
2082 "read" "record" "records" "references" "remote" "rename" "replication"
2083 "restart" "rewrite" "root" "row" "rule" "savepoint" "security"
2084 "sensitive" "sequence" "serializable" "server" "since" "size" "some"
2085 "startup" "statement" "station" "success" "sys_guid" "tables" "test"
2086 "timeout" "trace" "transaction" "translation" "trigger"
2087 "trigger_info_size" "true" "trunc" "uncommitted" "unicode" "unknown"
2088 "unlimited" "unlisted" "user" "utf8" "value" "varying" "volumes"
2089 "wait" "windows_code" "workspace" "write" "xml"
2090 )
2091
2092      ;; Linter Reserved
2093      (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
2094 "access" "action" "add" "address" "after" "all" "alter" "always" "and"
2095 "any" "append" "as" "asc" "ascic" "async" "at_begin" "at_end" "audit"
2096 "aud_obj_name_len" "backup" "base" "before" "between" "blobfile"
2097 "blobfiles" "blobpct" "brief" "browse" "by" "case" "cast" "check"
2098 "clear" "close" "column" "comment" "commit" "connect" "contains"
2099 "correct" "create" "delete" "desc" "disable" "disconnect" "distinct"
2100 "drop" "each" "ef" "else" "enable" "end" "event" "except" "exclude"
2101 "execute" "exists" "extract" "fetch" "finish" "for" "from" "get"
2102 "grant" "group" "having" "identified" "in" "index" "inner" "insert"
2103 "instead" "intersect" "into" "is" "isolation" "join" "left" "level"
2104 "like" "lock" "mode" "modify" "not" "nowait" "null" "of" "on" "open"
2105 "or" "order" "outer" "owner" "press" "prior" "procedure" "public"
2106 "purge" "rebuild" "resource" "restrict" "revoke" "right" "role"
2107 "rollback" "rownum" "select" "session" "set" "share" "shutdown"
2108 "start" "stop" "sync" "synchronize" "synonym" "sysdate" "table" "then"
2109 "to" "union" "unique" "unlock" "until" "update" "using" "values"
2110 "view" "when" "where" "with" "without"
2111 )
2112
2113      ;; Linter Functions
2114      (sql-font-lock-keywords-builder 'font-lock-builtin-face nil
2115 "abs" "acos" "asin" "atan" "atan2" "avg" "ceil" "cos" "cosh" "divtime"
2116 "exp" "floor" "getbits" "getblob" "getbyte" "getlong" "getraw"
2117 "getstr" "gettext" "getword" "hextoraw" "lenblob" "length" "log"
2118 "lower" "lpad" "ltrim" "max" "min" "mod" "monthname" "nvl"
2119 "octet_length" "power" "rand" "rawtohex" "repeat_string"
2120 "right_substr" "round" "rpad" "rtrim" "sign" "sin" "sinh" "soundex"
2121 "sqrt" "sum" "tan" "tanh" "timeint_to_days" "to_char" "to_date"
2122 "to_gmtime" "to_localtime" "to_number" "trim" "upper" "decode"
2123 "substr" "substring" "chr" "dayname" "days" "greatest" "hex" "initcap"
2124 "instr" "least" "multime" "replace" "width"
2125 )
2126
2127      ;; Linter Data Types
2128      (sql-font-lock-keywords-builder 'font-lock-type-face nil
2129 "bigint" "bitmap" "blob" "boolean" "char" "character" "date"
2130 "datetime" "dec" "decimal" "double" "float" "int" "integer" "nchar"
2131 "number" "numeric" "real" "smallint" "varbyte" "varchar" "byte"
2132 "cursor" "long"
2133 )))
2134
2135   "Linter SQL keywords used by font-lock.
2136
2137 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2138 regular expressions are created during compilation by calling the
2139 function `regexp-opt'.")
2140
2141 (defvar sql-mode-ms-font-lock-keywords
2142   (eval-when-compile
2143     (list
2144      ;; MS isql/osql Commands
2145      (cons
2146       (concat
2147        "^\\(?:\\(?:set\\s-+\\(?:"
2148        (regexp-opt '(
2149 "datefirst" "dateformat" "deadlock_priority" "lock_timeout"
2150 "concat_null_yields_null" "cursor_close_on_commit"
2151 "disable_def_cnst_chk" "fips_flagger" "identity_insert" "language"
2152 "offsets" "quoted_identifier" "arithabort" "arithignore" "fmtonly"
2153 "nocount" "noexec" "numeric_roundabort" "parseonly"
2154 "query_governor_cost_limit" "rowcount" "textsize" "ansi_defaults"
2155 "ansi_null_dflt_off" "ansi_null_dflt_on" "ansi_nulls" "ansi_padding"
2156 "ansi_warnings" "forceplan" "showplan_all" "showplan_text"
2157 "statistics" "implicit_transactions" "remote_proc_transactions"
2158 "transaction" "xact_abort"
2159 ) t)
2160        "\\)\\)\\|go\\s-*\\|use\\s-+\\|setuser\\s-+\\|dbcc\\s-+\\).*$")
2161       'font-lock-doc-face)
2162
2163      ;; MS Reserved
2164      (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
2165 "absolute" "add" "all" "alter" "and" "any" "as" "asc" "authorization"
2166 "avg" "backup" "begin" "between" "break" "browse" "bulk" "by"
2167 "cascade" "case" "check" "checkpoint" "close" "clustered" "coalesce"
2168 "column" "commit" "committed" "compute" "confirm" "constraint"
2169 "contains" "containstable" "continue" "controlrow" "convert" "count"
2170 "create" "cross" "current" "current_date" "current_time"
2171 "current_timestamp" "current_user" "database" "deallocate" "declare"
2172 "default" "delete" "deny" "desc" "disk" "distinct" "distributed"
2173 "double" "drop" "dummy" "dump" "else" "end" "errlvl" "errorexit"
2174 "escape" "except" "exec" "execute" "exists" "exit" "fetch" "file"
2175 "fillfactor" "first" "floppy" "for" "foreign" "freetext"
2176 "freetexttable" "from" "full" "goto" "grant" "group" "having"
2177 "holdlock" "identity" "identity_insert" "identitycol" "if" "in"
2178 "index" "inner" "insert" "intersect" "into" "is" "isolation" "join"
2179 "key" "kill" "last" "left" "level" "like" "lineno" "load" "max" "min"
2180 "mirrorexit" "national" "next" "nocheck" "nolock" "nonclustered" "not"
2181 "null" "nullif" "of" "off" "offsets" "on" "once" "only" "open"
2182 "opendatasource" "openquery" "openrowset" "option" "or" "order"
2183 "outer" "output" "over" "paglock" "percent" "perm" "permanent" "pipe"
2184 "plan" "precision" "prepare" "primary" "print" "prior" "privileges"
2185 "proc" "procedure" "processexit" "public" "raiserror" "read"
2186 "readcommitted" "readpast" "readtext" "readuncommitted" "reconfigure"
2187 "references" "relative" "repeatable" "repeatableread" "replication"
2188 "restore" "restrict" "return" "revoke" "right" "rollback" "rowcount"
2189 "rowguidcol" "rowlock" "rule" "save" "schema" "select" "serializable"
2190 "session_user" "set" "shutdown" "some" "statistics" "sum"
2191 "system_user" "table" "tablock" "tablockx" "tape" "temp" "temporary"
2192 "textsize" "then" "to" "top" "tran" "transaction" "trigger" "truncate"
2193 "tsequal" "uncommitted" "union" "unique" "update" "updatetext"
2194 "updlock" "use" "user" "values" "view" "waitfor" "when" "where"
2195 "while" "with" "work" "writetext" "collate" "function" "openxml"
2196 "returns"
2197 )
2198
2199      ;; MS Functions
2200      (sql-font-lock-keywords-builder 'font-lock-builtin-face nil
2201 "@@connections" "@@cpu_busy" "@@cursor_rows" "@@datefirst" "@@dbts"
2202 "@@error" "@@fetch_status" "@@identity" "@@idle" "@@io_busy"
2203 "@@langid" "@@language" "@@lock_timeout" "@@max_connections"
2204 "@@max_precision" "@@nestlevel" "@@options" "@@pack_received"
2205 "@@pack_sent" "@@packet_errors" "@@procid" "@@remserver" "@@rowcount"
2206 "@@servername" "@@servicename" "@@spid" "@@textsize" "@@timeticks"
2207 "@@total_errors" "@@total_read" "@@total_write" "@@trancount"
2208 "@@version" "abs" "acos" "and" "app_name" "ascii" "asin" "atan" "atn2"
2209 "avg" "case" "cast" "ceiling" "char" "charindex" "coalesce"
2210 "col_length" "col_name" "columnproperty" "containstable" "convert"
2211 "cos" "cot" "count" "current_timestamp" "current_user" "cursor_status"
2212 "databaseproperty" "datalength" "dateadd" "datediff" "datename"
2213 "datepart" "day" "db_id" "db_name" "degrees" "difference" "exp"
2214 "file_id" "file_name" "filegroup_id" "filegroup_name"
2215 "filegroupproperty" "fileproperty" "floor" "formatmessage"
2216 "freetexttable" "fulltextcatalogproperty" "fulltextserviceproperty"
2217 "getansinull" "getdate" "grouping" "host_id" "host_name" "ident_incr"
2218 "ident_seed" "identity" "index_col" "indexproperty" "is_member"
2219 "is_srvrolemember" "isdate" "isnull" "isnumeric" "left" "len" "log"
2220 "log10" "lower" "ltrim" "max" "min" "month" "nchar" "newid" "nullif"
2221 "object_id" "object_name" "objectproperty" "openquery" "openrowset"
2222 "parsename" "patindex" "patindex" "permissions" "pi" "power"
2223 "quotename" "radians" "rand" "replace" "replicate" "reverse" "right"
2224 "round" "rtrim" "session_user" "sign" "sin" "soundex" "space" "sqrt"
2225 "square" "stats_date" "stdev" "stdevp" "str" "stuff" "substring" "sum"
2226 "suser_id" "suser_name" "suser_sid" "suser_sname" "system_user" "tan"
2227 "textptr" "textvalid" "typeproperty" "unicode" "upper" "user"
2228 "user_id" "user_name" "var" "varp" "year"
2229 )
2230
2231      ;; MS Variables
2232      '("\\b@[a-zA-Z0-9_]*\\b" . font-lock-variable-name-face)
2233
2234      ;; MS Types
2235      (sql-font-lock-keywords-builder 'font-lock-type-face nil
2236 "binary" "bit" "char" "character" "cursor" "datetime" "dec" "decimal"
2237 "double" "float" "image" "int" "integer" "money" "national" "nchar"
2238 "ntext" "numeric" "numeric" "nvarchar" "precision" "real"
2239 "smalldatetime" "smallint" "smallmoney" "text" "timestamp" "tinyint"
2240 "uniqueidentifier" "varbinary" "varchar" "varying"
2241 )))
2242
2243   "Microsoft SQLServer SQL keywords used by font-lock.
2244
2245 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2246 regular expressions are created during compilation by calling the
2247 function `regexp-opt'.  Therefore, take a look at the source before
2248 you define your own `sql-mode-ms-font-lock-keywords'.")
2249
2250 (defvar sql-mode-sybase-font-lock-keywords nil
2251   "Sybase SQL keywords used by font-lock.
2252
2253 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2254 regular expressions are created during compilation by calling the
2255 function `regexp-opt'.  Therefore, take a look at the source before
2256 you define your own `sql-mode-sybase-font-lock-keywords'.")
2257
2258 (defvar sql-mode-informix-font-lock-keywords nil
2259   "Informix SQL keywords used by font-lock.
2260
2261 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2262 regular expressions are created during compilation by calling the
2263 function `regexp-opt'.  Therefore, take a look at the source before
2264 you define your own `sql-mode-informix-font-lock-keywords'.")
2265
2266 (defvar sql-mode-interbase-font-lock-keywords nil
2267   "Interbase SQL keywords used by font-lock.
2268
2269 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2270 regular expressions are created during compilation by calling the
2271 function `regexp-opt'.  Therefore, take a look at the source before
2272 you define your own `sql-mode-interbase-font-lock-keywords'.")
2273
2274 (defvar sql-mode-ingres-font-lock-keywords nil
2275   "Ingres SQL keywords used by font-lock.
2276
2277 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2278 regular expressions are created during compilation by calling the
2279 function `regexp-opt'.  Therefore, take a look at the source before
2280 you define your own `sql-mode-interbase-font-lock-keywords'.")
2281
2282 (defvar sql-mode-solid-font-lock-keywords nil
2283   "Solid SQL keywords used by font-lock.
2284
2285 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2286 regular expressions are created during compilation by calling the
2287 function `regexp-opt'.  Therefore, take a look at the source before
2288 you define your own `sql-mode-solid-font-lock-keywords'.")
2289
2290 (defvar sql-mode-mysql-font-lock-keywords
2291   (eval-when-compile
2292     (list
2293      ;; MySQL Functions
2294      (sql-font-lock-keywords-builder 'font-lock-builtin-face nil
2295 "ascii" "avg" "bdmpolyfromtext" "bdmpolyfromwkb" "bdpolyfromtext"
2296 "bdpolyfromwkb" "benchmark" "bin" "bit_and" "bit_length" "bit_or"
2297 "bit_xor" "both" "cast" "char_length" "character_length" "coalesce"
2298 "concat" "concat_ws" "connection_id" "conv" "convert" "count"
2299 "curdate" "current_date" "current_time" "current_timestamp" "curtime"
2300 "elt" "encrypt" "export_set" "field" "find_in_set" "found_rows" "from"
2301 "geomcollfromtext" "geomcollfromwkb" "geometrycollectionfromtext"
2302 "geometrycollectionfromwkb" "geometryfromtext" "geometryfromwkb"
2303 "geomfromtext" "geomfromwkb" "get_lock" "group_concat" "hex" "ifnull"
2304 "instr" "interval" "isnull" "last_insert_id" "lcase" "leading"
2305 "length" "linefromtext" "linefromwkb" "linestringfromtext"
2306 "linestringfromwkb" "load_file" "locate" "lower" "lpad" "ltrim"
2307 "make_set" "master_pos_wait" "max" "mid" "min" "mlinefromtext"
2308 "mlinefromwkb" "mpointfromtext" "mpointfromwkb" "mpolyfromtext"
2309 "mpolyfromwkb" "multilinestringfromtext" "multilinestringfromwkb"
2310 "multipointfromtext" "multipointfromwkb" "multipolygonfromtext"
2311 "multipolygonfromwkb" "now" "nullif" "oct" "octet_length" "ord"
2312 "pointfromtext" "pointfromwkb" "polyfromtext" "polyfromwkb"
2313 "polygonfromtext" "polygonfromwkb" "position" "quote" "rand"
2314 "release_lock" "repeat" "replace" "reverse" "rpad" "rtrim" "soundex"
2315 "space" "std" "stddev" "substring" "substring_index" "sum" "sysdate"
2316 "trailing" "trim" "ucase" "unix_timestamp" "upper" "user" "variance"
2317 )
2318
2319      ;; MySQL Keywords
2320      (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
2321 "action" "add" "after" "against" "all" "alter" "and" "as" "asc"
2322 "auto_increment" "avg_row_length" "bdb" "between" "by" "cascade"
2323 "case" "change" "character" "check" "checksum" "close" "collate"
2324 "collation" "column" "columns" "comment" "committed" "concurrent"
2325 "constraint" "create" "cross" "data" "database" "default"
2326 "delay_key_write" "delayed" "delete" "desc" "directory" "disable"
2327 "distinct" "distinctrow" "do" "drop" "dumpfile" "duplicate" "else" "elseif"
2328 "enable" "enclosed" "end" "escaped" "exists" "fields" "first" "for"
2329 "force" "foreign" "from" "full" "fulltext" "global" "group" "handler"
2330 "having" "heap" "high_priority" "if" "ignore" "in" "index" "infile"
2331 "inner" "insert" "insert_method" "into" "is" "isam" "isolation" "join"
2332 "key" "keys" "last" "left" "level" "like" "limit" "lines" "load"
2333 "local" "lock" "low_priority" "match" "max_rows" "merge" "min_rows"
2334 "mode" "modify" "mrg_myisam" "myisam" "natural" "next" "no" "not"
2335 "null" "offset" "oj" "on" "open" "optionally" "or" "order" "outer"
2336 "outfile" "pack_keys" "partial" "password" "prev" "primary"
2337 "procedure" "quick" "raid0" "raid_type" "read" "references" "rename"
2338 "repeatable" "restrict" "right" "rollback" "rollup" "row_format"
2339 "savepoint" "select" "separator" "serializable" "session" "set"
2340 "share" "show" "sql_big_result" "sql_buffer_result" "sql_cache"
2341 "sql_calc_found_rows" "sql_no_cache" "sql_small_result" "starting"
2342 "straight_join" "striped" "table" "tables" "temporary" "terminated"
2343 "then" "to" "transaction" "truncate" "type" "uncommitted" "union"
2344 "unique" "unlock" "update" "use" "using" "values" "when" "where"
2345 "with" "write" "xor"
2346 )
2347
2348      ;; MySQL Data Types
2349      (sql-font-lock-keywords-builder 'font-lock-type-face nil
2350 "bigint" "binary" "bit" "blob" "bool" "boolean" "char" "curve" "date"
2351 "datetime" "dec" "decimal" "double" "enum" "fixed" "float" "geometry"
2352 "geometrycollection" "int" "integer" "line" "linearring" "linestring"
2353 "longblob" "longtext" "mediumblob" "mediumint" "mediumtext"
2354 "multicurve" "multilinestring" "multipoint" "multipolygon"
2355 "multisurface" "national" "numeric" "point" "polygon" "precision"
2356 "real" "smallint" "surface" "text" "time" "timestamp" "tinyblob"
2357 "tinyint" "tinytext" "unsigned" "varchar" "year" "year2" "year4"
2358 "zerofill"
2359 )))
2360
2361   "MySQL SQL keywords used by font-lock.
2362
2363 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2364 regular expressions are created during compilation by calling the
2365 function `regexp-opt'.  Therefore, take a look at the source before
2366 you define your own `sql-mode-mysql-font-lock-keywords'.")
2367
2368 (defvar sql-mode-sqlite-font-lock-keywords
2369   (eval-when-compile
2370     (list
2371      ;; SQLite commands
2372      '("^[.].*$" . font-lock-doc-face)
2373
2374      ;; SQLite Keyword
2375      (sql-font-lock-keywords-builder 'font-lock-keyword-face nil
2376 "abort" "action" "add" "after" "all" "alter" "analyze" "and" "as"
2377 "asc" "attach" "autoincrement" "before" "begin" "between" "by"
2378 "cascade" "case" "cast" "check" "collate" "column" "commit" "conflict"
2379 "constraint" "create" "cross" "database" "default" "deferrable"
2380 "deferred" "delete" "desc" "detach" "distinct" "drop" "each" "else"
2381 "end" "escape" "except" "exclusive" "exists" "explain" "fail" "for"
2382 "foreign" "from" "full" "glob" "group" "having" "if" "ignore"
2383 "immediate" "in" "index" "indexed" "initially" "inner" "insert"
2384 "instead" "intersect" "into" "is" "isnull" "join" "key" "left" "like"
2385 "limit" "match" "natural" "no" "not" "notnull" "null" "of" "offset"
2386 "on" "or" "order" "outer" "plan" "pragma" "primary" "query" "raise"
2387 "references" "regexp" "reindex" "release" "rename" "replace"
2388 "restrict" "right" "rollback" "row" "savepoint" "select" "set" "table"
2389 "temp" "temporary" "then" "to" "transaction" "trigger" "union"
2390 "unique" "update" "using" "vacuum" "values" "view" "virtual" "when"
2391 "where"
2392 )
2393      ;; SQLite Data types
2394      (sql-font-lock-keywords-builder 'font-lock-type-face nil
2395 "int" "integer" "tinyint" "smallint" "mediumint" "bigint" "unsigned"
2396 "big" "int2" "int8" "character" "varchar" "varying" "nchar" "native"
2397 "nvarchar" "text" "clob" "blob" "real" "double" "precision" "float"
2398 "numeric" "number" "decimal" "boolean" "date" "datetime"
2399 )
2400      ;; SQLite Functions
2401      (sql-font-lock-keywords-builder 'font-lock-builtin-face nil
2402 ;; Core functions
2403 "abs" "changes" "coalesce" "glob" "ifnull" "hex" "last_insert_rowid"
2404 "length" "like" "load_extension" "lower" "ltrim" "max" "min" "nullif"
2405 "quote" "random" "randomblob" "replace" "round" "rtrim" "soundex"
2406 "sqlite_compileoption_get" "sqlite_compileoption_used"
2407 "sqlite_source_id" "sqlite_version" "substr" "total_changes" "trim"
2408 "typeof" "upper" "zeroblob"
2409 ;; Date/time functions
2410 "time" "julianday" "strftime"
2411 "current_date" "current_time" "current_timestamp"
2412 ;; Aggregate functions
2413 "avg" "count" "group_concat" "max" "min" "sum" "total"
2414 )))
2415
2416   "SQLite SQL keywords used by font-lock.
2417
2418 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2419 regular expressions are created during compilation by calling the
2420 function `regexp-opt'.  Therefore, take a look at the source before
2421 you define your own `sql-mode-sqlite-font-lock-keywords'.")
2422
2423 (defvar sql-mode-db2-font-lock-keywords nil
2424   "DB2 SQL keywords used by font-lock.
2425
2426 This variable is used by `sql-mode' and `sql-interactive-mode'.  The
2427 regular expressions are created during compilation by calling the
2428 function `regexp-opt'.  Therefore, take a look at the source before
2429 you define your own `sql-mode-db2-font-lock-keywords'.")
2430
2431 (defvar sql-mode-font-lock-keywords nil
2432   "SQL keywords used by font-lock.
2433
2434 Setting this variable directly no longer has any affect.  Use
2435 `sql-product' and `sql-add-product-keywords' to control the
2436 highlighting rules in SQL mode.")
2437
2438 \f
2439
2440 ;;; SQL Product support functions
2441
2442 (defun sql-read-product (prompt &optional initial)
2443   "Read a valid SQL product."
2444   (let ((init (or (and initial (symbol-name initial)) "ansi")))
2445     (intern (completing-read
2446              prompt
2447              (mapcar #'(lambda (info) (symbol-name (car info)))
2448                      sql-product-alist)
2449              nil 'require-match
2450              init 'sql-product-history init))))
2451
2452 (defun sql-add-product (product display &rest plist)
2453   "Add support for a database product in `sql-mode'.
2454
2455 Add PRODUCT to `sql-product-alist' which enables `sql-mode' to
2456 properly support syntax highlighting and interactive interaction.
2457 DISPLAY is the name of the SQL product that will appear in the
2458 menu bar and in messages.  PLIST initializes the product
2459 configuration."
2460
2461   ;; Don't do anything if the product is already supported
2462   (if (assoc product sql-product-alist)
2463       (user-error "Product `%s' is already defined" product)
2464
2465     ;; Add product to the alist
2466     (add-to-list 'sql-product-alist `(,product :name ,display . ,plist))
2467     ;; Add a menu item to the SQL->Product menu
2468     (easy-menu-add-item sql-mode-menu '("Product")
2469                         ;; Each product is represented by a radio
2470                         ;; button with it's display name.
2471                         `[,display
2472                           (sql-set-product ',product)
2473                          :style radio
2474                          :selected (eq sql-product ',product)]
2475                         ;; Maintain the product list in
2476                         ;; (case-insensitive) alphabetic order of the
2477                         ;; display names.  Loop thru each keymap item
2478                         ;; looking for an item whose display name is
2479                         ;; after this product's name.
2480                         (let ((next-item)
2481                               (down-display (downcase display)))
2482                           (map-keymap #'(lambda (k b)
2483                                           (when (and (not next-item)
2484                                                      (string-lessp down-display
2485                                                                    (downcase (cadr b))))
2486                                             (setq next-item k)))
2487                                       (easy-menu-get-map sql-mode-menu '("Product")))
2488                           next-item))
2489     product))
2490
2491 (defun sql-del-product (product)
2492   "Remove support for PRODUCT in `sql-mode'."
2493
2494   ;; Remove the menu item based on the display name
2495   (easy-menu-remove-item sql-mode-menu '("Product") (sql-get-product-feature product :name))
2496   ;; Remove the product alist item
2497   (setq sql-product-alist (assq-delete-all product sql-product-alist))
2498   nil)
2499
2500 (defun sql-set-product-feature (product feature newvalue)
2501   "Set FEATURE of database PRODUCT to NEWVALUE.
2502
2503 The PRODUCT must be a symbol which identifies the database
2504 product.  The product must have already exist on the product
2505 list.  See `sql-add-product' to add new products.  The FEATURE
2506 argument must be a plist keyword accepted by
2507 `sql-product-alist'."
2508
2509   (let* ((p (assoc product sql-product-alist))
2510          (v (plist-get (cdr p) feature)))
2511     (if p
2512         (if (and
2513              (member feature sql-indirect-features)
2514              (symbolp v))
2515             (set v newvalue)
2516           (setcdr p (plist-put (cdr p) feature newvalue)))
2517       (error "`%s' is not a known product; use `sql-add-product' to add it first." product))))
2518
2519 (defun sql-get-product-feature (product feature &optional fallback not-indirect)
2520   "Lookup FEATURE associated with a SQL PRODUCT.
2521
2522 If the FEATURE is nil for PRODUCT, and FALLBACK is specified,
2523 then the FEATURE associated with the FALLBACK product is
2524 returned.
2525
2526 If the FEATURE is in the list `sql-indirect-features', and the
2527 NOT-INDIRECT parameter is not set, then the value of the symbol
2528 stored in the connect alist is returned.
2529
2530 See `sql-product-alist' for a list of products and supported features."
2531   (let* ((p (assoc product sql-product-alist))
2532          (v (plist-get (cdr p) feature)))
2533
2534     (if p
2535         ;; If no value and fallback, lookup feature for fallback
2536         (if (and (not v)
2537                  fallback
2538                  (not (eq product fallback)))
2539             (sql-get-product-feature fallback feature)
2540
2541           (if (and
2542                (member feature sql-indirect-features)
2543                (not not-indirect)
2544                (symbolp v))
2545               (symbol-value v)
2546             v))
2547       (error "`%s' is not a known product; use `sql-add-product' to add it first." product)
2548       nil)))
2549
2550 (defun sql-product-font-lock (keywords-only imenu)
2551   "Configure font-lock and imenu with product-specific settings.
2552
2553 The KEYWORDS-ONLY flag is passed to font-lock to specify whether
2554 only keywords should be highlighted and syntactic highlighting
2555 skipped.  The IMENU flag indicates whether `imenu-mode' should
2556 also be configured."
2557
2558   (let
2559       ;; Get the product-specific syntax-alist.
2560       ((syntax-alist (sql-product-font-lock-syntax-alist)))
2561
2562     ;; Get the product-specific keywords.
2563     (set (make-local-variable 'sql-mode-font-lock-keywords)
2564          (append
2565           (unless (eq sql-product 'ansi)
2566             (sql-get-product-feature sql-product :font-lock))
2567           ;; Always highlight ANSI keywords
2568           (sql-get-product-feature 'ansi :font-lock)
2569           ;; Fontify object names in CREATE, DROP and ALTER DDL
2570           ;; statements
2571           (list sql-mode-font-lock-object-name)))
2572
2573     ;; Setup font-lock.  Force re-parsing of `font-lock-defaults'.
2574     (kill-local-variable 'font-lock-set-defaults)
2575     (set (make-local-variable 'font-lock-defaults)
2576          (list 'sql-mode-font-lock-keywords
2577                keywords-only t syntax-alist))
2578
2579     ;; Force font lock to reinitialize if it is already on
2580     ;; Otherwise, we can wait until it can be started.
2581     (when (and (fboundp 'font-lock-mode)
2582                (boundp 'font-lock-mode)
2583                font-lock-mode)
2584       (font-lock-mode-internal nil)
2585       (font-lock-mode-internal t))
2586
2587     (add-hook 'font-lock-mode-hook
2588               #'(lambda ()
2589                   ;; Provide defaults for new font-lock faces.
2590                   (defvar font-lock-builtin-face
2591                     (if (boundp 'font-lock-preprocessor-face)
2592                         font-lock-preprocessor-face
2593                       font-lock-keyword-face))
2594                   (defvar font-lock-doc-face font-lock-string-face))
2595               nil t)
2596
2597     ;; Setup imenu; it needs the same syntax-alist.
2598     (when imenu
2599       (setq imenu-syntax-alist syntax-alist))))
2600
2601 ;;;###autoload
2602 (defun sql-add-product-keywords (product keywords &optional append)
2603   "Add highlighting KEYWORDS for SQL PRODUCT.
2604
2605 PRODUCT should be a symbol, the name of a SQL product, such as
2606 `oracle'.  KEYWORDS should be a list; see the variable
2607 `font-lock-keywords'.  By default they are added at the beginning
2608 of the current highlighting list.  If optional argument APPEND is
2609 `set', they are used to replace the current highlighting list.
2610 If APPEND is any other non-nil value, they are added at the end
2611 of the current highlighting list.
2612
2613 For example:
2614
2615  (sql-add-product-keywords 'ms
2616   '((\"\\\\b\\\\w+_t\\\\b\" . font-lock-type-face)))
2617
2618 adds a fontification pattern to fontify identifiers ending in
2619 `_t' as data types."
2620
2621   (let* ((sql-indirect-features nil)
2622          (font-lock-var (sql-get-product-feature product :font-lock))
2623          (old-val))
2624
2625     (setq old-val (symbol-value font-lock-var))
2626     (set font-lock-var
2627          (if (eq append 'set)
2628              keywords
2629            (if append
2630                (append old-val keywords)
2631              (append keywords old-val))))))
2632
2633 (defun sql-for-each-login (login-params body)
2634   "Iterate through login parameters and return a list of results."
2635   (delq nil
2636         (mapcar
2637          #'(lambda (param)
2638              (let ((token (or (car-safe param) param))
2639                    (plist (cdr-safe param)))
2640                (funcall body token plist)))
2641          login-params)))
2642
2643 \f
2644
2645 ;;; Functions to switch highlighting
2646
2647 (defun sql-product-syntax-table ()
2648   (let ((table (copy-syntax-table sql-mode-syntax-table)))
2649     (mapc #'(lambda (entry)
2650               (modify-syntax-entry (car entry) (cdr entry) table))
2651           (sql-get-product-feature sql-product :syntax-alist))
2652     table))
2653
2654 (defun sql-product-font-lock-syntax-alist ()
2655   (append
2656    ;; Change all symbol character to word characters
2657    (mapcar
2658     #'(lambda (entry) (if (string= (substring (cdr entry) 0 1) "_")
2659                           (cons (car entry)
2660                                 (concat "w" (substring (cdr entry) 1)))
2661                         entry))
2662     (sql-get-product-feature sql-product :syntax-alist))
2663    '((?_ . "w"))))
2664
2665 (defun sql-highlight-product ()
2666   "Turn on the font highlighting for the SQL product selected."
2667   (when (derived-mode-p 'sql-mode)
2668     ;; Enhance the syntax table for the product
2669     (set-syntax-table (sql-product-syntax-table))
2670
2671     ;; Setup font-lock
2672     (sql-product-font-lock nil t)
2673
2674     ;; Set the mode name to include the product.
2675     (setq mode-name (concat "SQL[" (or (sql-get-product-feature sql-product :name)
2676                                        (symbol-name sql-product)) "]"))))
2677
2678 (defun sql-set-product (product)
2679   "Set `sql-product' to PRODUCT and enable appropriate highlighting."
2680   (interactive
2681    (list (sql-read-product "SQL product: ")))
2682   (if (stringp product) (setq product (intern product)))
2683   (when (not (assoc product sql-product-alist))
2684     (user-error "SQL product %s is not supported; treated as ANSI" product)
2685     (setq product 'ansi))
2686
2687   ;; Save product setting and fontify.
2688   (setq sql-product product)
2689   (sql-highlight-product))
2690 \f
2691
2692 ;;; Compatibility functions
2693
2694 (if (not (fboundp 'comint-line-beginning-position))
2695     ;; comint-line-beginning-position is defined in Emacs 21
2696     (defun comint-line-beginning-position ()
2697       "Return the buffer position of the beginning of the line, after any prompt.
2698 The prompt is assumed to be any text at the beginning of the line
2699 matching the regular expression `comint-prompt-regexp', a buffer
2700 local variable."
2701       (save-excursion (comint-bol nil) (point))))
2702
2703 ;;; SMIE support
2704
2705 ;; Needs a lot more love than I can provide.  --Stef
2706
2707 ;; (require 'smie)
2708
2709 ;; (defconst sql-smie-grammar
2710 ;;   (smie-prec2->grammar
2711 ;;    (smie-bnf->prec2
2712 ;;     ;; Partly based on http://www.h2database.com/html/grammar.html
2713 ;;     '((cmd ("SELECT" select-exp "FROM" select-table-exp)
2714 ;;            )
2715 ;;       (select-exp ("*") (exp) (exp "AS" column-alias))
2716 ;;       (column-alias)
2717 ;;       (select-table-exp (table-exp "WHERE" exp) (table-exp))
2718 ;;       (table-exp)
2719 ;;       (exp ("CASE" exp "WHEN" exp "THEN" exp "ELSE" exp "END")
2720 ;;            ("CASE" exp "WHEN" exp "THEN" exp "END"))
2721 ;;       ;; Random ad-hoc additions.
2722 ;;       (foo (foo "," foo))
2723 ;;       )
2724 ;;     '((assoc ",")))))
2725
2726 ;; (defun sql-smie-rules (kind token)
2727 ;;   (pcase (cons kind token)
2728 ;;     (`(:list-intro . ,_) t)
2729 ;;     (`(:before . "(") (smie-rule-parent))))
2730
2731 ;;; Motion Functions
2732
2733 (defun sql-statement-regexp (prod)
2734   (let* ((ansi-stmt (sql-get-product-feature 'ansi :statement))
2735          (prod-stmt (sql-get-product-feature prod  :statement)))
2736     (concat "^\\<"
2737             (if prod-stmt
2738                 ansi-stmt
2739               (concat "\\(" ansi-stmt "\\|" prod-stmt "\\)"))
2740             "\\>")))
2741
2742 (defun sql-beginning-of-statement (arg)
2743   "Move to the beginning of the current SQL statement."
2744   (interactive "p")
2745
2746   (let ((here (point))
2747         (regexp (sql-statement-regexp sql-product))
2748         last next)
2749
2750     ;; Go to the end of the statement before the start we desire
2751     (setq last (or (sql-end-of-statement (- arg))
2752                    (point-min)))
2753     ;; And find the end after that
2754     (setq next (or (sql-end-of-statement 1)
2755                    (point-max)))
2756
2757     ;; Our start must be between them
2758     (goto-char last)
2759     ;; Find an beginning-of-stmt that's not in a comment
2760     (while (and (re-search-forward regexp next t 1)
2761                 (nth 7 (syntax-ppss)))
2762       (goto-char (match-end 0)))
2763     (goto-char
2764      (if (match-data)
2765         (match-beginning 0)
2766        last))
2767     (beginning-of-line)
2768     ;; If we didn't move, try again
2769     (when (= here (point))
2770       (sql-beginning-of-statement (* 2 (cl-signum arg))))))
2771
2772 (defun sql-end-of-statement (arg)
2773   "Move to the end of the current SQL statement."
2774   (interactive "p")
2775   (let ((term (sql-get-product-feature sql-product :terminator))
2776         (re-search (if (> 0 arg) 're-search-backward 're-search-forward))
2777         (here (point))
2778         (n 0))
2779     (when (consp term)
2780       (setq term (car term)))
2781     ;; Iterate until we've moved the desired number of stmt ends
2782     (while (not (= (cl-signum arg) 0))
2783       ;; if we're looking at the terminator, jump by 2
2784       (if (or (and (> 0 arg) (looking-back term))
2785               (and (< 0 arg) (looking-at term)))
2786           (setq n 2)
2787         (setq n 1))
2788       ;; If we found another end-of-stmt
2789       (if (not (apply re-search term nil t n nil))
2790           (setq arg 0)
2791         ;; count it if we're not in a comment
2792         (unless (nth 7 (syntax-ppss))
2793           (setq arg (- arg (cl-signum arg))))))
2794     (goto-char (if (match-data)
2795                    (match-end 0)
2796                  here))))
2797
2798 ;;; Small functions
2799
2800 (defun sql-magic-go (arg)
2801   "Insert \"o\" and call `comint-send-input'.
2802 `sql-electric-stuff' must be the symbol `go'."
2803   (interactive "P")
2804   (self-insert-command (prefix-numeric-value arg))
2805   (if (and (equal sql-electric-stuff 'go)
2806            (save-excursion
2807              (comint-bol nil)
2808              (looking-at "go\\b")))
2809       (comint-send-input)))
2810 (put 'sql-magic-go 'delete-selection t)
2811
2812 (defun sql-magic-semicolon (arg)
2813   "Insert semicolon and call `comint-send-input'.
2814 `sql-electric-stuff' must be the symbol `semicolon'."
2815   (interactive "P")
2816   (self-insert-command (prefix-numeric-value arg))
2817   (if (equal sql-electric-stuff 'semicolon)
2818        (comint-send-input)))
2819 (put 'sql-magic-semicolon 'delete-selection t)
2820
2821 (defun sql-accumulate-and-indent ()
2822   "Continue SQL statement on the next line."
2823   (interactive)
2824   (if (fboundp 'comint-accumulate)
2825       (comint-accumulate)
2826     (newline))
2827   (indent-according-to-mode))
2828
2829 (defun sql-help-list-products (indent freep)
2830   "Generate listing of products available for use under SQLi.
2831
2832 List products with :free-software attribute set to FREEP.  Indent
2833 each line with INDENT."
2834
2835   (let (sqli-func doc)
2836     (setq doc "")
2837     (dolist (p sql-product-alist)
2838       (setq sqli-func (intern (concat "sql-" (symbol-name (car p)))))
2839
2840       (if (and (fboundp sqli-func)
2841                (eq (sql-get-product-feature (car p) :free-software) freep))
2842         (setq doc
2843               (concat doc
2844                       indent
2845                       (or (sql-get-product-feature (car p) :name)
2846                           (symbol-name (car p)))
2847                       ":\t"
2848                       "\\["
2849                       (symbol-name sqli-func)
2850                       "]\n"))))
2851     doc))
2852
2853 (defun sql-help ()
2854   "Show short help for the SQL modes."
2855   (interactive)
2856   (describe-function 'sql-help))
2857 (put 'sql-help 'function-documentation '(sql--make-help-docstring))
2858
2859 (defvar sql--help-docstring
2860   "Show short help for the SQL modes.
2861 Use an entry function to open an interactive SQL buffer.  This buffer is
2862 usually named `*SQL*'.  The name of the major mode is SQLi.
2863
2864 Use the following commands to start a specific SQL interpreter:
2865
2866     \\\\FREE
2867
2868 Other non-free SQL implementations are also supported:
2869
2870     \\\\NONFREE
2871
2872 But we urge you to choose a free implementation instead of these.
2873
2874 You can also use \\[sql-product-interactive] to invoke the
2875 interpreter for the current `sql-product'.
2876
2877 Once you have the SQLi buffer, you can enter SQL statements in the
2878 buffer.  The output generated is appended to the buffer and a new prompt
2879 is generated.  See the In/Out menu in the SQLi buffer for some functions
2880 that help you navigate through the buffer, the input history, etc.
2881
2882 If you have a really complex SQL statement or if you are writing a
2883 procedure, you can do this in a separate buffer.  Put the new buffer in
2884 `sql-mode' by calling \\[sql-mode].  The name of this buffer can be
2885 anything.  The name of the major mode is SQL.
2886
2887 In this SQL buffer (SQL mode), you can send the region or the entire
2888 buffer to the interactive SQL buffer (SQLi mode).  The results are
2889 appended to the SQLi buffer without disturbing your SQL buffer.")
2890
2891 (defun sql--make-help-docstring ()
2892   "Return a docstring for `sql-help' listing loaded SQL products."
2893   (let ((doc sql--help-docstring))
2894     ;; Insert FREE software list
2895     (when (string-match "^\\(\\s-*\\)[\\\\][\\\\]FREE\\s-*$" doc 0)
2896       (setq doc (replace-match (sql-help-list-products (match-string 1 doc) t)
2897                                t t doc 0)))
2898     ;; Insert non-FREE software list
2899     (when (string-match "^\\(\\s-*\\)[\\\\][\\\\]NONFREE\\s-*$" doc 0)
2900       (setq doc (replace-match (sql-help-list-products (match-string 1 doc) nil)
2901                                t t doc 0)))
2902     doc))
2903
2904 (defun sql-default-value (var)
2905   "Fetch the value of a variable.
2906
2907 If the current buffer is in `sql-interactive-mode', then fetch
2908 the global value, otherwise use the buffer local value."
2909   (if (derived-mode-p 'sql-interactive-mode)
2910       (default-value var)
2911     (buffer-local-value var (current-buffer))))
2912
2913 (defun sql-get-login-ext (symbol prompt history-var plist)
2914   "Prompt user with extended login parameters.
2915
2916 The global value of SYMBOL is the last value and the global value
2917 of the SYMBOL is set based on the user's input.
2918
2919 If PLIST is nil, then the user is simply prompted for a string
2920 value.
2921
2922 The property `:default' specifies the default value.  If the
2923 `:number' property is non-nil then ask for a number.
2924
2925 The `:file' property prompts for a file name that must match the
2926 regexp pattern specified in its value.
2927
2928 The `:completion' property prompts for a string specified by its
2929 value.  (The property value is used as the PREDICATE argument to
2930 `completing-read'.)"
2931   (set-default
2932    symbol
2933    (let* ((default (plist-get plist :default))
2934           (last-value (sql-default-value symbol))
2935           (prompt-def
2936            (if default
2937                (if (string-match "\\(\\):[ \t]*\\'" prompt)
2938                    (replace-match (format " (default \"%s\")" default) t t prompt 1)
2939                  (replace-regexp-in-string "[ \t]*\\'"
2940                                            (format " (default \"%s\") " default)
2941                                            prompt t t))
2942              prompt))
2943           (use-dialog-box nil))
2944      (cond
2945       ((plist-member plist :file)
2946        (expand-file-name
2947         (read-file-name prompt
2948                         (file-name-directory last-value) default t
2949                         (file-name-nondirectory last-value)
2950                         (when (plist-get plist :file)
2951                           `(lambda (f)
2952                              (string-match
2953                               (concat "\\<" ,(plist-get plist :file) "\\>")
2954                               (file-name-nondirectory f)))))))
2955
2956       ((plist-member plist :completion)
2957        (completing-read prompt-def (plist-get plist :completion) nil t
2958                         last-value history-var default))
2959
2960       ((plist-get plist :number)
2961        (read-number prompt (or default last-value 0)))
2962
2963       (t
2964        (read-string prompt-def last-value history-var default))))))
2965
2966 (defun sql-get-login (&rest what)
2967   "Get username, password and database from the user.
2968
2969 The variables `sql-user', `sql-password', `sql-server', and
2970 `sql-database' can be customized.  They are used as the default values.
2971 Usernames, servers and databases are stored in `sql-user-history',
2972 `sql-server-history' and `database-history'.  Passwords are not stored
2973 in a history.
2974
2975 Parameter WHAT is a list of tokens passed as arguments in the
2976 function call.  The function asks for the username if WHAT
2977 contains the symbol `user', for the password if it contains the
2978 symbol `password', for the server if it contains the symbol
2979 `server', and for the database if it contains the symbol
2980 `database'.  The members of WHAT are processed in the order in
2981 which they are provided.
2982
2983 Each token may also be a list with the token in the car and a
2984 plist of options as the cdr.  The following properties are
2985 supported:
2986
2987     :file <filename-regexp>
2988     :completion <list-of-strings-or-function>
2989     :default <default-value>
2990     :number t
2991
2992 In order to ask the user for username, password and database, call the
2993 function like this: (sql-get-login 'user 'password 'database)."
2994   (dolist (w what)
2995     (let ((plist (cdr-safe w)))
2996       (pcase (or (car-safe w) w)
2997         (`user
2998          (sql-get-login-ext 'sql-user "User: " 'sql-user-history plist))
2999
3000         (`password
3001          (setq-default sql-password
3002                        (read-passwd "Password: " nil (sql-default-value 'sql-password))))
3003
3004         (`server
3005          (sql-get-login-ext 'sql-server "Server: " 'sql-server-history plist))
3006
3007         (`database
3008          (sql-get-login-ext 'sql-database "Database: "
3009                             'sql-database-history plist))
3010
3011         (`port
3012          (sql-get-login-ext 'sql-port "Port: "
3013                             nil (append '(:number t) plist)))))))
3014
3015 (defun sql-find-sqli-buffer (&optional product connection)
3016   "Return the name of the current default SQLi buffer or nil.
3017 In order to qualify, the SQLi buffer must be alive, be in
3018 `sql-interactive-mode' and have a process."
3019   (let ((buf  sql-buffer)
3020         (prod (or product sql-product)))
3021     (or
3022      ;; Current sql-buffer, if there is one.
3023      (and (sql-buffer-live-p buf prod connection)
3024           buf)
3025      ;; Global sql-buffer
3026      (and (setq buf (default-value 'sql-buffer))
3027           (sql-buffer-live-p buf prod connection)
3028           buf)
3029      ;; Look thru each buffer
3030      (car (apply #'append
3031                  (mapcar #'(lambda (b)
3032                              (and (sql-buffer-live-p b prod connection)
3033                                   (list (buffer-name b))))
3034                          (buffer-list)))))))
3035
3036 (defun sql-set-sqli-buffer-generally ()
3037   "Set SQLi buffer for all SQL buffers that have none.
3038 This function checks all SQL buffers for their SQLi buffer.  If their
3039 SQLi buffer is nonexistent or has no process, it is set to the current
3040 default SQLi buffer.  The current default SQLi buffer is determined
3041 using `sql-find-sqli-buffer'.  If `sql-buffer' is set,
3042 `sql-set-sqli-hook' is run."
3043   (interactive)
3044   (save-excursion
3045     (let ((buflist (buffer-list))
3046           (default-buffer (sql-find-sqli-buffer)))
3047       (setq-default sql-buffer default-buffer)
3048       (while (not (null buflist))
3049         (let ((candidate (car buflist)))
3050           (set-buffer candidate)
3051           (if (and (derived-mode-p 'sql-mode)
3052                    (not (sql-buffer-live-p sql-buffer)))
3053               (progn
3054                 (setq sql-buffer default-buffer)
3055                 (when default-buffer
3056                   (run-hooks 'sql-set-sqli-hook)))))
3057         (setq buflist (cdr buflist))))))
3058
3059 (defun sql-set-sqli-buffer ()
3060   "Set the SQLi buffer SQL strings are sent to.
3061
3062 Call this function in a SQL buffer in order to set the SQLi buffer SQL
3063 strings are sent to.  Calling this function sets `sql-buffer' and runs
3064 `sql-set-sqli-hook'.
3065
3066 If you call it from a SQL buffer, this sets the local copy of
3067 `sql-buffer'.
3068
3069 If you call it from anywhere else, it sets the global copy of
3070 `sql-buffer'."
3071   (interactive)
3072   (let ((default-buffer (sql-find-sqli-buffer)))
3073     (if (null default-buffer)
3074         (sql-product-interactive)
3075       (let ((new-buffer (read-buffer "New SQLi buffer: " default-buffer t)))
3076         (if (null (sql-buffer-live-p new-buffer))
3077             (user-error "Buffer %s is not a working SQLi buffer" new-buffer)
3078           (when new-buffer
3079             (setq sql-buffer new-buffer)
3080             (run-hooks 'sql-set-sqli-hook)))))))
3081
3082 (defun sql-show-sqli-buffer ()
3083   "Display the current SQLi buffer.
3084
3085 This is the buffer SQL strings are sent to.
3086 It is stored in the variable `sql-buffer'.
3087 I
3088 See also `sql-help' on how to create such a buffer."
3089   (interactive)
3090   (unless (and sql-buffer (buffer-live-p (get-buffer sql-buffer))
3091                (get-buffer-process sql-buffer))
3092     (sql-set-sqli-buffer))
3093   (display-buffer sql-buffer))
3094
3095 (defun sql-make-alternate-buffer-name ()
3096   "Return a string that can be used to rename a SQLi buffer.
3097 This is used to set `sql-alternate-buffer-name' within
3098 `sql-interactive-mode'.
3099
3100 If the session was started with `sql-connect' then the alternate
3101 name would be the name of the connection.
3102
3103 Otherwise, it uses the parameters identified by the :sqlilogin
3104 parameter.
3105
3106 If all else fails, the alternate name would be the user and
3107 server/database name."
3108
3109   (let ((name ""))
3110
3111     ;; Build a name using the :sqli-login setting
3112     (setq name
3113           (apply #'concat
3114                  (cdr
3115                   (apply #'append nil
3116                          (sql-for-each-login
3117                           (sql-get-product-feature sql-product :sqli-login)
3118                           #'(lambda (token plist)
3119                               (pcase token
3120                                 (`user
3121                                  (unless (string= "" sql-user)
3122                                    (list "/" sql-user)))
3123                                 (`port
3124                                  (unless (or (not (numberp sql-port))
3125                                              (= 0 sql-port))
3126                                    (list ":" (number-to-string sql-port))))
3127                                 (`server
3128                                  (unless (string= "" sql-server)
3129                                    (list "."
3130                                          (if (plist-member plist :file)
3131                                              (file-name-nondirectory sql-server)
3132                                            sql-server))))
3133                                 (`database
3134                                  (unless (string= "" sql-database)
3135                                    (list "@"
3136                                          (if (plist-member plist :file)
3137                                              (file-name-nondirectory sql-database)
3138                                            sql-database))))
3139
3140                                 ;; (`password nil)
3141                                 (_         nil))))))))
3142
3143     ;; If there's a connection, use it and the name thus far
3144     (if sql-connection
3145         (format "<%s>%s" sql-connection (or name ""))
3146
3147       ;; If there is no name, try to create something meaningful
3148       (if (string= "" (or name ""))
3149           (concat
3150            (if (string= "" sql-user)
3151                (if (string= "" (user-login-name))
3152                    ()
3153                  (concat (user-login-name) "/"))
3154              (concat sql-user "/"))
3155            (if (string= "" sql-database)
3156                (if (string= "" sql-server)
3157                (system-name)
3158                sql-server)
3159              sql-database))
3160
3161         ;; Use the name we've got
3162         name))))
3163
3164 (defun sql-rename-buffer (&optional new-name)
3165   "Rename a SQL interactive buffer.
3166
3167 Prompts for the new name if command is preceded by
3168 \\[universal-argument].  If no buffer name is provided, then the
3169 `sql-alternate-buffer-name' is used.
3170
3171 The actual buffer name set will be \"*SQL: NEW-NAME*\".  If
3172 NEW-NAME is empty, then the buffer name will be \"*SQL*\"."
3173   (interactive "P")
3174
3175   (if (not (derived-mode-p 'sql-interactive-mode))
3176       (user-error "Current buffer is not a SQL interactive buffer")
3177
3178     (setq sql-alternate-buffer-name
3179           (cond
3180            ((stringp new-name) new-name)
3181            ((consp new-name)
3182             (read-string "Buffer name (\"*SQL: XXX*\"; enter `XXX'): "
3183                          sql-alternate-buffer-name))
3184            (t                  sql-alternate-buffer-name)))
3185
3186     (setq sql-alternate-buffer-name (substring-no-properties sql-alternate-buffer-name))
3187     (rename-buffer (if (string= "" sql-alternate-buffer-name)
3188                        "*SQL*"
3189                      (format "*SQL: %s*" sql-alternate-buffer-name))
3190                    t)))
3191
3192 (defun sql-copy-column ()
3193   "Copy current column to the end of buffer.
3194 Inserts SELECT or commas if appropriate."
3195   (interactive)
3196   (let ((column))
3197     (save-excursion
3198       (setq column (buffer-substring-no-properties
3199                   (progn (forward-char 1) (backward-sexp 1) (point))
3200                   (progn (forward-sexp 1) (point))))
3201       (goto-char (point-max))
3202       (let ((bol (comint-line-beginning-position)))
3203         (cond
3204          ;; if empty command line, insert SELECT
3205          ((= bol (point))
3206           (insert "SELECT "))
3207          ;; else if appending to INTO .* (, SELECT or ORDER BY, insert a comma
3208          ((save-excursion
3209             (re-search-backward "\\b\\(\\(into\\s-+\\S-+\\s-+(\\)\\|select\\|order by\\) .+"
3210                                 bol t))
3211           (insert ", "))
3212          ;; else insert a space
3213          (t
3214           (if (eq (preceding-char) ?\s)
3215               nil
3216             (insert " ")))))
3217       ;; in any case, insert the column
3218       (insert column)
3219       (message "%s" column))))
3220
3221 ;; On Windows, SQL*Plus for Oracle turns on full buffering for stdout
3222 ;; if it is not attached to a character device; therefore placeholder
3223 ;; replacement by SQL*Plus is fully buffered.  The workaround lets
3224 ;; Emacs query for the placeholders.
3225
3226 (defvar sql-placeholder-history nil
3227   "History of placeholder values used.")
3228
3229 (defun sql-placeholders-filter (string)
3230   "Replace placeholders in STRING.
3231 Placeholders are words starting with an ampersand like &this."
3232
3233   (when sql-oracle-scan-on
3234     (while (string-match "&?&\\(\\(?:\\sw\\|\\s_\\)+\\)[.]?" string)
3235       (setq string (replace-match
3236                     (read-from-minibuffer
3237                      (format "Enter value for %s: " (match-string 1 string))
3238                      nil nil nil 'sql-placeholder-history)
3239                     t t string))))
3240   string)
3241
3242 ;; Using DB2 interactively, newlines must be escaped with " \".
3243 ;; The space before the backslash is relevant.
3244
3245 (defun sql-escape-newlines-filter (string)
3246   "Escape newlines in STRING.
3247 Every newline in STRING will be preceded with a space and a backslash."
3248   (if (not sql-db2-escape-newlines)
3249       string
3250     (let ((result "") (start 0) mb me)
3251       (while (string-match "\n" string start)
3252         (setq mb (match-beginning 0)
3253               me (match-end 0)
3254               result (concat result
3255                              (substring string start mb)
3256                              (if (and (> mb 1)
3257                                       (string-equal " \\" (substring string (- mb 2) mb)))
3258                                  "" " \\\n"))
3259               start me))
3260       (concat result (substring string start)))))
3261
3262 \f
3263
3264 ;;; Input sender for SQLi buffers
3265
3266 (defvar sql-output-newline-count 0
3267   "Number of newlines in the input string.
3268
3269 Allows the suppression of continuation prompts.")
3270
3271 (defun sql-input-sender (proc string)
3272   "Send STRING to PROC after applying filters."
3273
3274   (let* ((product (buffer-local-value 'sql-product (process-buffer proc)))
3275          (filter  (sql-get-product-feature product :input-filter)))
3276
3277     ;; Apply filter(s)
3278     (cond
3279      ((not filter)
3280       nil)
3281      ((functionp filter)
3282       (setq string (funcall filter string)))
3283      ((listp filter)
3284       (mapc #'(lambda (f) (setq string (funcall f string))) filter))
3285      (t nil))
3286
3287     ;; Count how many newlines in the string
3288     (setq sql-output-newline-count
3289           (apply #'+ (mapcar #'(lambda (ch)
3290                                 (if (eq ch ?\n) 1 0)) string)))
3291
3292     ;; Send the string
3293     (comint-simple-send proc string)))
3294
3295 ;;; Strip out continuation prompts
3296
3297 (defvar sql-preoutput-hold nil)
3298
3299 (defun sql-starts-with-prompt-re ()
3300   "Anchor the prompt expression at the beginning of the output line.
3301 Remove the start of line regexp."
3302   (replace-regexp-in-string "\\^" "\\\\`" comint-prompt-regexp))
3303
3304 (defun sql-ends-with-prompt-re ()
3305   "Anchor the prompt expression at the end of the output line.
3306 Remove the start of line regexp from the prompt expression since
3307 it may not follow newline characters in the output line."
3308   (concat (replace-regexp-in-string "\\^" "" sql-prompt-regexp) "\\'"))
3309
3310 (defun sql-interactive-remove-continuation-prompt (oline)
3311   "Strip out continuation prompts out of the OLINE.
3312
3313 Added to the `comint-preoutput-filter-functions' hook in a SQL
3314 interactive buffer.  If `sql-output-newline-count' is greater than
3315 zero, then an output line matching the continuation prompt is filtered
3316 out.  If the count is zero, then a newline is inserted into the output
3317 to force the output from the query to appear on a new line.
3318
3319 The complication to this filter is that the continuation prompts
3320 may arrive in multiple chunks.  If they do, then the function
3321 saves any unfiltered output in a buffer and prepends that buffer
3322 to the next chunk to properly match the broken-up prompt.
3323
3324 If the filter gets confused, it should reset and stop filtering
3325 to avoid deleting non-prompt output."
3326
3327   (when comint-prompt-regexp
3328     (save-match-data
3329       (let (prompt-found last-nl)
3330
3331         ;; Add this text to what's left from the last pass
3332         (setq oline (concat sql-preoutput-hold oline)
3333               sql-preoutput-hold "")
3334
3335         ;; If we are looking for multiple prompts
3336         (when (and (integerp sql-output-newline-count)
3337                    (>= sql-output-newline-count 1))
3338           ;; Loop thru each starting prompt and remove it
3339           (let ((start-re (sql-starts-with-prompt-re)))
3340             (while (and (not (string= oline ""))
3341                       (> sql-output-newline-count 0)
3342                       (string-match start-re oline))
3343               (setq oline (replace-match "" nil nil oline)
3344                     sql-output-newline-count (1- sql-output-newline-count)
3345                     prompt-found t)))
3346
3347           ;; If we've found all the expected prompts, stop looking
3348           (if (= sql-output-newline-count 0)
3349               (setq sql-output-newline-count nil
3350                     oline (concat "\n" oline))
3351
3352             ;; Still more possible prompts, leave them for the next pass
3353             (setq sql-preoutput-hold oline
3354                   oline "")))
3355
3356         ;; If no prompts were found, stop looking
3357         (unless prompt-found
3358           (setq sql-output-newline-count nil
3359                 oline (concat oline sql-preoutput-hold)
3360                 sql-preoutput-hold ""))
3361
3362         ;; Break up output by physical lines if we haven't hit the final prompt
3363         (unless (and (not (string= oline ""))
3364                      (string-match (sql-ends-with-prompt-re) oline)
3365                      (>= (match-end 0) (length oline)))
3366           (setq last-nl 0)
3367           (while (string-match "\n" oline last-nl)
3368             (setq last-nl (match-end 0)))
3369           (setq sql-preoutput-hold (concat (substring oline last-nl)
3370                                            sql-preoutput-hold)
3371                 oline (substring oline 0 last-nl))))))
3372    oline)
3373
3374 ;;; Sending the region to the SQLi buffer.
3375
3376 (defun sql-send-string (str)
3377   "Send the string STR to the SQL process."
3378   (interactive "sSQL Text: ")
3379
3380   (let ((comint-input-sender-no-newline nil)
3381         (s (replace-regexp-in-string "[[:space:]\n\r]+\\'" "" str)))
3382     (if (sql-buffer-live-p sql-buffer)
3383         (progn
3384           ;; Ignore the hoping around...
3385           (save-excursion
3386             ;; Set product context
3387             (with-current-buffer sql-buffer
3388               ;; Send the string (trim the trailing whitespace)
3389               (sql-input-sender (get-buffer-process sql-buffer) s)
3390
3391               ;; Send a command terminator if we must
3392               (if sql-send-terminator
3393                   (sql-send-magic-terminator sql-buffer s sql-send-terminator))
3394
3395               (message "Sent string to buffer %s" sql-buffer)))
3396
3397           ;; Display the sql buffer
3398           (if sql-pop-to-buffer-after-send-region
3399               (pop-to-buffer sql-buffer)
3400             (display-buffer sql-buffer)))
3401
3402     ;; We don't have no stinkin' sql
3403     (user-error "No SQL process started"))))
3404
3405 (defun sql-send-region (start end)
3406   "Send a region to the SQL process."
3407   (interactive "r")
3408   (sql-send-string (buffer-substring-no-properties start end)))
3409
3410 (defun sql-send-paragraph ()
3411   "Send the current paragraph to the SQL process."
3412   (interactive)
3413   (let ((start (save-excursion
3414                  (backward-paragraph)
3415                  (point)))
3416         (end (save-excursion
3417                (forward-paragraph)
3418                (point))))
3419     (sql-send-region start end)))
3420
3421 (defun sql-send-buffer ()
3422   "Send the buffer contents to the SQL process."
3423   (interactive)
3424   (sql-send-region (point-min) (point-max)))
3425
3426 (defun sql-send-line-and-next ()
3427   "Send the current line to the SQL process and go to the next line."
3428   (interactive)
3429   (sql-send-region (line-beginning-position 1) (line-beginning-position 2))
3430   (beginning-of-line 2)
3431   (while (forward-comment 1)))  ; skip all comments and whitespace
3432
3433 (defun sql-send-magic-terminator (buf str terminator)
3434   "Send TERMINATOR to buffer BUF if its not present in STR."
3435   (let (comint-input-sender-no-newline pat term)
3436     ;; If flag is merely on(t), get product-specific terminator
3437     (if (eq terminator t)
3438         (setq terminator (sql-get-product-feature sql-product :terminator)))
3439
3440     ;; If there is no terminator specified, use default ";"
3441     (unless terminator
3442       (setq terminator ";"))
3443
3444     ;; Parse the setting into the pattern and the terminator string
3445     (cond ((stringp terminator)
3446            (setq pat (regexp-quote terminator)
3447                  term terminator))
3448           ((consp terminator)
3449            (setq pat (car terminator)
3450                  term (cdr terminator)))
3451           (t
3452            nil))
3453
3454     ;; Check to see if the pattern is present in the str already sent
3455     (unless (and pat term
3456                  (string-match (concat pat "\\'") str))
3457       (comint-simple-send (get-buffer-process buf) term)
3458       (setq sql-output-newline-count
3459             (if sql-output-newline-count
3460                 (1+ sql-output-newline-count)
3461               1)))))
3462
3463 (defun sql-remove-tabs-filter (str)
3464   "Replace tab characters with spaces."
3465   (replace-regexp-in-string "\t" " " str nil t))
3466
3467 (defun sql-toggle-pop-to-buffer-after-send-region (&optional value)
3468   "Toggle `sql-pop-to-buffer-after-send-region'.
3469
3470 If given the optional parameter VALUE, sets
3471 `sql-toggle-pop-to-buffer-after-send-region' to VALUE."
3472   (interactive "P")
3473   (if value
3474       (setq sql-pop-to-buffer-after-send-region value)
3475     (setq sql-pop-to-buffer-after-send-region
3476           (null sql-pop-to-buffer-after-send-region))))
3477
3478 \f
3479
3480 ;;; Redirect output functions
3481
3482 (defvar sql-debug-redirect nil
3483   "If non-nil, display messages related to the use of redirection.")
3484
3485 (defun sql-str-literal (s)
3486   (concat "'" (replace-regexp-in-string "[']" "''" s) "'"))
3487
3488 (defun sql-redirect (sqlbuf command &optional outbuf save-prior)
3489   "Execute the SQL command and send output to OUTBUF.
3490
3491 SQLBUF must be an active SQL interactive buffer.  OUTBUF may be
3492 an existing buffer, or the name of a non-existing buffer.  If
3493 omitted the output is sent to a temporary buffer which will be
3494 killed after the command completes.  COMMAND should be a string
3495 of commands accepted by the SQLi program.  COMMAND may also be a
3496 list of SQLi command strings."
3497
3498   (let* ((visible (and outbuf
3499                        (not (string= " " (substring outbuf 0 1))))))
3500     (when visible
3501       (message "Executing SQL command..."))
3502     (if (consp command)
3503         (mapc #'(lambda (c) (sql-redirect-one sqlbuf c outbuf save-prior))
3504               command)
3505       (sql-redirect-one sqlbuf command outbuf save-prior))
3506     (when visible
3507       (message "Executing SQL command...done"))))
3508
3509 (defun sql-redirect-one (sqlbuf command outbuf save-prior)
3510   (with-current-buffer sqlbuf
3511     (let ((buf  (get-buffer-create (or outbuf " *SQL-Redirect*")))
3512           (proc (get-buffer-process (current-buffer)))
3513           (comint-prompt-regexp (sql-get-product-feature sql-product
3514                                                          :prompt-regexp))
3515           (start nil))
3516       (with-current-buffer buf
3517         (setq-local view-no-disable-on-exit t)
3518         (read-only-mode -1)
3519         (unless save-prior
3520           (erase-buffer))
3521         (goto-char (point-max))
3522         (unless (zerop (buffer-size))
3523           (insert "\n"))
3524         (setq start (point)))
3525
3526       (when sql-debug-redirect
3527         (message ">>SQL> %S" command))
3528
3529       ;; Run the command
3530       (comint-redirect-send-command-to-process command buf proc nil t)
3531       (while (null comint-redirect-completed)
3532         (accept-process-output nil 1))
3533
3534       ;; Clean up the output results
3535       (with-current-buffer buf
3536         ;; Remove trailing whitespace
3537         (goto-char (point-max))
3538         (when (looking-back "[ \t\f\n\r]*" start)
3539           (delete-region (match-beginning 0) (match-end 0)))
3540         ;; Remove echo if there was one
3541         (goto-char start)
3542         (when (looking-at (concat "^" (regexp-quote command) "[\\n]"))
3543           (delete-region (match-beginning 0) (match-end 0)))
3544         ;; Remove Ctrl-Ms
3545         (goto-char start)
3546         (while (re-search-forward "\r+$" nil t)
3547           (replace-match "" t t))
3548         (goto-char start)))))
3549
3550 (defun sql-redirect-value (sqlbuf command regexp &optional regexp-groups)
3551   "Execute the SQL command and return part of result.
3552
3553 SQLBUF must be an active SQL interactive buffer.  COMMAND should
3554 be a string of commands accepted by the SQLi program.  From the
3555 output, the REGEXP is repeatedly matched and the list of
3556 REGEXP-GROUPS submatches is returned.  This behaves much like
3557 \\[comint-redirect-results-list-from-process] but instead of
3558 returning a single submatch it returns a list of each submatch
3559 for each match."
3560
3561   (let ((outbuf " *SQL-Redirect-values*")
3562         (results nil))
3563     (sql-redirect sqlbuf command outbuf nil)
3564     (with-current-buffer outbuf
3565       (while (re-search-forward regexp nil t)
3566         (push
3567          (cond
3568           ;; no groups-return all of them
3569           ((null regexp-groups)
3570            (let ((i (/ (length (match-data)) 2))
3571                  (r nil))
3572              (while (> i 0)
3573                (setq i (1- i))
3574                (push (match-string i) r))
3575              r))
3576           ;; one group specified
3577           ((numberp regexp-groups)
3578            (match-string regexp-groups))
3579           ;; list of numbers; return the specified matches only
3580           ((consp regexp-groups)
3581            (mapcar #'(lambda (c)
3582                        (cond
3583                         ((numberp c) (match-string c))
3584                         ((stringp c) (match-substitute-replacement c))
3585                         (t (error "sql-redirect-value: unknown REGEXP-GROUPS value - %s" c))))
3586                    regexp-groups))
3587           ;; String is specified; return replacement string
3588           ((stringp regexp-groups)
3589            (match-substitute-replacement regexp-groups))
3590           (t
3591            (error "sql-redirect-value: unknown REGEXP-GROUPS value - %s"
3592                   regexp-groups)))
3593          results)))
3594
3595     (when sql-debug-redirect
3596       (message ">>SQL> = %S" (reverse results)))
3597
3598     (nreverse results)))
3599
3600 (defun sql-execute (sqlbuf outbuf command enhanced arg)
3601   "Execute a command in a SQL interactive buffer and capture the output.
3602
3603 The commands are run in SQLBUF and the output saved in OUTBUF.
3604 COMMAND must be a string, a function or a list of such elements.
3605 Functions are called with SQLBUF, OUTBUF and ARG as parameters;
3606 strings are formatted with ARG and executed.
3607
3608 If the results are empty the OUTBUF is deleted, otherwise the
3609 buffer is popped into a view window."
3610   (mapc
3611    #'(lambda (c)
3612        (cond
3613         ((stringp c)
3614          (sql-redirect sqlbuf (if arg (format c arg) c) outbuf) t)
3615         ((functionp c)
3616          (apply c sqlbuf outbuf enhanced arg nil))
3617         (t (error "Unknown sql-execute item %s" c))))
3618    (if (consp command) command (cons command nil)))
3619
3620   (setq outbuf (get-buffer outbuf))
3621   (if (zerop (buffer-size outbuf))
3622       (kill-buffer outbuf)
3623     (let ((one-win (eq (selected-window)
3624                        (get-lru-window))))
3625       (with-current-buffer outbuf
3626         (set-buffer-modified-p nil)
3627         (setq-local revert-buffer-function
3628                     (lambda (_ignore-auto _noconfirm)
3629                       (sql-execute sqlbuf (buffer-name outbuf)
3630                                    command enhanced arg)))
3631         (special-mode))
3632       (pop-to-buffer outbuf)
3633       (when one-win
3634         (shrink-window-if-larger-than-buffer)))))
3635
3636 (defun sql-execute-feature (sqlbuf outbuf feature enhanced arg)
3637   "List objects or details in a separate display buffer."
3638   (let (command
3639         (product (buffer-local-value 'sql-product (get-buffer sqlbuf))))
3640     (setq command (sql-get-product-feature product feature))
3641     (unless command
3642       (error "%s does not support %s" product feature))
3643     (when (consp command)
3644       (setq command (if enhanced
3645                         (cdr command)
3646                       (car command))))
3647     (sql-execute sqlbuf outbuf command enhanced arg)))
3648
3649 (defvar sql-completion-object nil
3650   "A list of database objects used for completion.
3651
3652 The list is maintained in SQL interactive buffers.")
3653
3654 (defvar sql-completion-column nil
3655   "A list of column names used for completion.
3656
3657 The list is maintained in SQL interactive buffers.")
3658
3659 (defun sql-build-completions-1 (schema completion-list feature)
3660   "Generate a list of objects in the database for use as completions."
3661   (let ((f (sql-get-product-feature sql-product feature)))
3662     (when f
3663       (set completion-list
3664             (let (cl)
3665               (dolist (e (append (symbol-value completion-list)
3666                                  (apply f (current-buffer) (cons schema nil)))
3667                          cl)
3668                 (unless (member e cl) (setq cl (cons e cl))))
3669               (sort cl #'string<))))))
3670
3671 (defun sql-build-completions (schema)
3672   "Generate a list of names in the database for use as completions."
3673   (sql-build-completions-1 schema 'sql-completion-object :completion-object)
3674   (sql-build-completions-1 schema 'sql-completion-column :completion-column))
3675
3676 (defvar sql-completion-sqlbuf nil)
3677
3678 (defun sql--completion-table (string pred action)
3679   (when sql-completion-sqlbuf
3680     (with-current-buffer sql-completion-sqlbuf
3681       (let ((schema (and (string-match "\\`\\(\\sw\\(:?\\sw\\|\\s_\\)*\\)[.]" string)
3682                          (downcase (match-string 1 string)))))
3683
3684         ;; If we haven't loaded any object name yet, load local schema
3685         (unless sql-completion-object
3686           (sql-build-completions nil))
3687
3688         ;; If they want another schema, load it if we haven't yet
3689         (when schema
3690           (let ((schema-dot (concat schema "."))
3691                 (schema-len (1+ (length schema)))
3692                 (names sql-completion-object)
3693                 has-schema)
3694
3695             (while (and (not has-schema) names)
3696               (setq has-schema (and
3697                                 (>= (length (car names)) schema-len)
3698                                 (string= schema-dot
3699                                          (downcase (substring (car names)
3700                                                               0 schema-len))))
3701                     names (cdr names)))
3702             (unless has-schema
3703               (sql-build-completions schema)))))
3704
3705       ;; Try to find the completion
3706       (complete-with-action action sql-completion-object string pred))))
3707
3708 (defun sql-read-table-name (prompt)
3709   "Read the name of a database table."
3710   (let* ((tname
3711           (and (buffer-local-value 'sql-contains-names (current-buffer))
3712                (thing-at-point-looking-at
3713                 (concat "\\_<\\sw\\(:?\\sw\\|\\s_\\)*"
3714                         "\\(?:[.]+\\sw\\(?:\\sw\\|\\s_\\)*\\)*\\_>"))
3715                (buffer-substring-no-properties (match-beginning 0)
3716                                                (match-end 0))))
3717          (sql-completion-sqlbuf (sql-find-sqli-buffer))
3718          (product (when sql-completion-sqlbuf
3719                     (with-current-buffer sql-completion-sqlbuf sql-product)))
3720          (completion-ignore-case t))
3721
3722     (if product
3723         (if (sql-get-product-feature product :completion-object)
3724             (completing-read prompt #'sql--completion-table
3725                              nil nil tname)
3726           (read-from-minibuffer prompt tname))
3727       (user-error "There is no active SQLi buffer"))))
3728
3729 (defun sql-list-all (&optional enhanced)
3730   "List all database objects.
3731 With optional prefix argument ENHANCED, displays additional
3732 details or extends the listing to include other schemas objects."
3733   (interactive "P")
3734   (let ((sqlbuf (sql-find-sqli-buffer)))
3735     (unless sqlbuf
3736       (user-error "No SQL interactive buffer found"))
3737     (sql-execute-feature sqlbuf "*List All*" :list-all enhanced nil)
3738     (with-current-buffer sqlbuf
3739       ;; Contains the name of database objects
3740       (set (make-local-variable 'sql-contains-names) t)
3741       (set (make-local-variable 'sql-buffer) sqlbuf))))
3742
3743 (defun sql-list-table (name &optional enhanced)
3744   "List the details of a database table named NAME.
3745 Displays the columns in the relation.  With optional prefix argument
3746 ENHANCED, displays additional details about each column."
3747   (interactive
3748    (list (sql-read-table-name "Table name: ")
3749          current-prefix-arg))
3750   (let ((sqlbuf (sql-find-sqli-buffer)))
3751     (unless sqlbuf
3752       (user-error "No SQL interactive buffer found"))
3753     (unless name
3754       (user-error "No table name specified"))
3755     (sql-execute-feature sqlbuf (format "*List %s*" name)
3756                          :list-table enhanced name)))
3757 \f
3758
3759 ;;; SQL mode -- uses SQL interactive mode
3760
3761 ;;;###autoload
3762 (define-derived-mode sql-mode prog-mode "SQL"
3763   "Major mode to edit SQL.
3764
3765 You can send SQL statements to the SQLi buffer using
3766 \\[sql-send-region].  Such a buffer must exist before you can do this.
3767 See `sql-help' on how to create SQLi buffers.
3768
3769 \\{sql-mode-map}
3770 Customization: Entry to this mode runs the `sql-mode-hook'.
3771
3772 When you put a buffer in SQL mode, the buffer stores the last SQLi
3773 buffer created as its destination in the variable `sql-buffer'.  This
3774 will be the buffer \\[sql-send-region] sends the region to.  If this
3775 SQLi buffer is killed, \\[sql-send-region] is no longer able to
3776 determine where the strings should be sent to.  You can set the
3777 value of `sql-buffer' using \\[sql-set-sqli-buffer].
3778
3779 For information on how to create multiple SQLi buffers, see
3780 `sql-interactive-mode'.
3781
3782 Note that SQL doesn't have an escape character unless you specify
3783 one.  If you specify backslash as escape character in SQL, you
3784 must tell Emacs.  Here's how to do that in your init file:
3785
3786 \(add-hook 'sql-mode-hook
3787           (lambda ()
3788             (modify-syntax-entry ?\\\\ \".\" sql-mode-syntax-table)))"
3789   :abbrev-table sql-mode-abbrev-table
3790   (if sql-mode-menu
3791       (easy-menu-add sql-mode-menu)); XEmacs
3792
3793   ;; (smie-setup sql-smie-grammar #'sql-smie-rules)
3794   (set (make-local-variable 'comment-start) "--")
3795   ;; Make each buffer in sql-mode remember the "current" SQLi buffer.
3796   (make-local-variable 'sql-buffer)
3797   ;; Add imenu support for sql-mode.  Note that imenu-generic-expression
3798   ;; is buffer-local, so we don't need a local-variable for it.  SQL is
3799   ;; case-insensitive, that's why we have to set imenu-case-fold-search.
3800   (setq imenu-generic-expression sql-imenu-generic-expression
3801         imenu-case-fold-search t)
3802   ;; Make `sql-send-paragraph' work on paragraphs that contain indented
3803   ;; lines.
3804   (set (make-local-variable 'paragraph-separate) "[\f]*$")
3805   (set (make-local-variable 'paragraph-start) "[\n\f]")
3806   ;; Abbrevs
3807   (setq-local abbrev-all-caps 1)
3808   ;; Contains the name of database objects
3809   (set (make-local-variable 'sql-contains-names) t)
3810   ;; Set syntax and font-face highlighting
3811   ;; Catch changes to sql-product and highlight accordingly
3812   (sql-set-product (or sql-product 'ansi)) ; Fixes bug#13591
3813   (add-hook 'hack-local-variables-hook 'sql-highlight-product t t))
3814
3815 \f
3816
3817 ;;; SQL interactive mode
3818
3819 (put 'sql-interactive-mode 'mode-class 'special)
3820
3821 (defun sql-interactive-mode ()
3822   "Major mode to use a SQL interpreter interactively.
3823
3824 Do not call this function by yourself.  The environment must be
3825 initialized by an entry function specific for the SQL interpreter.
3826 See `sql-help' for a list of available entry functions.
3827
3828 \\[comint-send-input] after the end of the process' output sends the
3829 text from the end of process to the end of the current line.
3830 \\[comint-send-input] before end of process output copies the current
3831 line minus the prompt to the end of the buffer and sends it.
3832 \\[comint-copy-old-input] just copies the current line.
3833 Use \\[sql-accumulate-and-indent] to enter multi-line statements.
3834
3835 If you want to make multiple SQL buffers, rename the `*SQL*' buffer
3836 using \\[rename-buffer] or \\[rename-uniquely] and start a new process.
3837 See `sql-help' for a list of available entry functions.  The last buffer
3838 created by such an entry function is the current SQLi buffer.  SQL
3839 buffers will send strings to the SQLi buffer current at the time of
3840 their creation.  See `sql-mode' for details.
3841
3842 Sample session using two connections:
3843
3844 1. Create first SQLi buffer by calling an entry function.
3845 2. Rename buffer \"*SQL*\" to \"*Connection 1*\".
3846 3. Create a SQL buffer \"test1.sql\".
3847 4. Create second SQLi buffer by calling an entry function.
3848 5. Rename buffer \"*SQL*\" to \"*Connection 2*\".
3849 6. Create a SQL buffer \"test2.sql\".
3850
3851 Now \\[sql-send-region] in buffer \"test1.sql\" will send the region to
3852 buffer \"*Connection 1*\", \\[sql-send-region] in buffer \"test2.sql\"
3853 will send the region to buffer \"*Connection 2*\".
3854
3855 If you accidentally suspend your process, use \\[comint-continue-subjob]
3856 to continue it.  On some operating systems, this will not work because
3857 the signals are not supported.
3858
3859 \\{sql-interactive-mode-map}
3860 Customization: Entry to this mode runs the hooks on `comint-mode-hook'
3861 and `sql-interactive-mode-hook' (in that order).  Before each input, the
3862 hooks on `comint-input-filter-functions' are run.  After each SQL
3863 interpreter output, the hooks on `comint-output-filter-functions' are
3864 run.
3865
3866 Variable `sql-input-ring-file-name' controls the initialization of the
3867 input ring history.
3868
3869 Variables `comint-output-filter-functions', a hook, and
3870 `comint-scroll-to-bottom-on-input' and
3871 `comint-scroll-to-bottom-on-output' control whether input and output
3872 cause the window to scroll to the end of the buffer.
3873
3874 If you want to make SQL buffers limited in length, add the function
3875 `comint-truncate-buffer' to `comint-output-filter-functions'.
3876
3877 Here is an example for your init file.  It keeps the SQLi buffer a
3878 certain length.
3879
3880 \(add-hook 'sql-interactive-mode-hook
3881     \(function (lambda ()
3882         \(setq comint-output-filter-functions 'comint-truncate-buffer))))
3883
3884 Here is another example.  It will always put point back to the statement
3885 you entered, right above the output it created.
3886
3887 \(setq comint-output-filter-functions
3888        \(function (lambda (STR) (comint-show-output))))"
3889   (delay-mode-hooks (comint-mode))
3890
3891   ;; Get the `sql-product' for this interactive session.
3892   (set (make-local-variable 'sql-product)
3893        (or sql-interactive-product
3894            sql-product))
3895
3896   ;; Setup the mode.
3897   (setq major-mode 'sql-interactive-mode)
3898   (setq mode-name
3899         (concat "SQLi[" (or (sql-get-product-feature sql-product :name)
3900                             (symbol-name sql-product)) "]"))
3901   (use-local-map sql-interactive-mode-map)
3902   (if sql-interactive-mode-menu
3903       (easy-menu-add sql-interactive-mode-menu)) ; XEmacs
3904   (set-syntax-table sql-mode-syntax-table)
3905
3906   ;; Note that making KEYWORDS-ONLY nil will cause havoc if you try
3907   ;; SELECT 'x' FROM DUAL with SQL*Plus, because the title of the column
3908   ;; will have just one quote.  Therefore syntactic highlighting is
3909   ;; disabled for interactive buffers.  No imenu support.
3910   (sql-product-font-lock t nil)
3911
3912   ;; Enable commenting and uncommenting of the region.
3913   (set (make-local-variable 'comment-start) "--")
3914   ;; Abbreviation table init and case-insensitive.  It is not activated
3915   ;; by default.
3916   (setq local-abbrev-table sql-mode-abbrev-table)
3917   (setq abbrev-all-caps 1)
3918   ;; Exiting the process will call sql-stop.
3919   (set-process-sentinel (get-buffer-process (current-buffer)) 'sql-stop)
3920   ;; Save the connection and login params
3921   (set (make-local-variable 'sql-user)       sql-user)
3922   (set (make-local-variable 'sql-database)   sql-database)
3923   (set (make-local-variable 'sql-server)     sql-server)
3924   (set (make-local-variable 'sql-port)       sql-port)
3925   (set (make-local-variable 'sql-connection) sql-connection)
3926   (setq-default sql-connection nil)
3927   ;; Contains the name of database objects
3928   (set (make-local-variable 'sql-contains-names) t)
3929   ;; Keep track of existing object names
3930   (set (make-local-variable 'sql-completion-object) nil)
3931   (set (make-local-variable 'sql-completion-column) nil)
3932   ;; Create a useful name for renaming this buffer later.
3933   (set (make-local-variable 'sql-alternate-buffer-name)
3934        (sql-make-alternate-buffer-name))
3935   ;; User stuff.  Initialize before the hook.
3936   (set (make-local-variable 'sql-prompt-regexp)
3937        (sql-get-product-feature sql-product :prompt-regexp))
3938   (set (make-local-variable 'sql-prompt-length)
3939        (sql-get-product-feature sql-product :prompt-length))
3940   (set (make-local-variable 'sql-prompt-cont-regexp)
3941        (sql-get-product-feature sql-product :prompt-cont-regexp))
3942   (make-local-variable 'sql-output-newline-count)
3943   (make-local-variable 'sql-preoutput-hold)
3944   (add-hook 'comint-preoutput-filter-functions
3945             'sql-interactive-remove-continuation-prompt nil t)
3946   (make-local-variable 'sql-input-ring-separator)
3947   (make-local-variable 'sql-input-ring-file-name)
3948   ;; Run the mode hook (along with comint's hooks).
3949   (run-mode-hooks 'sql-interactive-mode-hook)
3950   ;; Set comint based on user overrides.
3951   (setq comint-prompt-regexp
3952         (if sql-prompt-cont-regexp
3953             (concat "\\(" sql-prompt-regexp
3954                     "\\|" sql-prompt-cont-regexp "\\)")
3955           sql-prompt-regexp))
3956   (setq left-margin sql-prompt-length)
3957   ;; Install input sender
3958   (set (make-local-variable 'comint-input-sender) 'sql-input-sender)
3959   ;; People wanting a different history file for each
3960   ;; buffer/process/client/whatever can change separator and file-name
3961   ;; on the sql-interactive-mode-hook.
3962   (setq-local comint-input-ring-separator sql-input-ring-separator)
3963   (setq comint-input-ring-file-name sql-input-ring-file-name)
3964   ;; Calling the hook before calling comint-read-input-ring allows users
3965   ;; to set comint-input-ring-file-name in sql-interactive-mode-hook.
3966   (comint-read-input-ring t))
3967
3968 (defun sql-stop (process event)
3969   "Called when the SQL process is stopped.
3970
3971 Writes the input history to a history file using
3972 `comint-write-input-ring' and inserts a short message in the SQL buffer.
3973
3974 This function is a sentinel watching the SQL interpreter process.
3975 Sentinels will always get the two parameters PROCESS and EVENT."
3976   (comint-write-input-ring)
3977   (if (and (eq (current-buffer) sql-buffer)
3978            (not buffer-read-only))
3979       (insert (format "\nProcess %s %s\n" process event))
3980     (message "Process %s %s" process event)))
3981
3982 \f
3983
3984 ;;; Connection handling
3985
3986 (defun sql-read-connection (prompt &optional initial default)
3987   "Read a connection name."
3988   (let ((completion-ignore-case t))
3989     (completing-read prompt
3990                      (mapcar #'(lambda (c) (car c))
3991                              sql-connection-alist)
3992                      nil t initial 'sql-connection-history default)))
3993
3994 ;;;###autoload
3995 (defun sql-connect (connection &optional new-name)
3996   "Connect to an interactive session using CONNECTION settings.
3997
3998 See `sql-connection-alist' to see how to define connections and
3999 their settings.
4000
4001 The user will not be prompted for any login parameters if a value
4002 is specified in the connection settings."
4003
4004   ;; Prompt for the connection from those defined in the alist
4005   (interactive
4006    (if sql-connection-alist
4007        (list (sql-read-connection "Connection: " nil '(nil))
4008              current-prefix-arg)
4009      (user-error "No SQL Connections defined")))
4010
4011   ;; Are there connections defined
4012   (if sql-connection-alist
4013       ;; Was one selected
4014       (when connection
4015         ;; Get connection settings
4016         (let ((connect-set (assoc-string connection sql-connection-alist t)))
4017           ;; Settings are defined
4018           (if connect-set
4019               ;; Set the desired parameters
4020               (let (param-var login-params set-params rem-params)
4021
4022                 ;; :sqli-login params variable
4023                 (setq param-var
4024                       (sql-get-product-feature sql-product :sqli-login nil t))
4025
4026                 ;; :sqli-login params value
4027                 (setq login-params
4028                       (sql-get-product-feature sql-product :sqli-login))
4029
4030                 ;; Params in the connection
4031                 (setq set-params
4032                       (mapcar
4033                        #'(lambda (v)
4034                            (pcase (car v)
4035                              (`sql-user     'user)
4036                              (`sql-password 'password)
4037                              (`sql-server   'server)
4038                              (`sql-database 'database)
4039                              (`sql-port     'port)
4040                              (s             s)))
4041                        (cdr connect-set)))
4042
4043                 ;; the remaining params (w/o the connection params)
4044                 (setq rem-params
4045                       (sql-for-each-login login-params
4046                        #'(lambda (token plist)
4047                            (unless (member token set-params)
4048                              (if plist (cons token plist) token)))))
4049
4050                 ;; Set the parameters and start the interactive session
4051                 (mapc
4052                  #'(lambda (vv)
4053                      (set-default (car vv) (eval (cadr vv))))
4054                  (cdr connect-set))
4055                 (setq-default sql-connection connection)
4056
4057                 ;; Start the SQLi session with revised list of login parameters
4058                 (eval `(let ((,param-var ',rem-params))
4059                          (sql-product-interactive ',sql-product ',new-name))))
4060
4061             (user-error "SQL Connection <%s> does not exist" connection)
4062             nil)))
4063
4064     (user-error "No SQL Connections defined")
4065     nil))
4066
4067 (defun sql-save-connection (name)
4068   "Captures the connection information of the current SQLi session.
4069
4070 The information is appended to `sql-connection-alist' and
4071 optionally is saved to the user's init file."
4072
4073   (interactive "sNew connection name: ")
4074
4075   (unless (derived-mode-p 'sql-interactive-mode)
4076     (user-error "Not in a SQL interactive mode!"))
4077
4078   ;; Capture the buffer local settings
4079   (let* ((buf        (current-buffer))
4080          (connection (buffer-local-value 'sql-connection buf))
4081          (product    (buffer-local-value 'sql-product    buf))
4082          (user       (buffer-local-value 'sql-user       buf))
4083          (database   (buffer-local-value 'sql-database   buf))
4084          (server     (buffer-local-value 'sql-server     buf))
4085          (port       (buffer-local-value 'sql-port       buf)))
4086
4087     (if connection
4088         (message "This session was started by a connection; it's already been saved.")
4089
4090       (let ((login (sql-get-product-feature product :sqli-login))
4091             (alist sql-connection-alist)
4092             connect)
4093
4094         ;; Remove the existing connection if the user says so
4095         (when (and (assoc name alist)
4096                    (yes-or-no-p (format "Replace connection definition <%s>? " name)))
4097           (setq alist (assq-delete-all name alist)))
4098
4099         ;; Add the new connection if it doesn't exist
4100         (if (assoc name alist)
4101             (user-error "Connection <%s> already exists" name)
4102           (setq connect
4103                 (cons name
4104                       (sql-for-each-login
4105                        `(product ,@login)
4106                        #'(lambda (token _plist)
4107                            (pcase token
4108                              (`product  `(sql-product  ',product))
4109                              (`user     `(sql-user     ,user))
4110                              (`database `(sql-database ,database))
4111                              (`server   `(sql-server   ,server))
4112                              (`port     `(sql-port     ,port)))))))
4113
4114           (setq alist (append alist (list connect)))
4115
4116           ;; confirm whether we want to save the connections
4117           (if (yes-or-no-p "Save the connections for future sessions? ")
4118               (customize-save-variable 'sql-connection-alist alist)
4119             (customize-set-variable 'sql-connection-alist alist)))))))
4120
4121 (defun sql-connection-menu-filter (tail)
4122   "Generate menu entries for using each connection."
4123   (append
4124    (mapcar
4125     #'(lambda (conn)
4126         (vector
4127          (format "Connection <%s>\t%s" (car conn)
4128                  (let ((sql-user "") (sql-database "")
4129                        (sql-server "") (sql-port 0))
4130                    (eval `(let ,(cdr conn) (sql-make-alternate-buffer-name)))))
4131          (list 'sql-connect (car conn))
4132          t))
4133     sql-connection-alist)
4134    tail))
4135
4136 \f
4137
4138 ;;; Entry functions for different SQL interpreters.
4139 ;;;###autoload
4140 (defun sql-product-interactive (&optional product new-name)
4141   "Run PRODUCT interpreter as an inferior process.
4142
4143 If buffer `*SQL*' exists but no process is running, make a new process.
4144 If buffer exists and a process is running, just switch to buffer `*SQL*'.
4145
4146 To specify the SQL product, prefix the call with
4147 \\[universal-argument].  To set the buffer name as well, prefix
4148 the call to \\[sql-product-interactive] with
4149 \\[universal-argument] \\[universal-argument].
4150
4151 \(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
4152   (interactive "P")
4153
4154   ;; Handle universal arguments if specified
4155   (when (not (or executing-kbd-macro noninteractive))
4156     (when (and (consp product)
4157                (not (cdr product))
4158                (numberp (car product)))
4159       (when (>= (prefix-numeric-value product) 16)
4160         (when (not new-name)
4161           (setq new-name '(4)))
4162         (setq product '(4)))))
4163
4164   ;; Get the value of product that we need
4165   (setq product
4166         (cond
4167          ((= (prefix-numeric-value product) 4) ; C-u, prompt for product
4168           (sql-read-product "SQL product: " sql-product))
4169          ((and product                  ; Product specified
4170                (symbolp product)) product)
4171          (t sql-product)))              ; Default to sql-product
4172
4173   ;; If we have a product and it has a interactive mode
4174   (if product
4175       (when (sql-get-product-feature product :sqli-comint-func)
4176         ;; If no new name specified, try to pop to an active SQL
4177         ;; interactive for the same product
4178         (let ((buf (sql-find-sqli-buffer product sql-connection)))
4179           (if (and (not new-name) buf)
4180               (pop-to-buffer buf)
4181
4182             ;; We have a new name or sql-buffer doesn't exist or match
4183             ;; Start by remembering where we start
4184             (let ((start-buffer (current-buffer))
4185                   new-sqli-buffer rpt)
4186
4187               ;; Get credentials.
4188               (apply #'sql-get-login
4189                      (sql-get-product-feature product :sqli-login))
4190
4191               ;; Connect to database.
4192               (setq rpt (make-progress-reporter "Login"))
4193
4194               (let ((sql-user       (default-value 'sql-user))
4195                     (sql-password   (default-value 'sql-password))
4196                     (sql-server     (default-value 'sql-server))
4197                     (sql-database   (default-value 'sql-database))
4198                     (sql-port       (default-value 'sql-port))
4199                     (default-directory (or sql-default-directory
4200                                            default-directory)))
4201                 (funcall (sql-get-product-feature product :sqli-comint-func)
4202                          product
4203                          (sql-get-product-feature product :sqli-options)))
4204
4205               ;; Set SQLi mode.
4206               (let ((sql-interactive-product product))
4207                 (sql-interactive-mode))
4208
4209               ;; Set the new buffer name
4210               (setq new-sqli-buffer (current-buffer))
4211               (when new-name
4212                 (sql-rename-buffer new-name))
4213               (set (make-local-variable 'sql-buffer)
4214                    (buffer-name new-sqli-buffer))
4215
4216               ;; Set `sql-buffer' in the start buffer
4217               (with-current-buffer start-buffer
4218                 (when (derived-mode-p 'sql-mode)
4219                   (setq sql-buffer (buffer-name new-sqli-buffer))
4220                   (run-hooks 'sql-set-sqli-hook)))
4221
4222               ;; Make sure the connection is complete
4223               ;; (Sometimes start up can be slow)
4224               ;;  and call the login hook
4225               (let ((proc (get-buffer-process new-sqli-buffer))
4226                     (secs sql-login-delay)
4227                     (step 0.3))
4228                 (while (and (memq (process-status proc) '(open run))
4229                             (or (accept-process-output proc step)
4230                                 (<= 0.0 (setq secs (- secs step))))
4231                             (progn (goto-char (point-max))
4232                                    (not (re-search-backward sql-prompt-regexp 0 t))))
4233                   (progress-reporter-update rpt)))
4234
4235               (goto-char (point-max))
4236               (when (re-search-backward sql-prompt-regexp nil t)
4237                 (run-hooks 'sql-login-hook))
4238
4239               ;; All done.
4240               (progress-reporter-done rpt)
4241               (pop-to-buffer new-sqli-buffer)
4242               (goto-char (point-max))
4243               (current-buffer)))))
4244     (user-error "No default SQL product defined.  Set `sql-product'.")))
4245
4246 (defun sql-comint (product params)
4247   "Set up a comint buffer to run the SQL processor.
4248
4249 PRODUCT is the SQL product.  PARAMS is a list of strings which are
4250 passed as command line arguments."
4251   (let ((program (sql-get-product-feature product :sqli-program))
4252         (buf-name "SQL"))
4253     ;; Make sure we can find the program.  `executable-find' does not
4254     ;; work for remote hosts; we suppress the check there.
4255     (unless (or (file-remote-p default-directory)
4256                 (executable-find program))
4257       (error "Unable to locate SQL program \'%s\'" program))
4258     ;; Make sure buffer name is unique.
4259     (when (sql-buffer-live-p (format "*%s*" buf-name))
4260       (setq buf-name (format "SQL-%s" product))
4261       (when (sql-buffer-live-p (format "*%s*" buf-name))
4262         (let ((i 1))
4263           (while (sql-buffer-live-p
4264                   (format "*%s*"
4265                           (setq buf-name (format "SQL-%s%d" product i))))
4266             (setq i (1+ i))))))
4267     (set-buffer
4268      (apply #'make-comint buf-name program nil params))))
4269
4270 ;;;###autoload
4271 (defun sql-oracle (&optional buffer)
4272   "Run sqlplus by Oracle as an inferior process.
4273
4274 If buffer `*SQL*' exists but no process is running, make a new process.
4275 If buffer exists and a process is running, just switch to buffer
4276 `*SQL*'.
4277
4278 Interpreter used comes from variable `sql-oracle-program'.  Login uses
4279 the variables `sql-user', `sql-password', and `sql-database' as
4280 defaults, if set.  Additional command line parameters can be stored in
4281 the list `sql-oracle-options'.
4282
4283 The buffer is put in SQL interactive mode, giving commands for sending
4284 input.  See `sql-interactive-mode'.
4285
4286 To set the buffer name directly, use \\[universal-argument]
4287 before \\[sql-oracle].  Once session has started,
4288 \\[sql-rename-buffer] can be called separately to rename the
4289 buffer.
4290
4291 To specify a coding system for converting non-ASCII characters
4292 in the input and output to the process, use \\[universal-coding-system-argument]
4293 before \\[sql-oracle].  You can also specify this with \\[set-buffer-process-coding-system]
4294 in the SQL buffer, after you start the process.
4295 The default comes from `process-coding-system-alist' and
4296 `default-process-coding-system'.
4297
4298 \(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
4299   (interactive "P")
4300   (sql-product-interactive 'oracle buffer))
4301
4302 (defun sql-comint-oracle (product options)
4303   "Create comint buffer and connect to Oracle."
4304   ;; Produce user/password@database construct.  Password without user
4305   ;; is meaningless; database without user/password is meaningless,
4306   ;; because "@param" will ask sqlplus to interpret the script
4307   ;; "param".
4308   (let (parameter nlslang coding)
4309     (if (not (string= "" sql-user))
4310         (if (not (string= "" sql-password))
4311             (setq parameter (concat sql-user "/" sql-password))
4312           (setq parameter sql-user)))
4313     (if (and parameter (not (string= "" sql-database)))
4314         (setq parameter (concat parameter "@" sql-database)))
4315     ;; options must appear before the logon parameters
4316     (if parameter
4317         (setq parameter (append options (list parameter)))
4318       (setq parameter options))
4319     (sql-comint product parameter)
4320     ;; Set process coding system to agree with the interpreter
4321     (setq nlslang (or (getenv "NLS_LANG") "")
4322           coding  (dolist (cs
4323                            ;; Are we missing any common NLS character sets
4324                            '(("US8PC437"  . cp437)
4325                              ("EL8PC737"  . cp737)
4326                              ("WE8PC850"  . cp850)
4327                              ("EE8PC852"  . cp852)
4328                              ("TR8PC857"  . cp857)
4329                              ("WE8PC858"  . cp858)
4330                              ("IS8PC861"  . cp861)
4331                              ("IW8PC1507" . cp862)
4332                              ("N8PC865"   . cp865)
4333                              ("RU8PC866"  . cp866)
4334                              ("US7ASCII"  . us-ascii)
4335                              ("UTF8"      . utf-8)
4336                              ("AL32UTF8"  . utf-8)
4337                              ("AL16UTF16" . utf-16))
4338                            (or coding 'utf-8))
4339                     (when (string-match (format "\\.%s\\'" (car cs)) nlslang)
4340                       (setq coding (cdr cs)))))
4341     (set-buffer-process-coding-system coding coding)))
4342
4343 (defun sql-oracle-save-settings (sqlbuf)
4344   "Save most SQL*Plus settings so they may be reset by \\[sql-redirect]."
4345   ;; Note: does not capture the following settings:
4346   ;;
4347   ;; APPINFO
4348   ;; BTITLE
4349   ;; COMPATIBILITY
4350   ;; COPYTYPECHECK
4351   ;; MARKUP
4352   ;; RELEASE
4353   ;; REPFOOTER
4354   ;; REPHEADER
4355   ;; SQLPLUSCOMPATIBILITY
4356   ;; TTITLE
4357   ;; USER
4358   ;;
4359
4360   (append
4361   ;; (apply #'concat (append
4362   ;;  '("SET")
4363
4364    ;; option value...
4365    (sql-redirect-value
4366     sqlbuf
4367     (concat "SHOW ARRAYSIZE AUTOCOMMIT AUTOPRINT AUTORECOVERY AUTOTRACE"
4368             " CMDSEP COLSEP COPYCOMMIT DESCRIBE ECHO EDITFILE EMBEDDED"
4369             " ESCAPE FLAGGER FLUSH HEADING INSTANCE LINESIZE LNO LOBOFFSET"
4370             " LOGSOURCE LONG LONGCHUNKSIZE NEWPAGE NULL NUMFORMAT NUMWIDTH"
4371             " PAGESIZE PAUSE PNO RECSEP SERVEROUTPUT SHIFTINOUT SHOWMODE"
4372             " SPOOL SQLBLANKLINES SQLCASE SQLCODE SQLCONTINUE SQLNUMBER"
4373             " SQLPROMPT SUFFIX TAB TERMOUT TIMING TRIMOUT TRIMSPOOL VERIFY")
4374     "^.+$"
4375     "SET \\&")
4376
4377    ;; option "c" (hex xx)
4378    (sql-redirect-value
4379     sqlbuf
4380     (concat "SHOW BLOCKTERMINATOR CONCAT DEFINE SQLPREFIX SQLTERMINATOR"
4381             " UNDERLINE HEADSEP RECSEPCHAR")
4382     "^\\(.+\\) (hex ..)$"
4383     "SET \\1")
4384
4385    ;; FEEDBACK ON for 99 or more rows
4386    ;; feedback OFF
4387    (sql-redirect-value
4388     sqlbuf
4389     "SHOW FEEDBACK"
4390     "^\\(?:FEEDBACK ON for \\([[:digit:]]+\\) or more rows\\|feedback \\(OFF\\)\\)"
4391     "SET FEEDBACK \\1\\2")
4392
4393    ;; wrap : lines will be wrapped
4394    ;; wrap : lines will be truncated
4395    (list (concat "SET WRAP "
4396                  (if (string=
4397                       (car (sql-redirect-value
4398                             sqlbuf
4399                             "SHOW WRAP"
4400                             "^wrap : lines will be \\(wrapped\\|truncated\\)" 1))
4401                       "wrapped")
4402                      "ON" "OFF")))))
4403
4404 (defun sql-oracle-restore-settings (sqlbuf saved-settings)
4405   "Restore the SQL*Plus settings in SAVED-SETTINGS."
4406
4407   ;; Remove any settings that haven't changed
4408   (mapc
4409    #'(lambda (one-cur-setting)
4410        (setq saved-settings (delete one-cur-setting saved-settings)))
4411    (sql-oracle-save-settings sqlbuf))
4412
4413   ;; Restore the changed settings
4414   (sql-redirect sqlbuf saved-settings))
4415
4416 (defun sql-oracle-list-all (sqlbuf outbuf enhanced _table-name)
4417   ;; Query from USER_OBJECTS or ALL_OBJECTS
4418   (let ((settings (sql-oracle-save-settings sqlbuf))
4419         (simple-sql
4420          (concat
4421           "SELECT INITCAP(x.object_type) AS SQL_EL_TYPE "
4422           ", x.object_name AS SQL_EL_NAME "
4423           "FROM user_objects                    x "
4424           "WHERE x.object_type NOT LIKE '%% BODY' "
4425           "ORDER BY 2, 1;"))
4426         (enhanced-sql
4427          (concat
4428           "SELECT INITCAP(x.object_type) AS SQL_EL_TYPE "
4429           ", x.owner ||'.'|| x.object_name AS SQL_EL_NAME "
4430           "FROM all_objects x "
4431           "WHERE x.object_type NOT LIKE '%% BODY' "
4432           "AND x.owner <> 'SYS' "
4433           "ORDER BY 2, 1;")))
4434
4435     (sql-redirect sqlbuf
4436                   (concat "SET LINESIZE 80 PAGESIZE 50000 TRIMOUT ON"
4437                           " TAB OFF TIMING OFF FEEDBACK OFF"))
4438
4439     (sql-redirect sqlbuf
4440                   (list "COLUMN SQL_EL_TYPE  HEADING \"Type\" FORMAT A19"
4441                         "COLUMN SQL_EL_NAME  HEADING \"Name\""
4442                         (format "COLUMN SQL_EL_NAME  FORMAT A%d"
4443                                 (if enhanced 60 35))))
4444
4445     (sql-redirect sqlbuf
4446                   (if enhanced enhanced-sql simple-sql)
4447                   outbuf)
4448
4449     (sql-redirect sqlbuf
4450                   '("COLUMN SQL_EL_NAME CLEAR"
4451                     "COLUMN SQL_EL_TYPE CLEAR"))
4452
4453     (sql-oracle-restore-settings sqlbuf settings)))
4454
4455 (defun sql-oracle-list-table (sqlbuf outbuf _enhanced table-name)
4456   "Implements :list-table under Oracle."
4457   (let ((settings (sql-oracle-save-settings sqlbuf)))
4458
4459     (sql-redirect sqlbuf
4460                   (format
4461                    (concat "SET LINESIZE %d PAGESIZE 50000"
4462                            " DESCRIBE DEPTH 1 LINENUM OFF INDENT ON")
4463                    (max 65 (min 120 (window-width)))))
4464
4465     (sql-redirect sqlbuf (format "DESCRIBE %s" table-name)
4466                   outbuf)
4467
4468     (sql-oracle-restore-settings sqlbuf settings)))
4469
4470 (defcustom sql-oracle-completion-types '("FUNCTION" "PACKAGE" "PROCEDURE"
4471                                          "SEQUENCE" "SYNONYM" "TABLE" "TRIGGER"
4472                                          "TYPE" "VIEW")
4473   "List of object types to include for completion under Oracle.
4474
4475 See the distinct values in ALL_OBJECTS.OBJECT_TYPE for possible values."
4476   :version "24.1"
4477   :type '(repeat string)
4478   :group 'SQL)
4479
4480 (defun sql-oracle-completion-object (sqlbuf schema)
4481   (sql-redirect-value
4482    sqlbuf
4483    (concat
4484     "SELECT CHR(1)||"
4485     (if schema
4486         (format "owner||'.'||object_name AS o FROM all_objects WHERE owner = %s AND "
4487                 (sql-str-literal (upcase schema)))
4488       "object_name AS o FROM user_objects WHERE ")
4489     "temporary = 'N' AND generated = 'N' AND secondary = 'N' AND "
4490     "object_type IN ("
4491     (mapconcat (function sql-str-literal) sql-oracle-completion-types ",")
4492     ");")
4493    "^[\001]\\(.+\\)$" 1))
4494 \f
4495
4496 ;;;###autoload
4497 (defun sql-sybase (&optional buffer)
4498   "Run isql by Sybase as an inferior process.
4499
4500 If buffer `*SQL*' exists but no process is running, make a new process.
4501 If buffer exists and a process is running, just switch to buffer
4502 `*SQL*'.
4503
4504 Interpreter used comes from variable `sql-sybase-program'.  Login uses
4505 the variables `sql-server', `sql-user', `sql-password', and
4506 `sql-database' as defaults, if set.  Additional command line parameters
4507 can be stored in the list `sql-sybase-options'.
4508
4509 The buffer is put in SQL interactive mode, giving commands for sending
4510 input.  See `sql-interactive-mode'.
4511
4512 To set the buffer name directly, use \\[universal-argument]
4513 before \\[sql-sybase].  Once session has started,
4514 \\[sql-rename-buffer] can be called separately to rename the
4515 buffer.
4516
4517 To specify a coding system for converting non-ASCII characters
4518 in the input and output to the process, use \\[universal-coding-system-argument]
4519 before \\[sql-sybase].  You can also specify this with \\[set-buffer-process-coding-system]
4520 in the SQL buffer, after you start the process.
4521 The default comes from `process-coding-system-alist' and
4522 `default-process-coding-system'.
4523
4524 \(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
4525   (interactive "P")
4526   (sql-product-interactive 'sybase buffer))
4527
4528 (defun sql-comint-sybase (product options)
4529   "Create comint buffer and connect to Sybase."
4530   ;; Put all parameters to the program (if defined) in a list and call
4531   ;; make-comint.
4532   (let ((params
4533          (append
4534           (if (not (string= "" sql-user))
4535               (list "-U" sql-user))
4536           (if (not (string= "" sql-password))
4537               (list "-P" sql-password))
4538           (if (not (string= "" sql-database))
4539               (list "-D" sql-database))
4540           (if (not (string= "" sql-server))
4541               (list "-S" sql-server))
4542           options)))
4543     (sql-comint product params)))
4544
4545 \f
4546
4547 ;;;###autoload
4548 (defun sql-informix (&optional buffer)
4549   "Run dbaccess by Informix as an inferior process.
4550
4551 If buffer `*SQL*' exists but no process is running, make a new process.
4552 If buffer exists and a process is running, just switch to buffer
4553 `*SQL*'.
4554
4555 Interpreter used comes from variable `sql-informix-program'.  Login uses
4556 the variable `sql-database' as default, if set.
4557
4558 The buffer is put in SQL interactive mode, giving commands for sending
4559 input.  See `sql-interactive-mode'.
4560
4561 To set the buffer name directly, use \\[universal-argument]
4562 before \\[sql-informix].  Once session has started,
4563 \\[sql-rename-buffer] can be called separately to rename the
4564 buffer.
4565
4566 To specify a coding system for converting non-ASCII characters
4567 in the input and output to the process, use \\[universal-coding-system-argument]
4568 before \\[sql-informix].  You can also specify this with \\[set-buffer-process-coding-system]
4569 in the SQL buffer, after you start the process.
4570 The default comes from `process-coding-system-alist' and
4571 `default-process-coding-system'.
4572
4573 \(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
4574   (interactive "P")
4575   (sql-product-interactive 'informix buffer))
4576
4577 (defun sql-comint-informix (product options)
4578   "Create comint buffer and connect to Informix."
4579   ;; username and password are ignored.
4580   (let ((db (if (string= "" sql-database)
4581                 "-"
4582               (if (string= "" sql-server)
4583                   sql-database
4584                 (concat sql-database "@" sql-server)))))
4585     (sql-comint product (append `(,db "-") options))))
4586
4587 \f
4588
4589 ;;;###autoload
4590 (defun sql-sqlite (&optional buffer)
4591   "Run sqlite as an inferior process.
4592
4593 SQLite is free software.
4594
4595 If buffer `*SQL*' exists but no process is running, make a new process.
4596 If buffer exists and a process is running, just switch to buffer
4597 `*SQL*'.
4598
4599 Interpreter used comes from variable `sql-sqlite-program'.  Login uses
4600 the variables `sql-user', `sql-password', `sql-database', and
4601 `sql-server' as defaults, if set.  Additional command line parameters
4602 can be stored in the list `sql-sqlite-options'.
4603
4604 The buffer is put in SQL interactive mode, giving commands for sending
4605 input.  See `sql-interactive-mode'.
4606
4607 To set the buffer name directly, use \\[universal-argument]
4608 before \\[sql-sqlite].  Once session has started,
4609 \\[sql-rename-buffer] can be called separately to rename the
4610 buffer.
4611
4612 To specify a coding system for converting non-ASCII characters
4613 in the input and output to the process, use \\[universal-coding-system-argument]
4614 before \\[sql-sqlite].  You can also specify this with \\[set-buffer-process-coding-system]
4615 in the SQL buffer, after you start the process.
4616 The default comes from `process-coding-system-alist' and
4617 `default-process-coding-system'.
4618
4619 \(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
4620   (interactive "P")
4621   (sql-product-interactive 'sqlite buffer))
4622
4623 (defun sql-comint-sqlite (product options)
4624   "Create comint buffer and connect to SQLite."
4625   ;; Put all parameters to the program (if defined) in a list and call
4626   ;; make-comint.
4627   (let ((params
4628          (append options
4629                  (if (not (string= "" sql-database))
4630                      `(,(expand-file-name sql-database))))))
4631     (sql-comint product params)))
4632
4633 (defun sql-sqlite-completion-object (sqlbuf _schema)
4634   (sql-redirect-value sqlbuf ".tables" "\\sw\\(?:\\sw\\|\\s_\\)*" 0))
4635
4636 \f
4637
4638 ;;;###autoload
4639 (defun sql-mysql (&optional buffer)
4640   "Run mysql by TcX as an inferior process.
4641
4642 Mysql versions 3.23 and up are free software.
4643
4644 If buffer `*SQL*' exists but no process is running, make a new process.
4645 If buffer exists and a process is running, just switch to buffer
4646 `*SQL*'.
4647
4648 Interpreter used comes from variable `sql-mysql-program'.  Login uses
4649 the variables `sql-user', `sql-password', `sql-database', and
4650 `sql-server' as defaults, if set.  Additional command line parameters
4651 can be stored in the list `sql-mysql-options'.
4652
4653 The buffer is put in SQL interactive mode, giving commands for sending
4654 input.  See `sql-interactive-mode'.
4655
4656 To set the buffer name directly, use \\[universal-argument]
4657 before \\[sql-mysql].  Once session has started,
4658 \\[sql-rename-buffer] can be called separately to rename the
4659 buffer.
4660
4661 To specify a coding system for converting non-ASCII characters
4662 in the input and output to the process, use \\[universal-coding-system-argument]
4663 before \\[sql-mysql].  You can also specify this with \\[set-buffer-process-coding-system]
4664 in the SQL buffer, after you start the process.
4665 The default comes from `process-coding-system-alist' and
4666 `default-process-coding-system'.
4667
4668 \(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
4669   (interactive "P")
4670   (sql-product-interactive 'mysql buffer))
4671
4672 (defun sql-comint-mysql (product options)
4673   "Create comint buffer and connect to MySQL."
4674   ;; Put all parameters to the program (if defined) in a list and call
4675   ;; make-comint.
4676   (let ((params
4677          (append
4678           options
4679           (if (not (string= "" sql-user))
4680               (list (concat "--user=" sql-user)))
4681           (if (not (string= "" sql-password))
4682               (list (concat "--password=" sql-password)))
4683           (if (not (= 0 sql-port))
4684               (list (concat "--port=" (number-to-string sql-port))))
4685           (if (not (string= "" sql-server))
4686               (list (concat "--host=" sql-server)))
4687           (if (not (string= "" sql-database))
4688               (list sql-database)))))
4689     (sql-comint product params)))
4690
4691 \f
4692
4693 ;;;###autoload
4694 (defun sql-solid (&optional buffer)
4695   "Run solsql by Solid as an inferior process.
4696
4697 If buffer `*SQL*' exists but no process is running, make a new process.
4698 If buffer exists and a process is running, just switch to buffer
4699 `*SQL*'.
4700
4701 Interpreter used comes from variable `sql-solid-program'.  Login uses
4702 the variables `sql-user', `sql-password', and `sql-server' as
4703 defaults, if set.
4704
4705 The buffer is put in SQL interactive mode, giving commands for sending
4706 input.  See `sql-interactive-mode'.
4707
4708 To set the buffer name directly, use \\[universal-argument]
4709 before \\[sql-solid].  Once session has started,
4710 \\[sql-rename-buffer] can be called separately to rename the
4711 buffer.
4712
4713 To specify a coding system for converting non-ASCII characters
4714 in the input and output to the process, use \\[universal-coding-system-argument]
4715 before \\[sql-solid].  You can also specify this with \\[set-buffer-process-coding-system]
4716 in the SQL buffer, after you start the process.
4717 The default comes from `process-coding-system-alist' and
4718 `default-process-coding-system'.
4719
4720 \(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
4721   (interactive "P")
4722   (sql-product-interactive 'solid buffer))
4723
4724 (defun sql-comint-solid (product options)
4725   "Create comint buffer and connect to Solid."
4726   ;; Put all parameters to the program (if defined) in a list and call
4727   ;; make-comint.
4728   (let ((params
4729          (append
4730           (if (not (string= "" sql-server))
4731               (list sql-server))
4732           ;; It only makes sense if both username and password are there.
4733           (if (not (or (string= "" sql-user)
4734                        (string= "" sql-password)))
4735               (list sql-user sql-password))
4736           options)))
4737     (sql-comint product params)))
4738
4739 \f
4740
4741 ;;;###autoload
4742 (defun sql-ingres (&optional buffer)
4743   "Run sql by Ingres as an inferior process.
4744
4745 If buffer `*SQL*' exists but no process is running, make a new process.
4746 If buffer exists and a process is running, just switch to buffer
4747 `*SQL*'.
4748
4749 Interpreter used comes from variable `sql-ingres-program'.  Login uses
4750 the variable `sql-database' as default, if set.
4751
4752 The buffer is put in SQL interactive mode, giving commands for sending
4753 input.  See `sql-interactive-mode'.
4754
4755 To set the buffer name directly, use \\[universal-argument]
4756 before \\[sql-ingres].  Once session has started,
4757 \\[sql-rename-buffer] can be called separately to rename the
4758 buffer.
4759
4760 To specify a coding system for converting non-ASCII characters
4761 in the input and output to the process, use \\[universal-coding-system-argument]
4762 before \\[sql-ingres].  You can also specify this with \\[set-buffer-process-coding-system]
4763 in the SQL buffer, after you start the process.
4764 The default comes from `process-coding-system-alist' and
4765 `default-process-coding-system'.
4766
4767 \(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
4768   (interactive "P")
4769   (sql-product-interactive 'ingres buffer))
4770
4771 (defun sql-comint-ingres (product options)
4772   "Create comint buffer and connect to Ingres."
4773   ;; username and password are ignored.
4774   (sql-comint product
4775                (append (if (string= "" sql-database)
4776                            nil
4777                          (list sql-database))
4778                        options)))
4779
4780 \f
4781
4782 ;;;###autoload
4783 (defun sql-ms (&optional buffer)
4784   "Run osql by Microsoft as an inferior process.
4785
4786 If buffer `*SQL*' exists but no process is running, make a new process.
4787 If buffer exists and a process is running, just switch to buffer
4788 `*SQL*'.
4789
4790 Interpreter used comes from variable `sql-ms-program'.  Login uses the
4791 variables `sql-user', `sql-password', `sql-database', and `sql-server'
4792 as defaults, if set.  Additional command line parameters can be stored
4793 in the list `sql-ms-options'.
4794
4795 The buffer is put in SQL interactive mode, giving commands for sending
4796 input.  See `sql-interactive-mode'.
4797
4798 To set the buffer name directly, use \\[universal-argument]
4799 before \\[sql-ms].  Once session has started,
4800 \\[sql-rename-buffer] can be called separately to rename the
4801 buffer.
4802
4803 To specify a coding system for converting non-ASCII characters
4804 in the input and output to the process, use \\[universal-coding-system-argument]
4805 before \\[sql-ms].  You can also specify this with \\[set-buffer-process-coding-system]
4806 in the SQL buffer, after you start the process.
4807 The default comes from `process-coding-system-alist' and
4808 `default-process-coding-system'.
4809
4810 \(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
4811   (interactive "P")
4812   (sql-product-interactive 'ms buffer))
4813
4814 (defun sql-comint-ms (product options)
4815   "Create comint buffer and connect to Microsoft SQL Server."
4816   ;; Put all parameters to the program (if defined) in a list and call
4817   ;; make-comint.
4818   (let ((params
4819          (append
4820           (if (not (string= "" sql-user))
4821               (list "-U" sql-user))
4822           (if (not (string= "" sql-database))
4823               (list "-d" sql-database))
4824           (if (not (string= "" sql-server))
4825               (list "-S" sql-server))
4826           options)))
4827     (setq params
4828           (if (not (string= "" sql-password))
4829               `("-P" ,sql-password ,@params)
4830             (if (string= "" sql-user)
4831                 ;; If neither user nor password is provided, use system
4832                 ;; credentials.
4833                 `("-E" ,@params)
4834               ;; If -P is passed to ISQL as the last argument without a
4835               ;; password, it's considered null.
4836               `(,@params "-P"))))
4837     (sql-comint product params)))
4838
4839 \f
4840
4841 ;;;###autoload
4842 (defun sql-postgres (&optional buffer)
4843   "Run psql by Postgres as an inferior process.
4844
4845 If buffer `*SQL*' exists but no process is running, make a new process.
4846 If buffer exists and a process is running, just switch to buffer
4847 `*SQL*'.
4848
4849 Interpreter used comes from variable `sql-postgres-program'.  Login uses
4850 the variables `sql-database' and `sql-server' as default, if set.
4851 Additional command line parameters can be stored in the list
4852 `sql-postgres-options'.
4853
4854 The buffer is put in SQL interactive mode, giving commands for sending
4855 input.  See `sql-interactive-mode'.
4856
4857 To set the buffer name directly, use \\[universal-argument]
4858 before \\[sql-postgres].  Once session has started,
4859 \\[sql-rename-buffer] can be called separately to rename the
4860 buffer.
4861
4862 To specify a coding system for converting non-ASCII characters
4863 in the input and output to the process, use \\[universal-coding-system-argument]
4864 before \\[sql-postgres].  You can also specify this with \\[set-buffer-process-coding-system]
4865 in the SQL buffer, after you start the process.
4866 The default comes from `process-coding-system-alist' and
4867 `default-process-coding-system'.  If your output lines end with ^M,
4868 your might try undecided-dos as a coding system.  If this doesn't help,
4869 Try to set `comint-output-filter-functions' like this:
4870
4871 \(setq comint-output-filter-functions (append comint-output-filter-functions
4872                                              '(comint-strip-ctrl-m)))
4873
4874 \(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
4875   (interactive "P")
4876   (sql-product-interactive 'postgres buffer))
4877
4878 (defun sql-comint-postgres (product options)
4879   "Create comint buffer and connect to Postgres."
4880   ;; username and password are ignored.  Mark Stosberg suggests to add
4881   ;; the database at the end.  Jason Beegan suggests using --pset and
4882   ;; pager=off instead of \\o|cat.  The later was the solution by
4883   ;; Gregor Zych.  Jason's suggestion is the default value for
4884   ;; sql-postgres-options.
4885   (let ((params
4886          (append
4887           (if (not (= 0 sql-port))
4888               (list "-p" (number-to-string sql-port)))
4889           (if (not (string= "" sql-user))
4890               (list "-U" sql-user))
4891           (if (not (string= "" sql-server))
4892               (list "-h" sql-server))
4893           options
4894           (if (not (string= "" sql-database))
4895               (list sql-database)))))
4896     (sql-comint product params)))
4897
4898 (defun sql-postgres-completion-object (sqlbuf schema)
4899   (sql-redirect sqlbuf "\\t on")
4900   (let ((aligned
4901          (string= "aligned"
4902                   (car (sql-redirect-value
4903                         sqlbuf "\\a"
4904                         "Output format is \\(.*\\)[.]$" 1)))))
4905     (when aligned
4906       (sql-redirect sqlbuf "\\a"))
4907     (let* ((fs (or (car (sql-redirect-value
4908                          sqlbuf "\\f" "Field separator is \"\\(.\\)[.]$" 1))
4909                    "|"))
4910            (re (concat "^\\([^" fs "]*\\)" fs "\\([^" fs "]*\\)"
4911                        fs "[^" fs "]*" fs  "[^" fs "]*$"))
4912            (cl (if (not schema)
4913                    (sql-redirect-value sqlbuf "\\d" re '(1 2))
4914                  (append (sql-redirect-value
4915                           sqlbuf (format "\\dt %s.*" schema) re '(1 2))
4916                          (sql-redirect-value
4917                           sqlbuf (format "\\dv %s.*" schema) re '(1 2))
4918                          (sql-redirect-value
4919                           sqlbuf (format "\\ds %s.*" schema) re '(1 2))))))
4920