;;; sql.el --- specialized comint.el for SQL interpreters -*- lexical-binding: t -*-
-;; Copyright (C) 1998-2014 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2016 Free Software Foundation, Inc.
;; Author: Alex Schroeder <alex@gnu.org>
;; Maintainer: Michael Mauger <michael@mauger.com>
-;; Version: 3.4
+;; Version: 3.5
;; Keywords: comm languages processes
;; URL: http://savannah.gnu.org/projects/emacs/
(defcustom sql-default-directory nil
"Default directory for SQL processes."
- :version "24.5"
- :type 'string
+ :version "25.1"
+ :type '(choice (const nil) string)
:group 'SQL
:safe 'stringp)
:sqli-comint-func sql-comint-db2
:prompt-regexp "^db2 => "
:prompt-length 7
- :prompt-cont-regexp "^db2 (cont\.) => "
+ :prompt-cont-regexp "^db2 (cont\\.) => "
:input-filter sql-escape-newlines-filter)
(informix
:sqli-options sql-ingres-options
:sqli-login sql-ingres-login-params
:sqli-comint-func sql-comint-ingres
- :prompt-regexp "^\* "
+ :prompt-regexp "^\\* "
:prompt-length 2
- :prompt-cont-regexp "^\* ")
+ :prompt-cont-regexp "^\\* ")
(interbase
:name "Interbase"
:completion-object sql-sqlite-completion-object
:prompt-regexp "^sqlite> "
:prompt-length 8
- :prompt-cont-regexp "^ \.\.\.> "
+ :prompt-cont-regexp "^ \\.\\.\\.> "
:terminator ";")
(sybase
:prompt-length 5
:syntax-alist ((?@ . "_"))
:terminator ("^go" . "go"))
+
+ (vertica
+ :name "Vertica"
+ :sqli-program sql-vertica-program
+ :sqli-options sql-vertica-options
+ :sqli-login sql-vertica-login-params
+ :sqli-comint-func sql-comint-vertica
+ :list-all ("\\d" . "\\dS")
+ :list-table "\\d %s"
+ :prompt-regexp "^\\w*=[#>] "
+ :prompt-length 5
+ :prompt-cont-regexp "^\\w*[-(][#>] ")
)
"An alist of product specific configuration settings.
Each element in the list is in the following format:
- \(PRODUCT FEATURE VALUE ...)
+ (PRODUCT FEATURE VALUE ...)
where PRODUCT is the appropriate value of `sql-product'. The
product name is then followed by FEATURE-VALUE pairs. If a
"An alist of connection parameters for interacting with a SQL product.
Each element of the alist is as follows:
- \(CONNECTION \(SQL-VARIABLE VALUE) ...)
+ (CONNECTION \(SQL-VARIABLE VALUE) ...)
Where CONNECTION is a case-insensitive string identifying the
connection, SQL-VARIABLE is the symbol name of a SQL mode
;; Oracle SQL*Plus Commands
;; Only recognized in they start in column 1 and the
;; abbreviation is followed by a space or the end of line.
-
- "\\|"
(list (concat "^" (sql-regexp-abbrev "rem~ark") "\\(?:\\s-.*\\)?$")
0 'font-lock-comment-face t)
0 'font-lock-doc-face t)
'("&?&\\(?:\\sw\\|\\s_\\)+[.]?" 0 font-lock-preprocessor-face t)
+ ;; Oracle PL/SQL Attributes (Declare these first to match %TYPE correctly)
+ (sql-font-lock-keywords-builder 'font-lock-builtin-face '("%" . "\\b")
+"bulk_exceptions" "bulk_rowcount" "found" "isopen" "notfound"
+"rowcount" "rowtype" "type"
+)
;; Oracle Functions
(sql-font-lock-keywords-builder 'font-lock-builtin-face nil
"abs" "acos" "add_months" "appendchildxml" "ascii" "asciistr" "asin"
"prediction" "prediction_bounds" "prediction_cost"
"prediction_details" "prediction_probability" "prediction_set"
"presentnnv" "presentv" "previous" "rank" "ratio_to_report" "rawtohex"
-"rawtonhex" "ref" "reftohex" "regexp_count" "regexp_instr"
+"rawtonhex" "ref" "reftohex" "regexp_count" "regexp_instr" "regexp_like"
"regexp_replace" "regexp_substr" "regr_avgx" "regr_avgy" "regr_count"
"regr_intercept" "regr_r2" "regr_slope" "regr_sxx" "regr_sxy"
"regr_syy" "remainder" "replace" "round" "rowidtochar" "rowidtonchar"
"password_life_time" "password_lock_time" "password_reuse_max"
"password_reuse_time" "password_verify_function" "pctfree"
"pctincrease" "pctthreshold" "pctused" "pctversion" "percent"
-"performance" "permanent" "pfile" "physical" "pipelined" "plan"
+"performance" "permanent" "pfile" "physical" "pipelined" "pivot" "plan"
"post_transaction" "pragma" "prebuilt" "preserve" "primary" "private"
"private_sga" "privileges" "procedure" "profile" "protection" "public"
"purge" "query" "quiesce" "quota" "range" "read" "reads" "rebuild"
"temporary" "test" "than" "then" "thread" "through" "time_zone"
"timeout" "to" "trace" "transaction" "trigger" "triggers" "truncate"
"trust" "type" "types" "unarchived" "under" "under_path" "undo"
-"uniform" "union" "unique" "unlimited" "unlock" "unquiesce"
+"uniform" "union" "unique" "unlimited" "unlock" "unpivot" "unquiesce"
"unrecoverable" "until" "unusable" "unused" "update" "upgrade" "usage"
"use" "using" "validate" "validation" "value" "values" "variable"
"varray" "version" "view" "wait" "when" "whenever" "where" "with"
"clob" "date" "day" "float" "interval" "local" "long" "longraw"
"minute" "month" "nchar" "nclob" "number" "nvarchar2" "raw" "rowid" "second"
"time" "timestamp" "urowid" "varchar2" "with" "year" "zone"
-)
-
- ;; Oracle PL/SQL Attributes
- (sql-font-lock-keywords-builder 'font-lock-builtin-face '("%" . "\\b")
-"bulk_exceptions" "bulk_rowcount" "found" "isopen" "notfound"
-"rowcount" "rowtype" "type"
)
;; Oracle PL/SQL Functions
For example:
- (sql-add-product-keywords 'ms
- '((\"\\\\b\\\\w+_t\\\\b\" . font-lock-type-face)))
+ (sql-add-product-keywords \\='ms
+ \\='((\"\\\\b\\\\w+_t\\\\b\" . font-lock-type-face)))
adds a fontification pattern to fontify identifiers ending in
`_t' as data types."
:number t
In order to ask the user for username, password and database, call the
-function like this: (sql-get-login 'user 'password 'database)."
+function like this: (sql-get-login \\='user \\='password \\='database)."
(dolist (w what)
(let ((plist (cdr-safe w)))
(pcase (or (car-safe w) w)
(interactive)
(let ((default-buffer (sql-find-sqli-buffer)))
(if (null default-buffer)
- (user-error "There is no suitable SQLi buffer")
+ (sql-product-interactive)
(let ((new-buffer (read-buffer "New SQLi buffer: " default-buffer t)))
(if (null (sql-buffer-live-p new-buffer))
(user-error "Buffer %s is not a working SQLi buffer" new-buffer)
I
See also `sql-help' on how to create such a buffer."
(interactive)
- (unless (and sql-buffer (buffer-live-p (get-buffer sql-buffer)))
+ (unless (and sql-buffer (buffer-live-p (get-buffer sql-buffer))
+ (get-buffer-process sql-buffer))
(sql-set-sqli-buffer))
- (unless (get-buffer-process sql-buffer)
- (user-error "Buffer %s has no process" sql-buffer))
(display-buffer sql-buffer))
(defun sql-make-alternate-buffer-name ()
(defun sql-starts-with-prompt-re ()
"Anchor the prompt expression at the beginning of the output line.
Remove the start of line regexp."
- (replace-regexp-in-string "\\^" "\\\\`" comint-prompt-regexp))
+ (concat "\\`" comint-prompt-regexp))
(defun sql-ends-with-prompt-re ()
"Anchor the prompt expression at the end of the output line.
-Remove the start of line regexp from the prompt expression since
-it may not follow newline characters in the output line."
- (concat (replace-regexp-in-string "\\^" "" sql-prompt-regexp) "\\'"))
+Match a SQL prompt or a password prompt."
+ (concat "\\(?:\\(?:" sql-prompt-regexp "\\)\\|"
+ "\\(?:" comint-password-prompt-regexp "\\)\\)\\'"))
(defun sql-interactive-remove-continuation-prompt (oline)
"Strip out continuation prompts out of the OLINE.
If the filter gets confused, it should reset and stop filtering
to avoid deleting non-prompt output."
- (when comint-prompt-regexp
+ ;; continue gathering lines of text iff
+ ;; + we know what a prompt looks like, and
+ ;; + there is held text, or
+ ;; + there are continuation prompt yet to come, or
+ ;; + not just a prompt string
+ (when (and comint-prompt-regexp
+ (or (> (length (or sql-preoutput-hold "")) 0)
+ (> (or sql-output-newline-count 0) 0)
+ (not (or (string-match sql-prompt-regexp oline)
+ (string-match sql-prompt-cont-regexp oline)))))
+
(save-match-data
(let (prompt-found last-nl)
sql-preoutput-hold ""))
;; Break up output by physical lines if we haven't hit the final prompt
- (unless (and (not (string= oline ""))
- (string-match (sql-ends-with-prompt-re) oline)
- (>= (match-end 0) (length oline)))
- (setq last-nl 0)
- (while (string-match "\n" oline last-nl)
- (setq last-nl (match-end 0)))
- (setq sql-preoutput-hold (concat (substring oline last-nl)
- sql-preoutput-hold)
- oline (substring oline 0 last-nl))))))
- oline)
+ (let ((end-re (sql-ends-with-prompt-re)))
+ (unless (and (not (string= oline ""))
+ (string-match end-re oline)
+ (>= (match-end 0) (length oline)))
+ ;; Find everything upto the last nl
+ (setq last-nl 0)
+ (while (string-match "\n" oline last-nl)
+ (setq last-nl (match-end 0)))
+ ;; Hold after the last nl, return upto last nl
+ (setq sql-preoutput-hold (concat (substring oline last-nl)
+ sql-preoutput-hold)
+ oline (substring oline 0 last-nl)))))))
+ oline)
;;; Sending the region to the SQLi buffer.
(message "Executing SQL command...done"))))
(defun sql-redirect-one (sqlbuf command outbuf save-prior)
- (with-current-buffer sqlbuf
- (let ((buf (get-buffer-create (or outbuf " *SQL-Redirect*")))
- (proc (get-buffer-process (current-buffer)))
- (comint-prompt-regexp (sql-get-product-feature sql-product
- :prompt-regexp))
- (start nil))
- (with-current-buffer buf
- (setq-local view-no-disable-on-exit t)
- (read-only-mode -1)
- (unless save-prior
- (erase-buffer))
- (goto-char (point-max))
- (unless (zerop (buffer-size))
- (insert "\n"))
- (setq start (point)))
-
- (when sql-debug-redirect
- (message ">>SQL> %S" command))
-
- ;; Run the command
- (comint-redirect-send-command-to-process command buf proc nil t)
- (while (null comint-redirect-completed)
- (accept-process-output nil 1))
-
- ;; Clean up the output results
- (with-current-buffer buf
- ;; Remove trailing whitespace
- (goto-char (point-max))
- (when (looking-back "[ \t\f\n\r]*" start)
- (delete-region (match-beginning 0) (match-end 0)))
- ;; Remove echo if there was one
- (goto-char start)
- (when (looking-at (concat "^" (regexp-quote command) "[\\n]"))
- (delete-region (match-beginning 0) (match-end 0)))
- ;; Remove Ctrl-Ms
- (goto-char start)
- (while (re-search-forward "\r+$" nil t)
- (replace-match "" t t))
- (goto-char start)))))
+ (when command
+ (with-current-buffer sqlbuf
+ (let ((buf (get-buffer-create (or outbuf " *SQL-Redirect*")))
+ (proc (get-buffer-process (current-buffer)))
+ (comint-prompt-regexp (sql-get-product-feature sql-product
+ :prompt-regexp))
+ (start nil))
+ (with-current-buffer buf
+ (setq-local view-no-disable-on-exit t)
+ (read-only-mode -1)
+ (unless save-prior
+ (erase-buffer))
+ (goto-char (point-max))
+ (unless (zerop (buffer-size))
+ (insert "\n"))
+ (setq start (point)))
+
+ (when sql-debug-redirect
+ (message ">>SQL> %S" command))
+
+ ;; Run the command
+ (let ((inhibit-quit t)
+ comint-preoutput-filter-functions)
+ (with-local-quit
+ (comint-redirect-send-command-to-process command buf proc nil t)
+ (while (or quit-flag (null comint-redirect-completed))
+ (accept-process-output nil 1)))
+
+ (if quit-flag
+ (comint-redirect-cleanup)
+ ;; Clean up the output results
+ (with-current-buffer buf
+ ;; Remove trailing whitespace
+ (goto-char (point-max))
+ (when (looking-back "[ \t\f\n\r]*" start)
+ (delete-region (match-beginning 0) (match-end 0)))
+ ;; Remove echo if there was one
+ (goto-char start)
+ (when (looking-at (concat "^" (regexp-quote command) "[\\n]"))
+ (delete-region (match-beginning 0) (match-end 0)))
+ ;; Remove Ctrl-Ms
+ (goto-char start)
+ (while (re-search-forward "\r+$" nil t)
+ (replace-match "" t t))
+ (goto-char start))))))))
(defun sql-redirect-value (sqlbuf command regexp &optional regexp-groups)
"Execute the SQL command and return part of result.
(get-lru-window))))
(with-current-buffer outbuf
(set-buffer-modified-p nil)
- (read-only-mode +1))
+ (setq-local revert-buffer-function
+ (lambda (_ignore-auto _noconfirm)
+ (sql-execute sqlbuf (buffer-name outbuf)
+ command enhanced arg)))
+ (special-mode))
(pop-to-buffer outbuf)
(when one-win
(shrink-window-if-larger-than-buffer)))))
one. If you specify backslash as escape character in SQL, you
must tell Emacs. Here's how to do that in your init file:
-\(add-hook 'sql-mode-hook
+\(add-hook \\='sql-mode-hook
(lambda ()
(modify-syntax-entry ?\\\\ \".\" sql-mode-syntax-table)))"
+ :group 'SQL
:abbrev-table sql-mode-abbrev-table
+
(if sql-mode-menu
(easy-menu-add sql-mode-menu)); XEmacs
;;; SQL interactive mode
(put 'sql-interactive-mode 'mode-class 'special)
+(put 'sql-interactive-mode 'custom-mode-group 'SQL)
(defun sql-interactive-mode ()
"Major mode to use a SQL interpreter interactively.
Here is an example for your init file. It keeps the SQLi buffer a
certain length.
-\(add-hook 'sql-interactive-mode-hook
- \(function (lambda ()
- \(setq comint-output-filter-functions 'comint-truncate-buffer))))
+\(add-hook \\='sql-interactive-mode-hook
+ (function (lambda ()
+ (setq comint-output-filter-functions \\='comint-truncate-buffer))))
Here is another example. It will always put point back to the statement
you entered, right above the output it created.
\(setq comint-output-filter-functions
- \(function (lambda (STR) (comint-show-output))))"
+ (function (lambda (STR) (comint-show-output))))"
(delay-mode-hooks (comint-mode))
;; Get the `sql-product' for this interactive session.
;; People wanting a different history file for each
;; buffer/process/client/whatever can change separator and file-name
;; on the sql-interactive-mode-hook.
- (setq-local comint-input-ring-separator sql-input-ring-separator)
- (setq comint-input-ring-file-name sql-input-ring-file-name)
- ;; Calling the hook before calling comint-read-input-ring allows users
- ;; to set comint-input-ring-file-name in sql-interactive-mode-hook.
- (comint-read-input-ring t))
+ (let
+ ((comint-input-ring-separator sql-input-ring-separator)
+ (comint-input-ring-file-name sql-input-ring-file-name))
+ (comint-read-input-ring t)))
(defun sql-stop (process event)
"Called when the SQL process is stopped.
This function is a sentinel watching the SQL interpreter process.
Sentinels will always get the two parameters PROCESS and EVENT."
- (comint-write-input-ring)
- (if (and (eq (current-buffer) sql-buffer)
- (not buffer-read-only))
- (insert (format "\nProcess %s %s\n" process event))
- (message "Process %s %s" process event)))
+ (with-current-buffer (process-buffer process)
+ (let
+ ((comint-input-ring-separator sql-input-ring-separator)
+ (comint-input-ring-file-name sql-input-ring-file-name))
+ (comint-write-input-ring))
+
+ (if (not buffer-read-only)
+ (insert (format "\nProcess %s %s\n" process event))
+ (message "Process %s %s" process event))))
\f
;; work for remote hosts; we suppress the check there.
(unless (or (file-remote-p default-directory)
(executable-find program))
- (error "Unable to locate SQL program \'%s\'" program))
+ (error "Unable to locate SQL program `%s'" program))
;; Make sure buffer name is unique.
(when (sql-buffer-live-p (format "*%s*" buf-name))
(setq buf-name (format "SQL-%s" product))
Try to set `comint-output-filter-functions' like this:
\(setq comint-output-filter-functions (append comint-output-filter-functions
- '(comint-strip-ctrl-m)))
+ \\='(comint-strip-ctrl-m)))
\(Type \\[describe-mode] in the SQL buffer for a list of commands.)"
(interactive "P")
\f
+(defcustom sql-vertica-program "vsql"
+ "Command to start the Vertica client."
+ :version "25.1"
+ :type 'file
+ :group 'SQL)
+
+(defcustom sql-vertica-options '("-P" "pager=off")
+ "List of additional options for `sql-vertica-program'.
+The default value disables the internal pager."
+ :version "25.1"
+ :type '(repeat string)
+ :group 'SQL)
+
+(defcustom sql-vertica-login-params '(user password database server)
+ "List of login parameters needed to connect to Vertica."
+ :version "25.1"
+ :type 'sql-login-params
+ :group 'SQL)
+
+(defun sql-comint-vertica (product options)
+ "Create comint buffer and connect to Vertica."
+ (sql-comint product
+ (nconc
+ (and (not (string= "" sql-server))
+ (list "-h" sql-server))
+ (and (not (string= "" sql-database))
+ (list "-d" sql-database))
+ (and (not (string= "" sql-password))
+ (list "-w" sql-password))
+ (and (not (string= "" sql-user))
+ (list "-U" sql-user))
+ options)))
+
+;;;###autoload
+(defun sql-vertica (&optional buffer)
+ "Run vsql as an inferior process."
+ (interactive "P")
+ (sql-product-interactive 'vertica buffer))
+
+\f
(provide 'sql)
;;; sql.el ends here