home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #26 / NN_1992_26.iso / spool / gnu / emacs / sources / 791 < prev    next >
Encoding:
Internet Message Format  |  1992-11-12  |  50.7 KB

  1. Path: sparky!uunet!stanford.edu!ames!elroy.jpl.nasa.gov!lll-winken!llnl.gov
  2. From: markl@llnl.gov (Mark Levinson)
  3. Newsgroups: gnu.emacs.sources
  4. Subject: using sqlplus and emacs
  5. Message-ID: <141295@lll-winken.LLNL.GOV>
  6. Date: 12 Nov 92 17:11:24 GMT
  7. Sender: usenet@lll-winken.LLNL.GOV
  8. Reply-To: markl@llnl.gov
  9. Organization: Lawrence Livermore National Lab
  10. Lines: 1231
  11. Nntp-Posting-Host: aisws7.llnl.gov
  12.  
  13.  
  14. Here are two files:    sql-mode.el and SQLMODE.DOC for using sqlplus with emacs:
  15.  
  16.  
  17. ---
  18.  
  19. ;; sql-mode.el - Oracle SQL*Plus interface
  20. ;;
  21. ;; Author:  Jim Lange, Oracle Corporation
  22. ;; Date:    27-MAR-90
  23. ;; Bugs to: jlange@us.oracle.com
  24. ;;
  25. ;; $Header: /home/jlange/emacs/RCS/sql-mode.el,v 1.2 90/04/10 07:11:42 jlange Exp Locker: jlange $
  26. ;; 
  27. ;; Revision History:
  28. ;;   19-APR-90 (jlange) - Trap EXIT/QUIT and terminate session.
  29. ;;                      - Trap EDIT, but just print message.
  30. ;;                      - Allow multiple sqlplus sessions by renaming current
  31. ;;                        buffer to new name and executing sqlplus again.
  32. ;;                      - Set left-margin to 5 in sqlplus-mode so that
  33. ;;                        newline-and-indent (C-j) will indent.
  34. ;;                      - Added (accept-process-output process) in 
  35. ;;                        sqlplus-kill-command to prevent occasional scrambled
  36. ;;                        lines when command is executed.
  37. ;;                      - Added sqlplus-reset-buffer.
  38. ;;   25-APR-90 (jlange) - Treat GET like LIST and RUN--ignore in 
  39. ;;                        sqlplus-get-command.
  40. ;;                      - Add sqlplus-drop-old-lines.
  41. ;;   04-MAY-90 (jlange) - Add sqlplus-copy-word (C-c C-w).
  42. ;;                      - Enhance sqlplus-kill-command to delete command or
  43. ;;                        command output, depending on location of point.
  44. ;;   11-MAY-90 (jlange) - In sql-send-region, detect imbedded SQL statement 
  45. ;;                        format (used in SQL*FORMS, SQL*REPORT, PRO*C, etc.) 
  46. ;;                        and convert to standard SQL before executing (remove
  47. ;;                        INTO clause and convert :WORD to &WORD).
  48. ;;                      - Automatically load and save session history based
  49. ;;                        on the variable sqlplus-keep-history.
  50. ;;   05-JUN-90 (jlange) - Delete ~/sqlplus.buf when exiting.
  51. ;;                      - In sqlplus-send-region, when performing substitutions
  52. ;;                        in statements, add "/" at end if not present.
  53. ;;   12-JUN-90 (jlange) - In sqlplus-send-region, look for :text.text and convert
  54. ;;                        to &text_text (used in SQL*Forms for block.field).
  55. ;;   07-SEP-90 (jlange) - Removed process argument from accept-process-output in
  56. ;;                        sql-send-line to prevent apparent lockup after issuing
  57. ;;                        complex SQL statement.
  58. ;;                      - Trap EDIT command and open new emacs buffer containing
  59. ;;                        command text.  (new revision 1.2)
  60. ;;   08-MAY-91 (jlange) - In sql-send-region, truncate &-variables to 30 characters
  61. ;;                        before executing.
  62. ;;---------------------------------------------------------------------------------
  63.  
  64. ;; Copyright (C) 1990 Free Software Foundation, Inc., and Jim Lange.
  65. ;;
  66. ;; This file is part of GNU Emacs.  It is derived from 18.55's shell.el.
  67. ;;
  68. ;; GNU Emacs is distributed in the hope that it will be useful,
  69. ;; but WITHOUT ANY WARRANTY.  No author or distributor
  70. ;; accepts responsibility to anyone for the consequences of using it
  71. ;; or for whether it serves any particular purpose or works at all,
  72. ;; unless he says so in writing.  Refer to the GNU Emacs General Public
  73. ;; License for full details.
  74. ;;
  75. ;; Everyone is granted permission to copy, modify and redistribute
  76. ;; GNU Emacs, but only under the conditions described in the
  77. ;; GNU Emacs General Public License.   A copy of this license is
  78. ;; supposed to have been given to you along with GNU Emacs so you
  79. ;; can know your rights and responsibilities.  It should be in a
  80. ;; file named COPYING.  Among other things, the copyright notice
  81. ;; and this notice must be preserved on all copies.
  82.  
  83. ;;----------------------------------------------------------------------
  84.  
  85. ;; This file contains function definitions for two new Emacs major modes,
  86. ;; sql-mode and sqlplus-mode.  Sql-mode is for editing SQL statements in
  87. ;; a standard text buffer.  Sqlplus-mode is used in conjunction with the 
  88. ;; sqlplus function which runs SQL*Plus as an inferior process (similar to 
  89. ;; shell-mode).
  90. ;;
  91. ;; Sql-mode is provided primarily as a convenience so that SQL statements 
  92. ;; may be sent to SQL*Plus running in another buffer.  Eventually it may
  93. ;; also provide automatic formatting of SQL statements based on Oracle 
  94. ;; indentation standards (if they exist).
  95. ;;
  96. ;; Both modes turn on abbrev-mode and share a mode-specific abbreviation table
  97. ;; with some predefined abbreviations.  Users may add to these or load in their
  98. ;; own.  Abbrev-mode may be turned off in a user defined hook routine.
  99. ;;
  100. ;; The following commands should be added to a global init file or to any 
  101. ;; user's .emacs file to conveniently use the new sql modes.
  102. ;;
  103. ;;      (autoload 'sqlplus "sql-mode" 
  104. ;;        "Run an interactive SQL*plus session in a separate buffer." t)
  105. ;;
  106. ;;      (autoload 'sql-mode "sql-mode"
  107. ;;        "Major mode for editing SQL*plus batch files." t)
  108. ;;
  109. ;;      (setq auto-mode-alist (cons '("\\.sql$" . sql-mode) auto-mode-alist))
  110. ;;
  111. ;; Possible Enhancements:
  112. ;;   - Detect actual prompt string and set sql-prompt variable appropriately.
  113. ;;
  114. ;;   - Suggestions?
  115.  
  116. (provide 'sql-mode)
  117.  
  118. ;; define variables
  119. (defvar sqlplus-startup-message
  120.   (concat 
  121.    "Emacs SQL*Plus Interpreter:  by Jim Lange of Oracle Corporation\n"
  122.    (substring "$Revision: 1.2 $" 1 -1)
  123.    "\n\nCopyright (c) 1990 Free Software Foundation, Inc., and Jim Lange.\n"
  124.    "------------------------------")
  125.   "Message displayed when \\[sqlplus] is executed.")
  126.  
  127. (defvar last-output-start nil
  128.   "In a sqlplus-mode buffer, marker for beginning of last batch of output.")
  129. (defvar sql-prompt nil
  130.   "In a sqlplus-mode buffer, string containing prompt text.")
  131. (defvar sql-continue-pattern nil
  132.   "In a sqlplus-mode buffer, regular expression for continuation line prompt.")
  133. (defvar sqlplus-username-password nil
  134.   "The username/password to use when starting SQL*Plus.")
  135. (defvar sqlplus-stack-pointer 0
  136.   "Current command recalled from history of commands.")
  137. (defvar sqlplus-keep-history nil
  138.   "If non-nil, save current session in file .sqlhist when exiting.")
  139. (defvar sqlplus-lines-to-keep 1000
  140.   "Number of lines to keep in a SQL*Plus buffer when \\[sqlplus-drop-old-lines] is executed.")
  141. (defvar sqlplus-mode-map nil)
  142. (defvar sql-mode-map nil)
  143. (defvar sql-mode-syntax-table nil
  144.   "Syntax table used while in SQL and SQL*Plus modes.")
  145. (defvar sql-mode-abbrev-table nil
  146.   "Abbrev table used in SQL and SQL*Plus modes.")
  147.  
  148. ;; initialize syntax table
  149. (if sql-mode-syntax-table
  150.     ()
  151.   (setq sql-mode-syntax-table (make-syntax-table))
  152.   (modify-syntax-entry ?/ ". 14" sql-mode-syntax-table)   ; comment start
  153.   (modify-syntax-entry ?* ". 23" sql-mode-syntax-table)
  154.   (modify-syntax-entry ?+ "." sql-mode-syntax-table)
  155.   (modify-syntax-entry ?- "." sql-mode-syntax-table)
  156.   (modify-syntax-entry ?= "." sql-mode-syntax-table)
  157.   (modify-syntax-entry ?% "w" sql-mode-syntax-table)
  158.   (modify-syntax-entry ?< "." sql-mode-syntax-table)
  159.   (modify-syntax-entry ?> "." sql-mode-syntax-table)
  160.   (modify-syntax-entry ?& "w" sql-mode-syntax-table)
  161.   (modify-syntax-entry ?| "." sql-mode-syntax-table)
  162.   (modify-syntax-entry ?_ "w" sql-mode-syntax-table)     ; make _ part of words
  163.   (modify-syntax-entry ?\' "\"" sql-mode-syntax-table))
  164.  
  165. ;; initialize abbreviations
  166. (if sql-mode-abbrev-table
  167.     nil
  168.   (define-abbrev-table 'sql-mode-abbrev-table ())
  169.   (let ((abbrevs-changed nil))
  170.     (define-abbrev sql-mode-abbrev-table  "d"   "describe" nil)
  171.     (define-abbrev sql-mode-abbrev-table  "s"   "select"   nil)
  172.     (define-abbrev sql-mode-abbrev-table  "f"   "from"     nil)
  173.     (define-abbrev sql-mode-abbrev-table  "w"   "where"    nil)
  174.     (define-abbrev sql-mode-abbrev-table  "o"   "order by" nil)
  175.     (define-abbrev sql-mode-abbrev-table  "l"   "like"     nil)
  176.     (define-abbrev sql-mode-abbrev-table  "i"   "in ("     nil)
  177.     (define-abbrev sql-mode-abbrev-table  "g"   "group by" nil)
  178.     (define-abbrev sql-mode-abbrev-table  "h"   "having"   nil)
  179.     (define-abbrev sql-mode-abbrev-table  "n"   "not"      nil)
  180.   )
  181. )
  182.  
  183. ;;-----------------------------
  184.  
  185. (defun sql-mode ()
  186.   "Major mode for editing SQL*Plus batch files.
  187. \\{sql-mode-map}
  188. sql-send-buffer and sql-send-region are commands that will send SQL*Plus
  189. commands defined in the current buffer to SQL*Plus to be executed.  Output
  190. is displayed in the *sqlplus* buffer (which will open as separate window
  191. if it does not already exist).  (use '\\[describe-mode]' while in *sqlplus*
  192. buffer for information on sqlplus-mode.)
  193.  
  194. Entry to this mode calls the value of sqlplus-mode-hook with no args,
  195. if that value is non-nil.  Abbrev-mode is also enabled with the following
  196. abbreviations available by default:
  197.  
  198.         s  ->  Select
  199.         f  ->  From
  200.         w  ->  Where
  201.         o  ->  Order By
  202.  
  203. Use \\[list-abbrevs] for a full list.
  204.  
  205. If the SQL statements to be executed contain variables prefixed with colons
  206. or INTO clauses, the colons are converted into ampersands and the INTO clauses
  207. are removed before being sent to SQL*Plus.  This provides compatibility with
  208. Pro*C, SQL*Report, and SQL*Forms (.inp files).  For example,
  209.  
  210.      SELECT SYSDATE + :days_added INTO :variable FROM SYSTEM.DUAL
  211.  
  212. is converted to
  213.  
  214.      SELECT SYSDATE + &days_added FROM SYSTEM.DUAL
  215.  
  216. and the user is prompted to enter the value of days_added."
  217.  
  218.   (interactive)
  219.   (setq major-mode 'sql-mode)
  220.   (setq mode-name "SQL")
  221.   (use-local-map sql-mode-map)
  222.   (set-syntax-table sql-mode-syntax-table)
  223.   (setq local-abbrev-table sql-mode-abbrev-table)
  224.   (abbrev-mode 1)
  225.   (setq abbrev-all-caps 1)
  226.   (setq require-final-newline t)
  227.   (run-hooks 'sql-mode-hook)
  228. )
  229.  
  230. (if sql-mode-map
  231.     nil
  232.   (setq sql-mode-map (make-sparse-keymap))
  233.   (define-key sql-mode-map "\C-c\C-x" 'sql-send-buffer)
  234.   (define-key sql-mode-map "\C-c\C-r" 'sql-send-region)
  235. )
  236.  
  237. (defun sqlplus-mode ()
  238.   "Major mode for interacting with Oracle SQL*Plus.
  239. Return at end of buffer sends line as input.
  240. Return not at end copies SQL statement to end and executes it.  
  241. \\{sqlplus-mode-map}
  242. This mode is normally invoked by 'M-x sqlplus' (not 'M-x sqlplus-mode').
  243. You will be prompted to enter a username/password combination
  244. to access the Oracle database.  This can be prevented by setting the 
  245. variable sqlplus-username-password in your .emacs file as follows:
  246.  
  247.      (setq sqlplus-username-password \"myname/mypassword\")
  248.  
  249. There are two ways of editing and re-executing prior commands.
  250. '\\[sqlplus-back-command]' and '\\[sqlplus-forward-command]' will move to the location 
  251. in the buffer of the previous or next SQL statement, respectively
  252. (based on the command prompt).  The command can then be edited
  253. normally and re-executed by pressing Return.  To insert a newline,
  254. you may press '\\[newline-and-indent]'.  '\\[sqlplus-next-command]' and '\\[sqlplus-previous-command]' 
  255. are similar except the next or previous SQL statement is inserted at
  256. the end of the buffer.  Repeating these commands will clear the
  257. current statement and recall the next or previous statement from the
  258. stack.  For additional information on command execution use 
  259. '\\[describe-key] RTN'.
  260.  
  261. '\\[show-sqlplus-output]' will move to the beginning of the last ouput
  262. generated by SQL*plus.  This is useful for reviewing the results of 
  263. the last statement.  '\\[sqlplus-end-of-buffer]' moves to the end of the buffer, 
  264. but unlike '\\[end-of-buffer]' (end-of-buffer), it does not set the mark.
  265.  
  266. '\\[sqlplus-kill-command]' deletes either the current command being entered or
  267. the last output generated by SQL*Plus, depending on when it is used.  
  268. If executed while the cursor is within a SQL statement, the statement and 
  269. any text after it are deleted.  If the cursor is within or at the end of
  270. output generated by SQL*Plus, the output is deleted and the cursor is 
  271. positioned at the end of the SQL statement that generated the ouput.  
  272. '\\[sqlplus-kill-command]' can be used like an undo command to alternately
  273. delete commands and output from the end of the buffer.
  274.  
  275. The commands sql-send-region and sql-send-buffer can be executed from
  276. another buffer to execute the SQL statements defined by the current
  277. region or entire buffer, respectively.  Output from these commands is
  278. displayed in the *sqlplus* buffer.  The major mode called sql-mode has
  279. these functions bound to key sequences.
  280.  
  281. Entry to this mode calls the value of sqlplus-mode-hook with no args,
  282. if that value is non-nil.  Abbrev-mode is also enabled with the following
  283. abbreviations available by default:
  284.  
  285.         s  ->  Select
  286.         f  ->  From
  287.         w  ->  Where
  288.         o  ->  Order By
  289.  
  290. Use '\\[list-abbrevs]' for a full list.  
  291.  
  292. If the variable sqlplus-keep-history is non-nil, the current session is
  293. saved in the file ~/.sqlhist and recalled automatically the next time
  294. sqlplus is executed.  The session will only be saved if the EXIT or QUIT
  295. command is used to terminate the SQL*Plus session.  The maximum number of 
  296. lines saved can be set with the variable sqlplus-lines-to-keep which defaults
  297. to 1000.  The command '\\[sqlplus-drop-old-lines]' will truncate the buffer 
  298. to this length at any time.  sqlplus-keep-history and sqlplus-lines-to-keep
  299. should be set in your .emacs file.
  300.  
  301. If the *sqlplus* buffer is killed with '\\[kill-buffer]', the SQL*Plus
  302. process will automatically be terminated, but the session will not be saved,
  303. even if sqlplus-keep-history is non-nil.
  304.  
  305. '\\[sqlplus-reset-buffer]' will delete all ouput lines from the buffer, leaving
  306. only commands.  This will significantly shrink the buffer, but retain a full 
  307. history of commands for re-execution."
  308.  
  309.   (interactive)
  310.   (kill-all-local-variables)
  311.   (setq major-mode 'sqlplus-mode)
  312.   (setq mode-name "SQL*Plus")
  313.   (setq mode-line-process '(": %s"))
  314.   (use-local-map sqlplus-mode-map)
  315.   (set-syntax-table sql-mode-syntax-table)
  316.   (setq local-abbrev-table sql-mode-abbrev-table)
  317.   (make-local-variable 'last-output-start)
  318.   (setq last-output-start (make-marker))
  319.   (make-local-variable 'sql-prompt)
  320.   (setq sql-prompt "^\\(SQL> \\)+")     ;* allows "SQL> SQL> ..."
  321.   (make-local-variable 'sql-continue-pattern)
  322.   (setq sql-continue-pattern "^[ 0-9][ 0-9][0-9][* \t][ \t]\\|     ")
  323.   (setq indent-tabs-mode nil)
  324.   (setq left-margin 5)
  325.   (abbrev-mode 1)
  326.   (setq abbrev-all-caps 1)
  327.   (run-hooks 'sqlplus-mode-hook)
  328. )
  329.  
  330. (if sqlplus-mode-map
  331.     nil
  332.   (setq sqlplus-mode-map (make-sparse-keymap))
  333.   (define-key sqlplus-mode-map "\C-m" 'sqlplus-execute-command)      
  334.   (define-key sqlplus-mode-map "\t" 'indent-relative)                
  335.   (define-key sqlplus-mode-map "\C-c\C-c" 'interrupt-sqlplus-subjob) 
  336.   (define-key sqlplus-mode-map "\C-c\C-r" 'show-sqlplus-output)      
  337.   (define-key sqlplus-mode-map "\C-c\C-p" 'sqlplus-previous-command) 
  338.   (define-key sqlplus-mode-map "\C-c\C-n" 'sqlplus-next-command)     
  339.   (define-key sqlplus-mode-map "\C-c\C-e" 'sqlplus-end-of-buffer)    
  340.   (define-key sqlplus-mode-map "\C-c\C-b" 'sqlplus-back-command)     
  341.   (define-key sqlplus-mode-map "\C-c\C-f" 'sqlplus-forward-command)  
  342.   (define-key sqlplus-mode-map "\C-c\C-k" 'sqlplus-kill-command)     
  343.   (define-key sqlplus-mode-map "\C-c\C-x" 'sqlplus-reset-buffer)     
  344.   (define-key sqlplus-mode-map "\C-c\C-d" 'sqlplus-drop-old-lines)   
  345.   (define-key sqlplus-mode-map "\C-c\C-w" 'sqlplus-copy-word)        
  346.   (define-key sqlplus-mode-map "\C-c\C-s" 'sqlplus-save-session)     
  347. )
  348.  
  349. ;;-----------------------------
  350.  
  351. (defun sqlplus ()
  352.   "Start up an interactive SQL*Plus session in a new buffer.
  353. If an active SQL*Plus process already exists, will switch to that
  354. buffer."
  355.   (interactive)
  356.   (let ((process (sqlplus-start)))
  357.     (switch-to-buffer "*sqlplus*")
  358.     (if (and sqlplus-keep-history
  359.          (file-readable-p (expand-file-name "~/.sqlhist")))
  360.     (progn
  361.       (sit-for 1)
  362.       (while (accept-process-output) (sleep-for 1)) 
  363.       (insert-file-contents (expand-file-name "~/.sqlhist") nil)
  364.       (goto-char (point-max))
  365.       (set-marker (process-mark process) (point))
  366.       (message ".sqlhist loaded")
  367.         )
  368.     );endif
  369.   )
  370. )
  371.  
  372. (defun sqlplus-start ()
  373.   "Start up an interactive SQL*Plus session in a new buffer."
  374.   (let ((sqlplus-buffer (get-buffer-create "*sqlplus*")) process)
  375.     (setq process            ; set process
  376.       (or                ; to the first that is non-nil:
  377.        (get-buffer-process sqlplus-buffer)    ; current process
  378.        (progn                      ; or new process
  379.          (set-buffer sqlplus-buffer)
  380.          (insert sqlplus-startup-message)
  381.          (start-process "SQL*plus" sqlplus-buffer "sqlplus" 
  382.         (or sqlplus-username-password
  383.             (setq sqlplus-username-password 
  384.               (read-string "Enter SQL*plus username/password: "))))
  385.        ))
  386.     )
  387.     (set-buffer sqlplus-buffer)
  388.     (goto-char (point-max))
  389.     (set-marker (process-mark process) (point))
  390.     (sqlplus-mode)
  391.     process             ; return process
  392.   )
  393. )
  394.  
  395. (defun sqlplus-execute-command ()
  396. "When executed at end of buffer, sends text entered since last 
  397. output from SQL*Plus.  When executed while positioned within another
  398. valid command in the buffer, copies command to end of buffer and 
  399. re-executes it.  If point is within a multi-line statement at the end
  400. of the buffer (such as after '\\[sqlplus-previous-command]'), the entire
  401. statement will be cleared and re-entered one line at a time.
  402.  
  403. Multi-line statements are recognized by the continuation prompt displayed
  404. by SQL*Plus.  This is controlled by the variable sqlplus-continue-pattern
  405. which defaults to recognize either a right-justified number padded to four 
  406. characters followed by a space or asterisk, or simply five spaces.  A line
  407. ending with \";\" or \" /\" is also considered the end of a statement.
  408. A new line inserted into a prior statement must be indented at least five
  409. spaces to be included when the statement is re-executed. 
  410.  
  411. The output from a List command is also recognized as a valid SQL*Plus
  412. statement; the 'List' command itself is stripped out (as are 'Get' and 'Run').
  413.  
  414. When a complex SQL statement is executed, it may take a long time before
  415. the output is generated.  Emacs may appear to be hung since no keystrokes
  416. are accepted until the first character of output arrives.  In this situation
  417. '\\[keyboard-quit]' may be used to force emacs to stop waiting for output.
  418. You may then switch to another buffer to perform other work while you wait
  419. or press '\\[interrupt-sqlplus-subjob]' to cancel the current SQL command."
  420.   (interactive)
  421.   (let ((process (get-buffer-process (current-buffer))))
  422.     (if (not process) 
  423.     (error "Current buffer has no process.  Use 'M-x sqlplus' to start SQL*Plus process.")
  424.     )
  425.  
  426.     (cond
  427. ; last line of buffer and only one input line
  428.      ((and (save-excursion (end-of-line) (eobp)) 
  429.        (<= (count-lines (process-mark process) (point)) 1))
  430.     (end-of-line)
  431.         (sqlplus-send-line process)
  432.      )
  433.  
  434. ; within last multi-line command of buffer 
  435.      ((not (save-excursion (re-search-forward sql-prompt (point-max) t)))
  436.     (let ((command-lines (sqlplus-get-command)))
  437.       (sqlplus-kill-command t)        ; clear existing command lines
  438.       (while command-lines            ; send command lines
  439.         (insert (car command-lines))
  440.         (sqlplus-send-line process)
  441.         (setq command-lines (cdr command-lines))
  442.       )
  443.     )
  444.       )
  445. ; otherwise - prior command in buffer
  446.      (t                                 
  447.     (or (save-excursion
  448.           (beginning-of-line)
  449.           (looking-at (concat sql-prompt "\\|" sql-continue-pattern)))
  450.         (error "This is not a valid SQL*plus command."))
  451.     (let ((command-lines (sqlplus-get-command)))
  452.          (goto-char (point-max))
  453.          (sqlplus-kill-command t)     ; clear pending command (if any)
  454.          (while command-lines
  455.         (insert (car command-lines))
  456.         (sqlplus-send-line process)
  457.         (setq command-lines (cdr command-lines))
  458.          )
  459.     )
  460.     )
  461.   ) ;end cond
  462.  ) ;end let
  463.  (setq sqlplus-stack-pointer 0)
  464. )                    ; end defun
  465.  
  466. (defun sqlplus-send-line (process)      ; called from sqlplus-execute-command
  467.   (insert ?\n)
  468.   (let ((command (buffer-substring (process-mark process) (point)))
  469.     (temp-file (expand-file-name "~/sqlplus.buf")))
  470.     (move-marker last-output-start (point))
  471. ; trap EDIT command - must be the only word on the line
  472.     (if (string-match "^ *edit\\s-*\\(\\w*\\)[ ;]*$" command) 
  473.       (let (command-lines 
  474.         (edit-file-name (save-excursion (and 
  475.                          (re-search-backward "edit\\s-+\\([^ \t\n;]+\\)" 
  476.                                  (process-mark process) t)
  477.                          (buffer-substring (match-beginning 1) (match-end 1))
  478.                         )))
  479.  
  480.        )
  481.     (sit-for 0)
  482.     (set-marker (process-mark process) (point))
  483.     (process-send-string process "LIST\n")
  484.     (accept-process-output process)    ; wait for process to respond
  485.     (sleep-for 1)
  486.     (forward-line -1)
  487.     (setq command-lines (sqlplus-get-command)) ; capture command
  488.     (delete-region last-output-start (point))  ; delete listed lines
  489.     (goto-char (point-max))
  490.     (switch-to-buffer-other-window (get-buffer-create (or edit-file-name "*sqlplus-temp*")))
  491.     (if edit-file-name 
  492.         (setq buffer-offer-save t)
  493.     )
  494.     (delete-region (point-min) (point-max))    ; clear buffer
  495.     (while command-lines                   ;insert command lines
  496.       (insert (car command-lines) "\n")
  497.       (setq command-lines (cdr command-lines))
  498.     )
  499.     (insert "/\n")
  500.     (goto-char (point-min))
  501.     (sql-mode)            ;turn on sql-mode
  502.       )
  503. ;   else
  504. ; execute command line
  505.       (process-send-string process command)
  506.       (goto-char (point-max))
  507.       (set-marker (process-mark process) (point))
  508.       (sit-for 0)            ; force display update
  509.       (accept-process-output)        ; wait for process to respond
  510.     )
  511. ; trap QUIT command
  512.     (if (string-match "^ *\\(exit\\|quit\\)[ ;]*$" command)
  513.     (progn
  514.       (if sqlplus-keep-history
  515.           (let ((lines-to-keep (or sqlplus-lines-to-keep 1000)))
  516.         (and (> (count-lines (point-min) (point-max)) lines-to-keep)
  517.              (y-or-n-p 
  518.               (format "Current session is longer than %d lines.  Ok to truncate? " lines-to-keep))
  519.              (sqlplus-drop-old-lines lines-to-keep)
  520.         )
  521.         (sqlplus-save-session "~/.sqlhist")
  522.           )
  523.       )
  524.       (while (get-buffer-process (current-buffer)) 
  525.         (sit-for 1))         ; wait for process to die
  526.       (kill-buffer (current-buffer))
  527.       (and (file-exists-p temp-file) ; if sqlplus.buf exists, delete it
  528.            (delete-file temp-file))
  529.     );end progn
  530.     );end if
  531.   );end let
  532. )
  533.  
  534. (defun sqlplus-kill-command (command-only-flag)
  535.   "Delete the current SQL command or output generated by last SQL command.
  536. When used at the end of the buffer, serves as an undo command.
  537.  
  538. If point is within a valid SQL statement, delete region from SQL> prompt 
  539. before point to end of buffer, otherwise delete all text between the end 
  540. of the prior SQL statement and the end of the buffer."
  541.   (interactive "P")
  542.   (let ((process (get-buffer-process (current-buffer))))
  543.     (if (or command-only-flag
  544.         (save-excursion
  545.           (beginning-of-line)
  546.           (looking-at (concat sql-prompt ".+\\|" sql-continue-pattern))
  547.         )
  548.      )
  549.     ;then - delete command and everything beyond
  550.     (progn
  551.       (delete-region (progn 
  552.                (re-search-backward sql-prompt (point-min) t) 
  553.                (point))
  554.              (point-max))
  555.       (process-send-string process "\n")    ; generate new SQL> prompt
  556.       (goto-char (point-max))
  557.       (set-marker (process-mark process) (point))
  558.       (sit-for 0)                ; update display
  559.       (accept-process-output process)    ; wait for prompt
  560.     )
  561.     ;else - delete output from prior command, leaving cursor at end of command
  562.       (beginning-of-line)
  563.       (or (re-search-backward sql-prompt (point-min) t)
  564.       (error "Nothing to kill"))
  565.       (set-marker (process-mark process) (match-end 0))
  566.       (sqlplus-get-command)        ; convenient way to find end of command
  567.       (forward-char -1)            ; back up one character
  568.       (delete-region (point) (point-max))
  569.     );end if
  570.   )
  571. )
  572.  
  573. (defun sqlplus-get-command ()
  574.   (interactive)
  575.   (let ((line "") command-lines)
  576.     (end-of-line)
  577.     (or (re-search-backward sql-prompt (point-min) t)
  578.     (error "Unable to execute this command"))
  579.     (goto-char (match-end 0))       ; skip past prompt
  580.     (setq command-lines             ; initialize command-lines list
  581.         (if (looking-at "l$\\|list$\\|r$\\|run$\\|get .*\\|edit") ;ignore LIST,RUN,GET,EDIT
  582.         nil
  583.       (list (setq line 
  584.                   (buffer-substring (point) (progn (end-of-line) (point)))))
  585.     )
  586.     )
  587.     (forward-line)
  588.     (while (and                                      ; while previous line 
  589.         (not (string-match "^\\(.*;$\\| */\\)$" line)) ; does not end in / or ;
  590.         (looking-at sql-continue-pattern))       ; and this is a cont. line
  591.          (goto-char (match-end 0))                   ; skip over prompt
  592.      (setq line (buffer-substring (point) (progn (end-of-line) (point))))
  593.      (setq command-lines (append command-lines (list line)))
  594.      (forward-line)
  595.     )
  596.     command-lines          ; return command-lines as value of function
  597. ))
  598.  
  599. (defun interrupt-sqlplus-subjob ()
  600.   "Interrupt this shell's current subjob."
  601.   (interactive)
  602.   (interrupt-process nil t))
  603.  
  604. (defun show-sqlplus-output ()
  605.   "Display most recent batch of output at top of window.
  606. Also put cursor there."
  607.   (interactive)
  608.   (goto-char last-output-start)
  609. )
  610.  
  611. (defun sql-send-buffer (prefix-arg)
  612.   "Execute all SQL*Plus commands defined in current buffer.
  613. Output is displayed in the *sqlplus* buffer."
  614.   (interactive "P")
  615.   (sql-send-region (point-min) (point-max) prefix-arg)
  616. )
  617.  
  618. (defun sql-send-region (start end prefix-arg)
  619.   "Execute all SQL*Plus commands defined between point and mark.
  620. Output is displayed in the *sqlpus* buffer."
  621.   (interactive "r\nP")
  622.   (let (process this-buffer temp-file-name imbedded-variables (temp-buffer nil))
  623.    (setq this-buffer (current-buffer))
  624.    (or (setq process (get-buffer-process "*sqlplus*")) ; look for process
  625.        (setq process (sqlplus-start)) ; or create process
  626.        (error "Unable to create SQL*plus session.")) 
  627. ;    (setq temp-file-name (format "/tmp/sqlbuf.%d" (process-id process)))
  628.     (setq temp-file-name (expand-file-name "~/sqlplus.buf"))
  629.     (set-buffer this-buffer) 
  630.     (if (and (null prefix-arg)        ; if no prefix argument
  631.          (save-excursion        ; look for 'INTO :' or ':variable'
  632.            (goto-char start)
  633.            (re-search-forward "\\binto\\s-+:\\|\\s-:\\w+" end t)))
  634.     (progn
  635.       (setq temp-buffer (get-buffer-create "*sql-temp*"))
  636.       (set-buffer temp-buffer)
  637.       (set-syntax-table sql-mode-syntax-table) ; important for regular expressions
  638.       (erase-buffer)
  639.       (insert-buffer-substring this-buffer start end) ; insert region
  640.       (skip-chars-backward "\n\t ")    ; trim trailing whitespace
  641.       (if (save-excursion
  642.         (forward-char -1)    ; back up one
  643.         (not (looking-at ";\\|/")) ; last character is not ; or /
  644.           )
  645.         (insert "\n/\n")        ; add "/" so statement is executed
  646.       )
  647.       (goto-char (point-min))    ; delete INTO clause
  648.       (if (re-search-forward "\\binto\\s-+:" (point-max) t)
  649.         (delete-region (match-beginning 0) ; delete between INTO & FROM
  650.                    (progn
  651.                  (re-search-forward "\\bfrom\\b" (point-max) t)
  652.                  (match-beginning 0)
  653.                    )
  654.         )
  655.       ) ;endif
  656.       (goto-char (point-min))    ; convert all ":block.field" to "&block_field"
  657.       (replace-regexp ":\\(\\w+\\)\\." "&\\1_" nil)
  658.       (goto-char (point-min))    ; convert all remaining ":" to "&"
  659.       (replace-string ":" "&" nil)
  660.       (goto-char (point-min))
  661.       (while (re-search-forward "&\\w+" (point-max) t)
  662.         (let ( (wbeg (match-beginning 0)) (wend (match-end 0)) )
  663.          (if (> (- wend wbeg) 30)    ; if word > 30 characters
  664.              (delete-region (+ wbeg 1) (- wend 30)) ; truncate to 30
  665.          )
  666.         )
  667.       )
  668.       (setq start (point-min))    ; reset start & end for write-region
  669.       (setq end (point-max))
  670.     ) ;end progn
  671.     ) ;endif 
  672.     (setq imbedded-variables (save-excursion     ; look for &, accept, acc
  673.                    (goto-char start)
  674.                    (re-search-forward "&\\|\\bacc\\(ept\\)?\\b" end t)))
  675.     (write-region start end temp-file-name nil 0) ; write temp file
  676.     (switch-to-buffer-other-window "*sqlplus*")
  677.     (goto-char (point-max))
  678.     (recenter 0)
  679.     (insert (format "\nOutput from buffer '%s':\n" 
  680.             (buffer-name this-buffer)))
  681.     (set-marker (process-mark process) (point))
  682.     (sit-for 0)                ; update display
  683.     (process-send-string process (concat "@" temp-file-name "\n"))
  684.     (if temp-buffer (kill-buffer temp-buffer))
  685.     (if imbedded-variables        ; stay in *sqlplus* buffer to
  686.     (goto-char (point-max))        ; allow entry of variables
  687.       (switch-to-buffer-other-window this-buffer)
  688.     )
  689.   )
  690. )
  691.  
  692. (defun sqlplus-back-command (arg)
  693.   "Move to the SQL*plus command before current position.
  694. With prefix argument, move to ARG'th previous command."
  695.   (interactive "p")
  696.   (if (save-excursion 
  697.     (beginning-of-line)
  698.     (re-search-backward sql-prompt (point-min) t arg)
  699.       )
  700.       (goto-char (match-end 0))
  701.     (error "No previous SQL*plus command.")
  702.   )
  703. )
  704.   
  705. (defun sqlplus-forward-command (arg)
  706.   "Move to the SQL*plus command after current position.
  707. With prefix argument, move to ARG'th previous command."
  708.   (interactive "p")
  709.   (if (re-search-forward sql-prompt (point-max) t arg)
  710.       nil
  711.     (error "No next SQL*plus command.")
  712.   )
  713. )
  714.  
  715. (defun sqlplus-previous-command (arg)
  716.   "Recall the previous SQL*plus command from the command stack.
  717. With prefix argument, recall the command ARG commands before the current
  718. stack pointer."
  719.   (interactive "p")
  720. ; - clear current pending command
  721.   (goto-char (process-mark (get-buffer-process (current-buffer))))
  722.   (delete-region (point) (point-max))
  723.  
  724. ; - increment stack pointer by arg
  725.   (setq sqlplus-stack-pointer (+ sqlplus-stack-pointer arg))
  726.   (if (< sqlplus-stack-pointer 0)
  727.       (progn (setq sqlplus-stack-pointer 0)
  728.          (error "At last command."))
  729.   )
  730.   ;if there is a prior command    
  731.   (if (re-search-backward (concat sql-prompt ".+")  ; skip empty prompts
  732.               (point-min) t sqlplus-stack-pointer)
  733.   ;then
  734.       (let ((command-lines (sqlplus-get-command)) col)
  735.     (goto-char (point-max))
  736.     (setq col (current-column))
  737.     (while command-lines
  738.       (indent-to col)
  739.       (insert (car command-lines))
  740.       (setq command-lines (cdr command-lines))
  741.       (if command-lines (insert ?\n))
  742.     )
  743.         (message (if (> sqlplus-stack-pointer 0)
  744.              (format "#%d" sqlplus-stack-pointer)
  745.            ""))
  746.       )
  747.   ;else
  748.     (setq sqlplus-stack-pointer (- sqlplus-stack-pointer arg)) ; reset
  749.     (error "No previous SQL*plus command.")
  750.   )
  751. )
  752.  
  753. (defun sqlplus-next-command (arg)
  754.   "Recall the next SQL*plus command from the command stack.
  755. With prefix argument, recall the command ARG commands after the current
  756. stack pointer."
  757.   (interactive "p")
  758.   (sqlplus-previous-command (- arg))
  759. )
  760.  
  761. (defun sqlplus-end-of-buffer ()
  762.   "Move cursor to end of buffer."
  763.   (interactive)
  764.   (goto-char (point-max))
  765. )
  766.  
  767. (defun sqlplus-reset-buffer ()
  768.   "Reset SQL*Plus buffer to contain only command history, not output.
  769. Commands of one or fewer characters (/, l, r, etc.) are not retained."
  770.   (interactive)
  771.   (and (y-or-n-p 
  772.     (format "Delete all output lines from buffer %s? " (buffer-name)))
  773.        (let ((line "") (process (get-buffer-process (current-buffer))) start)
  774.      (message "Deleting output lines...")
  775.      (goto-char (point-min))
  776.      (setq start (point))
  777.      (while (re-search-forward (concat sql-prompt "..+") (point-max) t)
  778.        (goto-char (match-end 1))
  779.        (setq line (buffer-substring (point) (progn (end-of-line) (point))))
  780.        (beginning-of-line)
  781.        (delete-region start (point))
  782.        (forward-line)
  783.        (while (and            ; skip past SQL statement
  784.            (not (string-match "^\\(.*;$\\| */\\)$" line))
  785.            (looking-at sql-continue-pattern)) ; and this is a cont. line
  786.          (goto-char (match-end 0))                   ; skip over prompt
  787.          (setq line (buffer-substring (point) (progn (end-of-line) (point))))
  788.          (forward-line)
  789.        )
  790.        (setq start (point))
  791.      )
  792.      (goto-char (point-max))
  793.      (delete-region start (point))
  794.      (process-send-string process "\n")    ; generate new SQL> prompt
  795.      (goto-char (point-max))
  796.      (set-marker (process-mark process) (point))
  797.      (sit-for 0)                ; update display
  798.      (accept-process-output)        ; wait for prompt
  799.      (message "Deleting output lines...Done.")
  800.        )
  801.   )
  802. )
  803.  
  804. (defun sqlplus-drop-old-lines (lines-to-keep)
  805.   "Delete old lines from current buffer.
  806. Number of lines to keep is determined by the variable sqlplus-lines-to-keep.
  807. With prefix argument, keep the last ARG lines."
  808.   (interactive "P")
  809.   (delete-region (save-excursion
  810.            (goto-char (point-min))
  811.            (point))
  812.          (save-excursion
  813.            (goto-char (point-max))
  814.            (forward-line (- (or lines-to-keep 
  815.                     sqlplus-lines-to-keep 
  816.                     1000)))
  817.            (point)))
  818. )
  819.  
  820. (defun sqlplus-save-session (filename)
  821. "Save current SQL*Plus session to FILENAME."
  822.   (interactive "FFile to save session to: ")        
  823.   (save-excursion
  824.     (if (or (null filename) (string= filename ""))
  825.     (setq filename "~/.sqlhist"))
  826.     (message (format "Saving %s..." filename))
  827.     (write-region (progn
  828.             (goto-char (point-min))
  829.             (re-search-forward sql-prompt (point-max) t)
  830.             (match-end 0))
  831.           (progn
  832.             (goto-char (point-max))
  833.             (re-search-backward sql-prompt (point-min) t)
  834.             (match-end 0))
  835.           (expand-file-name filename) nil 0)
  836.     (message (format "Saving %s...done" filename))
  837.   )
  838. )
  839.  
  840. (defun sqlplus-copy-word ()
  841.   "Copy current word to the end of buffer, inserting SELECT keyword 
  842. or commas if appropriate."
  843.   (interactive)
  844.   (let (word preceding-word)
  845.     (save-excursion
  846.       (setq word (buffer-substring    ; extract word
  847.           (progn (forward-char 1) (backward-word 1) (point))
  848.           (progn (forward-word 1) (point))))
  849.       (goto-char (point-max))        ; goto end of buffer
  850.       (cond
  851.        ; sitting at empty command line
  852.        ((save-excursion (beginning-of-line) 
  853.             (looking-at (concat sql-prompt "$")))
  854.     (insert "SELECT ")
  855.        )
  856.        ; on same line as SELECT or ORDER BY, but other words already inserted
  857.        ((save-excursion (re-search-backward " select .+\\| order by .+" 
  858.               (save-excursion (beginning-of-line) (point)) t))
  859.     (insert ", ")
  860.        )
  861.        ; Otherwise
  862.        (t
  863.     (if (eq (preceding-char) ? )    ; if preceding character = space
  864.         nil
  865.       (insert " ")
  866.     )
  867.        )
  868.       );end case
  869.       (insert word)
  870.       (message (format "\"%s\" copied" word))
  871.     )
  872.   )
  873. )
  874.  
  875. ;end if file -------- cut here ---------------------------------------
  876.  
  877. ;This is a seperate file of documentation
  878.  
  879. Although SQL*Plus is a powerful tool for producing ad hoc queries and
  880. interacting with an Oracle database, the user interface is less than
  881. state-of-the-art.
  882.  
  883. I am now pleased to announce a new utility available to users of Emacs and
  884. SQL*Plus that allows SQL*Plus to run in an Emacs buffer.  Even if you don't
  885. know Emacs, this utility makes SQL*Plus so much friendlier that you may want
  886. to learn the basics of Emacs just to take advantage of the improvements.  For
  887. those of you who have been using the current version, this version includes
  888. many significant enhancements (see below).
  889.  
  890. If anyone receives this message that does not yet have access to this utility
  891. but would like to use it, send me a mail message and I can send you the
  892. appropriate files with instructions.
  893.  
  894. If you are not familiar with Emacs, some of the terms used below may be
  895. foreign to you (buffers, modes, key sequences, etc.).  However, Emacs comes
  896. with an excellent tutorial that will teach you the basics (just press
  897. Control-H, then the letter "T", 'C-h t', after starting Emacs) as well as full
  898. on-line documentation (C-h i).
  899.  
  900.  
  901. Description
  902. ===========
  903.  
  904. Here is a brief description of the enhancements that this utility adds to 
  905. SQL*Plus (features added since version 1.1 are indicated with NEW!):
  906.  
  907.         * Fully compatible with SQL*Plus.  If none of the new features
  908.           are accessed, SQL*Plus looks and behaves exactly like it
  909.           does normally.  You can enter commands one line at a time and
  910.           use all the awkward line editing commands you've become
  911.           accustomed to. 
  912.  
  913.         * Full history buffer.  All text entered and received in the 
  914.           current session is stored so you can scroll forward and back
  915.           to examine prior results.
  916.  
  917. NEW!    * Save history between sessions.  You have the option of saving
  918.           your sessions automatically so that the next time SQL*Plus
  919.           is invoked, you are returned to where you left off--with all
  920.           prior input and output intact!
  921.  
  922.         * Full command line editing.  All of Emacs' editing commands
  923.           may be used to correct errors in the current input line before
  924.           pressing RETURN.  When entering multi-line statements you may
  925.           easily move up to prior lines to change them before executing
  926.           the entire statement.
  927.  
  928.         * Recall, edit, and re-execute prior commands.  Any prior command
  929.           entered in the buffer may be modified and re-executed.  Also, 
  930.           full cut and paste of commands or parts or commands is supported
  931.           using standard Emacs features.
  932.  
  933.         * Entry shortcuts.  Single letter abbreviations are provided for
  934.           commonly used keywords.  For example, typing S<space> inserts 
  935.           "SELECT ".  Also, any other keyword, table, or column name
  936.           used earlier may be abbreviated with the first few letters
  937.           (see dynamic expansion below).
  938.  
  939. NEW!    * Powerful "word grab" feature.  Position the cursor on a column
  940.           or table name and with the press of a key, the text is appended
  941.           to the end of the current SQL statement.  Commas are even inserted
  942.           automatically when appropriate!
  943.  
  944. NEW!    * Run multiple SQL*Plus sessions simultaneously.  Using Emacs'
  945.           multiple buffer/window features, two or more sessions may be
  946.           active concurrently--each attached to a different database if
  947.           desired.
  948.  
  949.         * Edit SQL*Plus batch files and execute them with a keystroke.
  950.           You no longer need to use the EDIT or HOST commands to move
  951.           in and out of a full screen editor while refining SQL scripts.  
  952.           Just edit in one Emacs window and with the press of a key, the 
  953.           commands will be executed with the output appearing in a second 
  954. NEW!      window. You can even execute SQL statements imbedded in a 
  955.           SQL*Report, SQL*Forms (.inp), or Pro*C (Fortran, COBOL, etc.) file!
  956.  
  957.         * On-line help.  Help is available in any mode by pressing C-h m.
  958.           (This is true of all Emacs modes, not just the new SQL modes.) 
  959.           You can also get help on any key sequence with C-h k <key sequence>.
  960.  
  961.         * Multi-tasking!  Since you are in Emacs, you can perform
  962.           other tasks while you wait for a complex SQL statement to finish
  963.           executing.  Switch to another document, open a new window, 
  964.           compose a letter, run an operating system shell, and if Emacs
  965.           is run from the Unix c-shell, it can be "suspended" and you 
  966.           can return to it later.
  967.  
  968. This utility is implemented as an Emacs "major mode" for editing text. There
  969. are actually two new major modes.  The first is sqlplus-mode which runs a
  970. SQL*Plus session in a buffer called *sqlplus* and allows you to edit and
  971. re-execute prior commands, as well as providing a history of all interaction.
  972. This mode is similar to shell-mode (and is, in fact, based upon it), but with
  973. additional features specific to SQL*Plus.
  974.  
  975. Another mode called sql-mode can be used to edit SQL*Plus batch programs which
  976. can then be executed with a keypress with the output appearing in another
  977. window.
  978.  
  979. Like most other special Emacs modes, the commands unique to these new modes
  980. are accessed using a keystroke sequence of Control-C followed by another
  981. control character.
  982.  
  983.  
  984. SQL*Plus Mode
  985. =============
  986.  
  987. To experiment with the interactive SQL*Plus mode, invoke Emacs with these
  988. options: 
  989.  
  990.         emacs -l sql-mode -f sqlplus
  991.  
  992. You will be prompted to enter a username/password combination to access an
  993. Oracle database.  Interaction in the *sqlplus* buffer is exactly like normal
  994. SQL*Plus, including its limited editing capabilities, if all commands are
  995. entered at the end of the buffer.  Prior commands may be recalled, edited, and
  996. re-executed in the following ways.
  997.  
  998.         1) Manually cursor back up to the command to be edited, make changes,
  999.            then press [Return] when the cursor is on any line of a multi-line
  1000.            statement.  This is convenient after a command that produces a
  1001.            small amount of output or after a LIST command.
  1002.  
  1003.         2) Use C-c C-b and C-c C-f (back/forward command) to move the cursor to
  1004.            the previous or next command in the buffer.  Then edit and
  1005.            re-execute by pressing [Return].  C-c C-b is also useful after a
  1006.            command has produced several pages of output and you wish to begin
  1007.            reviewing it from the beginning.  I have these commands bound to
  1008.            ESC up-arrow and ESC down-arrow in my .emacs file.
  1009.  
  1010.         3) Use C-c C-p and C-c C-n (previous/next command) to recall the prior
  1011.            commands directly after the last prompt at the end of the buffer.
  1012.            When the desired command has been recalled, press [Return] to
  1013.            execute, or edit and then re-execute with [Return].
  1014.  
  1015.  
  1016. Typing Shortcuts
  1017. ----------------
  1018.  
  1019. A powerful feature which is built into Emacs is the use of abbreviations.  In
  1020. sqlplus-mode, standard abbreviations are automatically available for common
  1021. keywords such as DESCRIBE, SELECT, FROM, WHERE, ORDER BY, etc. by entering the
  1022. first letter followed by space or tab.  You may add to or modify this table
  1023. and save it for later use (consult an Emacs manual or the on-line
  1024. documentation for more information on using abreviations).
  1025.  
  1026. Dynamic abbreviations are also very useful.  Entering the first few characters
  1027. of a table or column name (or any other word) included anywhere in the buffer
  1028. and typing M-/ (note: M = ESC) will complete the name; successive M-/'s will
  1029. cycle through all matches.  I use this after "DESCRIBE table" so that all
  1030. column names are conveniently available.
  1031.  
  1032. Another way to quickly and easily build queries after using DESCRIBE is to
  1033. position the cursor over (or after) the first column name you wish to SELECT
  1034. and press C-c C-w (copy word).  If the command line at the end of the buffer
  1035. is blank, "SELECT" will be inserted, followed by the column name.  Repeat this
  1036. for each column to be selected and the names will be appended to the line with
  1037. commas separating each entry.  This technique may also be used to copy words
  1038. from an earlier line of the same statement while entering expressions,
  1039. comparisons, or ORDER BY clauses.  Building SELECT statements has never been
  1040. so easy!
  1041.  
  1042.  
  1043. Saving Your Session
  1044. -------------------
  1045.  
  1046. Since all output is saved in the buffer, you can easily scroll back to review
  1047. prior queries, without having to re-execute them.  You may also save your
  1048. session with C-c C-s (or M-x sqlplus-save-session) to any file and re-load it
  1049. later with C-x i (insert-file).  A better option is to have Emacs do this
  1050. for you when you exit.  By setting the the Emacs variable sqlplus-keep-history
  1051. to a non-nil value in your .emacs file, your session will saved in the file
  1052. .sqlhist in your home directory and automatically loaded the next time sqlplus
  1053. is run (an example of how to set this variable is included later).
  1054.  
  1055. Since your .sqlhist file is likely to grow very large after only a few
  1056. sessions, I have provided some ways of preventing the history buffer from
  1057. growing too large.  When you exit SQL*Plus by typing EXIT or QUIT, the number
  1058. of lines in the buffer is compared with the variable sqlplus-lines-to-keep,
  1059. which defaults to 1000.  If it is larger, you will be asked if you wish to
  1060. tuncate the buffer to the indicated size before saving (the oldest lines will
  1061. be deleted).  You can also perform this truncation at any time during your
  1062. session with the command C-c C-d (delete old lines).  If you wish to exit
  1063. without saving the session, use C-x k (kill-buffer).
  1064.  
  1065. Another way to drastically shrink the buffer is with C-c C-x which deletes all
  1066. output lines in the buffer, keeping only the commands that have been entered.
  1067. This way you still have access to prior commands for re-execution.  
  1068.  
  1069. After entering a SQL command that generates an error, or produces a report
  1070. that still is not quite correct, rather than recall the command to edit and
  1071. re-execute it, use C-c C-k (kill) which deletes either the last output
  1072. generated by SQL*Plus or the current command being entered, depending on where
  1073. the cursor is when it is used.  If executed while the cursor is within a SQL
  1074. statement, the statement and any text after it are deleted.  If the cursor is
  1075. within or at the end of output generated by SQL*Plus, the output is deleted
  1076. and the cursor is positioned at the end of the SQL statement that generated
  1077. the output.  Thus, it can be used like an undo command to alternately delete
  1078. commands and output from the end of the buffer.  This helps prevent the buffer
  1079. from growing as a result of several "false starts" and makes finding prior
  1080. valid commands easier (because you don't have to wade through several bad
  1081. commands and their associated output).
  1082.  
  1083.  
  1084.  
  1085. which will also kill the process (but will not save your session).
  1086.  
  1087.  
  1088. Summary of Commands
  1089. -------------------
  1090.  
  1091.         C-c C-p   Recall previous command.
  1092.         C-c C-n   Recall next command.
  1093.         C-c C-b   Back one command.
  1094.         C-c C-f   Forward one command.
  1095.         C-c C-e   Move end of buffer (like M->, but does not set the mark.)
  1096.         C-c C-r   Return to beginning of last output produced by SQL*Plus.
  1097.         C-c C-c   Send ^C to interrupt current command execution.
  1098. NEW!    C-c C-k   Kill current SQL statement or last output.
  1099. NEW!    C-c C-x   Delete all output lines.
  1100. NEW!    C-c C-d   Drop old lines (truncate to value of sqlplus-lines-to-keep).
  1101. NEW!    C-c C-w   Copy word to end.
  1102. NEW!    C-c C-s   Save session to file.
  1103.  
  1104. You can generate a list like this while in sqlplus-mode by typing C-h m (Help
  1105. with current Mode) or C-h b (Help keyBindings).  You can also get help on any
  1106. specific command with C-h k (Help Key) followed by the key sequence.
  1107.  
  1108.  
  1109. SQL Edit Mode
  1110. =============
  1111.  
  1112. In a text buffer, the command 'M-x sql-mode' will enable SQL text editing
  1113. mode.  The keyword abbreviations described above are also available in this
  1114. mode.  Two special commands are provided to execute the SQL*Plus statements
  1115. contained in a sql-mode buffer.  C-c C-x will send the entire buffer to
  1116. SQL*Plus.  The output is displayed in the *sqlplus* buffer in a second window
  1117. (if SQL*Plus is not currently running, a new buffer is created and the process
  1118. started).  C-c C-r will send the commands in the currently defined region
  1119. (between point and mark).  This feature may be useful to Pro*C programmers who
  1120. need to test SQL statements imbedded in their code.
  1121.  
  1122. If the SQL statements to be executed contain variables prefixed with colons
  1123. or INTO clauses, the colons are converted into ampersands and the INTO clauses
  1124. are removed before being sent to SQL*Plus.  This provides compatibility with
  1125. Pro*C, SQL*Report, and SQL*Forms (.inp files).  For example,
  1126.  
  1127.      SELECT SYSDATE + :days_added INTO :variable FROM SYSTEM.DUAL
  1128.  
  1129. is converted to
  1130.  
  1131.      SELECT SYSDATE + &days_added FROM SYSTEM.DUAL
  1132.  
  1133. and the user is prompted to enter the value of days_added.  This substitution
  1134. process can be prevented by using a prefix argument with the
  1135. sqlplus-send-region command.  In practice, this is done by typing 'C-u C-c
  1136. C-r'.  Also, variables of the form :block_name.field_name are converted to
  1137. &block_name_field_name for convenience when editing .inp files.
  1138.  
  1139. In the future, this mode may automatically indent your SQL*Plus code based on
  1140. Oracle standards (if they have been defined).  Your suggestions are welcome.
  1141.  
  1142.  
  1143. Accessing the New Modes
  1144. =======================
  1145.  
  1146. If Emacs is started normally, the new modes will not be available until the
  1147. new library is loaded with the command:
  1148.  
  1149.          M-x load-library RET sql-mode RET      (RET = the RETURN key)
  1150.  
  1151. Or Emacs can be invoked with the option '-l sql-mode'.
  1152.  
  1153. Once the library is loaded, the commands 'M-x sqlplus' and 'M-x sql-mode' can
  1154. be used.  This can be automated by including the following commands in your
  1155. .emacs file:
  1156.  
  1157.         (autoload 'sql-mode "sql-mode" "SQL editing mode" t)
  1158.         (autoload 'sqlplus "sql-mode" "Run SQL*Plus interactively" t)
  1159.  
  1160. This will load the sql-mode library the first time either of these commands is
  1161. used.
  1162.  
  1163. Sql-mode can be invoked automatically whenever a file ending in .sql is edited
  1164. by including this command in .emacs:
  1165.  
  1166.    (setq auto-mode-alist (cons '("\\.sql$" . sql-mode) auto-mode-alist))
  1167.  
  1168. Note: The above statements may eventually be added to the global
  1169. initialization files used on each machine where Emacs is loaded
  1170. (i.e. site-init.el).
  1171.  
  1172.  
  1173. Customizing Your Environment
  1174. ============================
  1175.  
  1176. When sqlplus is initially executed, you will be prompted to enter a username
  1177. and password to access an Oracle database.  If you always use the same
  1178. username/password combination, this can be suppressed by setting a special
  1179. variable in your .emacs file as follows:
  1180.  
  1181.         (setq sqlplus-username-password "myname/mypassword")
  1182.  
  1183. You may also wish to assign some of the special functions to more convenient
  1184. keys on your keyboard.  Each of these modes calls a "hook" routine (like all
  1185. other Emacs modes).  By assigning custom routines to these hooks, you can add
  1186. additional functionality.  Below are some statements that will assign common
  1187. commands used in sqlplus and sql-mode to VT320 function keys.
  1188.  
  1189. (global-unset-key "\e\e"              ; allow ESC as a prefix to function keys
  1190. (setq sql-mode-hook 'set-sql-keys)
  1191. (setq sqlplus-mode-hook 'set-sqlplus-keys)
  1192.  
  1193. (defun set-sql-keys ()
  1194.   "Customize sql-mode keys."
  1195.   (local-set-key "\eOM" 'sql-send-buffer)                 ; Enter
  1196.   (local-set-key "\e\eOM" 'sql-send-region))              ; ESC Enter
  1197.  
  1198. (defun set-sqlplus-keys ()
  1199.   "Customize sqlplus-mode keys."
  1200.   (local-set-key "\e\eOA" 'sqlplus-back-command)          ; ESC up-arrow
  1201.   (local-set-key "\e\eOB" 'sqlplus-forward-command)       ; ESC down-arrow
  1202.   (local-set-key "\e\eOD" 'sqlplus-previous-command)      ; ESC left-arrow
  1203.   (local-set-key "\e\eOC" 'sqlplus-next-command)          ; ESC right-arrow
  1204.   (local-set-key "\e\r" 'sqlplus-end-of-buffer))          ; ESC Return
  1205.  
  1206. These key bindings will only be active in the buffers running the new modes
  1207. and thus will not affect other functions assigned to the same keys in other
  1208. buffers.
  1209.  
  1210. SQL*Plus reads and executes the contents of the file login.sql in your home
  1211. directory when it starts up.  If you have modified the default parameters you
  1212. may need to make changes to this file for compatibility with sqlplus-mode.
  1213.  
  1214. The current version requires that the SQL*Plus prompt be "SQL> " and that
  1215. continuation prompts are numbered lines (the default), so do not change the
  1216. settings of the SQL*Plus variables 'sqlprompt' or 'sqlnumber'.  Page pause
  1217. should be left OFF (set pause off) since you can page forward and back using
  1218. Emacs commands (although setting pause ON will still work).
  1219.  
  1220. Since Emacs automatically wraps long lines you can set the line length used by
  1221. SQL*Plus to the maximum value (set linesize 500).  Then if your terminal
  1222. supports wide displays or variable size windows, long lines will always wrap
  1223. to fit (however, this will also affect the centering of titles).
  1224.  
  1225.  
  1226. Known Bugs 
  1227. ==========
  1228.  
  1229. When entering a new command, if you move up to a prior line (of the same
  1230. multi-line statement), make a change, then move back to the last line and
  1231. finish entering it, SQL*Plus will not see the change--it will only process the
  1232. last line entered.  However, if you move up to any line except the last one
  1233. before pressing [Return], all lines will be re-evaluated when the command is
  1234. executed.
  1235.  
  1236. If you discover additional bugs or think of some good enhancements, send them
  1237. via email to jlange@us.oracle.com, or call me at (415) 506-4669.
  1238.  
  1239.     -Jim Lange
  1240.  
  1241.  
  1242.  
  1243.  
  1244.