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