The code files. Taken from assembla working copy

This commit is contained in:
Éibhear Ó hAnluain 2016-10-05 21:35:21 +01:00
parent 9403a67ac7
commit aeeab31ecf
4 changed files with 2727 additions and 0 deletions

765
enode-lisp/enode-oracle.el Executable file
View file

@ -0,0 +1,765 @@
(defun enode-oracle-connect (conn-user conn-pass conn-connection conn-prompt)
"A function to connect to an oracle database."
;; Create a temporary buffer and go to it.
(with-temp-buffer
;; Set it to be an SQL commands buffer.
(sql-mode)
;; Put in the connection and sqlprompt modification commands, and
;; set the serverout on.
(insert
(format "\nconnect %s/%s@%s\nset serverout on\nset sqlprompt \"%s> \"\n"
conn-user
conn-pass
conn-connection
conn-prompt))
;; Send the temp buffer to the *SQL* process buffer.
(sql-send-region (point-min) (point-max))
)
)
(defun enode-oracle-disconnect ()
"A function to close an oracle database connection."
(with-temp-buffer
(sql-mode)
(insert (format "\ndisconnect\n"))
(sql-send-region (point-min) (point-max))
(enode-oracle-sqlplus-set-prompt "NOP")
)
)
(defun enode-oracle-start-sql-engine ()
"A function to set up the SQL engine for connecting to an Oracle database.
Currently, only SQL*Plus is supported."
(call-interactively 'sql-oracle)
;; Set the prompt regexps properly
(save-excursion
(set-buffer "*SQL*")
(setq comint-prompt-regexp "^[0-9A-Za-z]\\{3\\}> ")
(setq sql-prompt-regexp "^[0-9A-Za-z]\\{3\\}> ")
;; (enode-oracle-sqlplus-set-timing "on")
)
)
(defun enode-oracle-stop-sql-engine ()
"A function to close the engine connecting to the oracle database.
Currently, only SQL*Plus is supported."
;; Kludge to get around the fact that redirecting output from exit
;; doesn't really work.
(comint-send-string (get-buffer-process sql-buffer) (format "exit\n"))
(sleep-for 3)
;; (with-temp-buffer
;; (enode-oracle-run-sql-command "exit"
;; (current-buffer)
;; sql-buffer
;; t)
;; )
)
(defun enode-oracle-list-users (user-list-buffer)
"A function to list the users in an Oracle database."
(let ((user-list-command
(format "select username from all_users order by username;"))
)
;; Run the SQL command.
(enode-oracle-run-sql-command user-list-command
user-list-buffer
sql-buffer)
)
)
(defun enode-oracle-desc (object-name desc-buffer)
"A function to run the SQL DESCRIBE command for an object and to present
the output."
(let ((desc-command (format "desc %s" object-name)))
(enode-oracle-run-sql-command desc-command
desc-buffer
sql-buffer)
)
)
(defun enode-oracle-list-objects (object-list-buffer dbuser
&optional object-type
invalid-flag
filter-string)
"A function to get up a list of objects in an oracle database."
(let ((object-list-command
(format "%s%s%s;"
"select object_name, object_type, status "
(format "from %s " (if dbuser "all_objects" "user_objects"))
(let (have-where
where-clause)
(if dbuser
(if have-where
(setq where-clause
(concat where-clause
" "
(format "and owner = '%s' " dbuser)
)
)
(setq where-clause
(format "where owner = '%s' " dbuser))
(setq have-where t)
)
)
(if object-type
(if have-where
(setq where-clause
(concat where-clause
" "
(format "and object_type = '%s' "
object-type)
)
)
(setq where-clause
(format "where object_type = '%s' "
object-type))
(setq have-where t)
)
)
(if invalid-flag
(if have-where
(setq where-clause
(concat where-clause
" and status = 'INVALID' "
)
)
(setq where-clause
"where status = 'INVALID' ")
(setq have-where t)
)
)
(if filter-string
(if have-where
(setq where-clause
(concat where-clause
" and object_name like '%"
filter-string
"%' "
)
)
(setq where-clause
(concat "where object_name like '%"
filter-string
"%' ")
)
(setq have-where t)
)
)
where-clause
)
)
)
)
(enode-oracle-run-sql-command object-list-command
object-list-buffer
sql-buffer)
)
)
(defun enode-oracle-list-object-types (object-type-list-buffer
&optional dbuser)
"A function to show the list of object types in an oracle database broken
down by user. If DBUSER is non-nil, list only for that user."
(let ((object-type-list-command
(format "%s%s%s%s%s;"
"select owner, object_type, count(*) "
"from all_objects "
(if dbuser (format "where owner = '%s' " (upcase dbuser)) "")
"group by owner, object_type "
"order by owner, object_type "
))
)
;; Run the SQL command.
(enode-oracle-run-sql-command object-type-list-command
object-type-list-buffer
sql-buffer)
)
)
(defun enode-oracle-run-sql-command (sql-command output-buffer sql-buffer
&optional asynchronous)
"A function to run an SQL command in a synchronous manner. If ASYNCHRONOUS is non-nil, it's run, you guessed it, asynchronously."
;; Run it as though it's from where we're calling it.
(save-excursion
;; Run the command, not echoing the output.
(comint-redirect-send-command-to-process sql-command
output-buffer
sql-buffer
nil)
;; If we don't want to pretend it's synchronous, don't
(if (not asynchronous)
(enode-wait-for-command)
)
)
)
(defun enode-oracle-pls-code-max-length (pls-name pls-type &optional pls-owner)
"A function to return the length of the longest line in a block of
stored PL/SQL code."
;; Do all this in a temporary buffer
(with-temp-buffer
;; Get the buffer name
(let ((my-buffer (current-buffer))
;; Determine the code to run
(plsql-code-line-length-command
(format "%s%s%s%s%s;"
"select max ( length ( text ) ) "
(format "from %s " (if pls-owner "all_source"
"user_source"))
(format "where name = '%s' " (upcase pls-name))
(format "and type = '%s' " (upcase pls-type))
(if pls-owner (format "and owner = '%s' "
(upcase pls-owner))
""))))
;; Run the command synchronously
(enode-oracle-run-sql-command plsql-code-line-length-command
my-buffer
sql-buffer)
;; Go to the buffer
(set-buffer my-buffer)
;; Go to the end
(goto-char (point-max))
;; Look back for the returned value
(re-search-backward "^[ ]+\\([0-9]+\\)[ ]*$")
;; and return it.
(match-string 1)
)
)
)
(defun enode-oracle-get-pls-code (pls-name pls-type &optional pls-owner)
"A function to present a block of PL/SQL code. Really should be called from
a wrapper. PLS-NAME is the name of the PL/SQL block, PLS-TYPE is its type
function, package, etc. and PLS-OWNER is the block's owner. If
PLS-OWNER is NIL, assume the current user."
;; Get the length of the longest line of the code block
(let ((block-line-length
(enode-oracle-pls-code-max-length pls-name pls-type pls-owner))
;; Determine the current SQL*Plus state
(current-sqlplus-state (enode-oracle-sqlplus-get-state))
;; Get a buffer for the code.
(code-buffer (enode-oracle-plsql-code-buffer pls-name pls-owner))
)
;; Set the SQL*Plus state to something that's suitable for this
;; '(LINESIZE PAGESIZE TIMING HEADING FEEDBACK LONG TRIMOUT TRIMSPOOL
;; LONGCHUNKSIZE TERMOUT)
(enode-oracle-sqlplus-set-state (list block-line-length 0 nil "off"
"off" nil)
)
;; Create the SQL code to get the PL/SQL code.
(let ((plsql-code-command
(format "%s%s%s%s%s%s;"
"select text "
(format "from %s " (if pls-owner "all_source"
"user_source"))
(format "where name = '%s' " (upcase pls-name))
(format "and type = '%s' " (upcase pls-type))
(if pls-owner (format "and owner = '%s' "
(upcase pls-owner))
"")
"order by line")))
;; Run the command.
(enode-oracle-run-sql-command plsql-code-command code-buffer sql-buffer)
)
;; Restore the state
(enode-oracle-sqlplus-set-state current-sqlplus-state)
(save-excursion
;; Go to the buffer with the code.
(set-buffer code-buffer)
;; It's PL/SQL code, set the mode.
(pls-mode)
)
(display-buffer code-buffer)
)
)
(defun enode-oracle-timing-on ()
"Turn on timing reports for SQL*Plus commands"
(interactive)
(enode-oracle-sqlplus-set-timing "on")
)
(defun enode-oracle-get-pls-package-code (proc-name &optional proc-owner)
"A function to return the code of a PL/SQL package spec."
(interactive (list (read-from-minibuffer "Package Name: ")))
(enode-oracle-get-pls-code proc-name "package" proc-owner))
(defun enode-oracle-get-pls-package-body-code (proc-name &optional proc-owner)
"A function to return the code of a PL/SQL package body."
(interactive (list (read-from-minibuffer "Package Name: ")))
(enode-oracle-get-pls-code proc-name "package body" proc-owner))
(defun enode-oracle-get-pls-procedure-code (proc-name &optional proc-owner)
"A function to return the code of a PL/SQL procedure."
(interactive (list (read-from-minibuffer "Procedure Name: ")))
(enode-oracle-get-pls-code proc-name "procedure" proc-owner))
(defun enode-oracle-get-pls-function-code (func-name &optional func-owner)
"A function to return the code of a PL/SQL function."
(interactive (list (read-from-minibuffer "Function Name: ")))
(enode-oracle-get-pls-code func-name "function" func-owner))
(defun enode-oracle-sqlplus-get-state ()
"A function to determine the current state of the SQL*Plus interface. It
returns a list in the following format '(LINESIZE PAGESIZE TIMING HEADING FEEDBACK LONG TRIMOUT TRIMSPOOL LONGCHUNKSIZE TERMOUT)."
;; Get the settings.
(let ((current-linesize (enode-oracle-sqlplus-get-linesize))
(current-pagesize (enode-oracle-sqlplus-get-pagesize))
(current-timing (enode-oracle-sqlplus-get-timing))
(current-heading (enode-oracle-sqlplus-get-heading))
(current-feedback (enode-oracle-sqlplus-get-feedback))
(current-long (enode-oracle-sqlplus-get-long))
(current-trimout (enode-oracle-sqlplus-get-trimout))
(current-trimspool (enode-oracle-sqlplus-get-trimspool))
(current-longchunksize (enode-oracle-sqlplus-get-longchunksize))
(current-termout (enode-oracle-sqlplus-get-termout))
)
;; Return the settings as a list.
(list current-linesize current-pagesize current-timing current-heading
current-feedback current-long current-trimout current-trimspool
current-longchunksize current-termout)
)
)
(defun enode-oracle-sqlplus-set-state (sqlplus-state)
"A function to put the current SQL*Plus interface into a certain statd. It
takes a list in the following format '(LINESIZE PAGESIZE TIMING HEADING FEEDBACK LONG TRIMOUT TRIMSPOOL LONGCHUNKSIZE TERMOUT).
If any of this is NIL, it's not touched"
;; Determine the settings
(let ((new-linesize (nth 0 sqlplus-state))
(new-pagesize (nth 1 sqlplus-state))
(new-timing (nth 2 sqlplus-state))
(new-heading (nth 3 sqlplus-state))
(new-feedback (nth 4 sqlplus-state))
(new-long (nth 5 sqlplus-state))
(new-trimout (nth 6 sqlplus-state))
(new-trimspool (nth 7 sqlplus-state))
(new-longchunksize (nth 8 sqlplus-state))
(new-termout (nth 9 sqlplus-state))
)
;; For each of the settings that are specified in the parameter,
;; set it.
(if new-linesize (enode-oracle-sqlplus-set-linesize new-linesize))
(if new-pagesize (enode-oracle-sqlplus-set-pagesize new-pagesize))
(if new-timing (enode-oracle-sqlplus-set-timing new-timing))
(if new-heading (enode-oracle-sqlplus-set-heading new-heading))
(if new-feedback (enode-oracle-sqlplus-set-feedback new-feedback))
(if new-long (enode-oracle-sqlplus-set-long new-long))
(if new-trimout (enode-oracle-sqlplus-set-trimout new-trimout))
(if new-trimspool (enode-oracle-sqlplus-set-trimspool new-trimspool))
(if new-longchunksize
(enode-oracle-sqlplus-set-longchunksize new-longchunksize))
(if new-termout (enode-oracle-sqlplus-set-termout new-termout))
)
)
(defun enode-oracle-plsql-code-buffer
(&optional pls-block-name pls-block-owner)
"A function to return a buffer to contain the code of a PL/SQL object. The
name of the buffer encorporates the name of the block if not nil"
(enode-code-buffer "plsql" pls-block-name pls-block-owner)
)
(defun enode-oracle-view-code-buffer
(&optional view-name view-owner)
"A function to return a buffer to contain the code of a view. The
name of the buffer encorporates the name of the block if not nil"
(enode-code-buffer "view" view-name view-owner)
)
(defun enode-oracle-view-length (view-name &optional view-owner)
"A function to return the length of the code making up the definition of
a view."
;; Do all this in a temporary buffer
(with-temp-buffer
;; What buffer?
(let ((my-buffer (current-buffer))
;; Create the SQL command to determine the value
(view-code-length-command
(format "%s%s%s%s;"
"select text_length "
(format "from %s " (if view-owner "all_views"
"user_views"))
(format "where view_name = '%s' " (upcase view-name))
(if view-owner (format "and owner = '%s' "
(upcase view-owner))
""))))
;; Run the command.
(enode-oracle-run-sql-command view-code-length-command
my-buffer
sql-buffer)
;; Go to the output buffer
(set-buffer my-buffer)
;; Go to the end.
(goto-char (point-max))
;; Look for the output
(re-search-backward "^[ ]+\\([0-9]+\\)[ ]*$")
;; Return it
(match-string 1)
)
)
)
(defun enode-oracle-get-view-code (view-name &optional view-owner)
"A function to present the code that makes up a view."
(interactive (list (read-from-minibuffer "View name: ")))
;; Get the current SQL*Plus state
(let ((current-sqlplus-state (enode-oracle-sqlplus-get-state))
;; The buffer to send the code to
(code-buffer (enode-oracle-view-code-buffer view-name view-owner))
)
;; Set the SQL*Plus state to something that is suitable.
;; '(LINESIZE PAGESIZE TIMING HEADING FEEDBACK LONG TRIMOUT TRIMSPOOL
;; LONGCHUNKSIZE TERMOUT)
(enode-oracle-sqlplus-set-state (list 2499 0 "off" "off" "off" 5242880 "on"
"on" 2499 "off"))
;; Create the command to get the code.
(let ((view-command
;; select dbms_metadate.get_ddl ( 'VIEW', '<<VIEW_NAME>>' )
;; from dual
(format "%s%s%s;"
"select dbms_metadata.get_ddl ( 'VIEW', '"
(upcase view-name)
"' ) from dual"
)))
;; Run the command.
(enode-oracle-run-sql-command view-command code-buffer sql-buffer)
)
;; Restore the SQL*Plus state.
(enode-oracle-sqlplus-set-state current-sqlplus-state)
(save-excursion
;; Go to the buffer
(set-buffer code-buffer)
;; It's SQL code. Set the mode.
(sql-mode)
)
(display-buffer code-buffer)
)
)
;;;; Change this to use enode-oracle-run-sql-command
(defun enode-oracle-sqlplus-get-param (sql-setting-command sql-setting-regexp)
"A function to get an SQL*Plus setting. It simply runs SQL-SETTING-COMMAND
and looks in the output for the first parenthesized expression in
SQL-SETTING-REGEXP."
;; We don't want to disturb anything, now do we?
(save-excursion
;; Get an empty output buffer
(let ((output-buffer (enode-temp-output-buffer)))
;; Send the command that was passed to get the setting.
(comint-redirect-send-command-to-process
sql-setting-command output-buffer sql-buffer nil t)
;; Go to the output buffer
(set-buffer output-buffer)
;; Wait a short period for the command to complete
(enode-wait-for-command)
;; Go to the last position
(goto-char (point-max))
;; Search backwards for the passed regular expression
(search-backward-regexp sql-setting-regexp nil t)
;; Return the first parenthesised expression from a matched string.
(match-string 1)
)
)
)
(defun enode-oracle-get-sql-prompt ()
"A function to get the setting of the SQL*Plus prompt"
(format "%s"
(enode-oracle-sqlplus-get-param
"show sqlprompt" "sqlprompt \"\\([^\"]*\\)\"$")
)
)
(defun enode-oracle-sqlplus-set-prompt (value)
"A function to set the 'sqlprompt' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "sqlprompt" (concat "\"" value "> \""))
)
(defun enode-oracle-sqlplus-get-linesize ()
"A function to get the 'linesize' SQL*Plus setting"
(format "%s"
(enode-oracle-sqlplus-get-param
"show linesize" "linesize \\([0-9]+\\)$")
)
)
(defun enode-oracle-sqlplus-set-linesize (value)
"A function to set the 'linesize' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "linesize" value)
)
(defun enode-oracle-sqlplus-get-long ()
"A function to get the 'long' SQL*Plus setting"
(format "%s"
(enode-oracle-sqlplus-get-param
"show long" "long \\([0-9]+\\)$")
)
)
(defun enode-oracle-sqlplus-set-long (value)
"A function to set the 'long' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "long" value)
)
(defun enode-oracle-sqlplus-get-longchunksize ()
"A function to get the 'longchunksize' SQL*Plus setting"
(format "%s"
(enode-oracle-sqlplus-get-param
"show longchunksize" "longchunksize \\([0-9]+\\)$")
)
)
(defun enode-oracle-sqlplus-set-longchunksize (value)
"A function to set the 'longchunksize' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "longchunksize" value)
)
(defun enode-oracle-sqlplus-get-pagesize ()
"A function to get the 'pagesize' SQL*Plus setting"
(format "%s"
(enode-oracle-sqlplus-get-param
"show pagesize" "^pagesize \\([0-9]+\\)$")
)
)
(defun enode-oracle-sqlplus-set-pagesize (value)
"A function to set the 'pagesize' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "pagesize" value)
)
(defun enode-oracle-sqlplus-get-heading ()
"A function to get the 'heading' SQL*Plus setting"
(format "%s"
(enode-oracle-sqlplus-get-param
"show heading" "^heading \\(O[NF]+\\)$")
)
)
(defun enode-oracle-sqlplus-set-heading (value)
"A function to set the 'heading' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "heading" value)
)
(defun enode-oracle-sqlplus-get-timing ()
"A function to get the 'timing' SQL*Plus setting"
(format "%s"
(enode-oracle-sqlplus-get-param
"show timing" "^timing \\(O[NF]+\\)$")
)
)
(defun enode-oracle-sqlplus-set-timing (value)
"A function to set the 'timing' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "timing" value)
)
(defun enode-oracle-sqlplus-get-termout ()
"A function to get the 'termout' SQL*Plus setting"
(format "%s"
(enode-oracle-sqlplus-get-param
"show termout" "^termout \\(O[NF]+\\)$")
)
)
(defun enode-oracle-sqlplus-set-termout (value)
"A function to set the 'termout' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "termout" value)
)
(defun enode-oracle-sqlplus-get-trimout ()
"A function to get the 'trimout' SQL*Plus setting"
(format "%s"
(enode-oracle-sqlplus-get-param
"show trimout" "^trimout \\(O[NF]+\\)$")
)
)
(defun enode-oracle-sqlplus-set-trimout (value)
"A function to set the 'trimout' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "trimout" value)
)
(defun enode-oracle-sqlplus-get-trimspool ()
"A function to get the 'trimspool' SQL*Plus setting"
(format "%s"
(enode-oracle-sqlplus-get-param
"show trimspool" "^trimspool \\(O[NF]+\\)$")
)
)
(defun enode-oracle-sqlplus-set-trimspool (value)
"A function to set the 'trimspool' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "trimspool" value)
)
(defun enode-oracle-sqlplus-get-feedback ()
"A function to get the 'feedback' SQL*Plus setting"
(format "%s"
(enode-oracle-sqlplus-get-param
"show feedback" "^FEEDBACK \\(O[NF]+\\).*$")
)
)
(defun enode-oracle-sqlplus-set-feedback (value)
"A function to set the 'feedback' SQL*Plus parameter to VALUE."
(enode-oracle-sqlplus-set-param "feedback" value)
)
;; This is useful for main ENODE environment.
;;;; Is this necessary if we user with-temp-buffer()?
(defun enode-temp-output-buffer ()
"A function to return the temporary output buffer for redirected SQL
commands. If the buffer already exists, it empties it first.
Call this function directly if you don't care about the output. Set a variable
to this function's return value if you want to process it once the command
has completed."
;; Get the buffer
(let ((the-buffer (get-buffer-create " *enode-comint-sql-output*")))
;; Empty it.
(enode-clean-buffer the-buffer)
;; Return it
the-buffer
)
)
;; This is useful for main ENODE environment.
;;;; Is this necessary if we user with-temp-buffer()?
(defun enode-stage-buffer ()
"A function to provide a buffer for staging commands out of."
(let ((the-buffer (get-buffer-create " *enode-stage-buffer*")))
;; Empty it
(enode-clean-buffer the-buffer)
;; Return it
the-buffer
)
)
;;;; Change this to use enode-oracle-run-sql-command
(defun enode-oracle-sqlplus-set-param (param value)
"A function to set an sqlplus parameter, PARAM, to VALUE."
(comint-redirect-send-command-to-process
(format "set %s %s\n" param value)
(enode-temp-output-buffer)
(get-buffer-process sql-buffer)
nil
t)
(enode-wait-for-command)
)
(defun enode-oracle-get-table-constraints (owner table)
"A function to return a list of tables belonging to OWNER"
(let ((the-command
(format
"select constraint_name from all_constraints where table_name = '%s' and owner = '%s';"
table
owner
)
)
)
(comint-redirect-results-list-from-process
(get-buffer-process sql-buffer)
the-command
"^\\([A-Z0-9_]+\\)$"
1)
)
)
(defun enode-oracle-get-table-indexes (owner table)
"A function to return a list of indexes on TABLE belonging to OWNER"
(let ((the-command
(format
"select index_name from all_indexes where table_name = '%s' and owner = '%s';"
table
owner
)
)
)
(comint-redirect-results-list-from-process
(get-buffer-process sql-buffer)
the-command
"^\\([A-Z0-9_]+\\)$"
1)
)
)
(defun enode-oracle-get-triggers (owner table)
"A function to return a list of indexes on TABLE belonging to OWNER"
(let ((the-command
(format
"select trigger_name from all_triggers where table_name = '%s' and owner = '%s';"
table
owner
)
)
)
(comint-redirect-results-list-from-process
(get-buffer-process sql-buffer)
the-command
"^\\([A-Z0-9_]+\\)$"
1)
)
)
(defun enode-oracle-get-constraint-columns (owner constraint)
"A function to return as a list the names of columns in a constraint
ordered by the position"
(let ((the-command
(format
"select table_name || '.' || column_name from all_cons_columns where constraint_name = '%s' and owner = '%s' order by position;"
constraint
owner
)
)
)
(comint-redirect-results-list-from-process
(get-buffer-process sql-buffer)
the-command
"^\\([\.A-Z0-9_]+\\)$"
1)
)
)
(defun enode-oracle-get-java-source (owner java-source)
"A function to return the source of a stored java program."
(let ((the-command
(format
"select text from all_source where name = '%s' and owner = '%s' and type = 'JAVA SOURCE' order by line;"
java-source
owner
)
)
)
(comint-redirect-send-command-to-process
the-command
(get-buffer-create "*tester*")
(get-buffer-process sql-buffer)
nil)
)
)
(defun enode-oracle-commit (&optional rollback)
"A function to commit changes to an oracle database"
(let ((output-buffer (enode-temp-output-buffer))
response-msg
)
(comint-redirect-send-command-to-process
(if rollback (format "rollback;\n") (format "commit;\n"))
output-buffer
(get-buffer-process sql-buffer)
nil
t)
(enode-wait-for-command)
(save-excursion
(set-buffer output-buffer)
(goto-char (point-min))
(forward-line)
(setq response-msg
(buffer-substring (point) (save-excursion (end-of-line) (point))))
)
(message "%s" response-msg)
)
)
(provide 'enode-oracle)

1132
enode-lisp/enode.el Executable file

File diff suppressed because it is too large Load diff

806
enode-lisp/pls-extras.el Executable file
View file

@ -0,0 +1,806 @@
(require 'pls-mode)
(defvar enode-pls-identifier-regexp
(format "%s%s"
(substring pls-identifier-regexp 0 4)
(substring pls-identifier-regexp 7))
"Removing the capital letters as this has problems later")
(defvar enode-pls-name-regexp
(format "%s%s"
(substring pls-name-regexp 0 4)
(substring pls-name-regexp 7))
"Removing the capital letters as this has problems later")
(defvar enode-pls-white-space-regexp
"\\s-+"
"White space that can separate two tokens."
)
(defvar enode-pls-white-space-newline-regexp
(concat "\\(
\\|\\s-\\)+")
;; \(^J\|\s-\)+
"White space that can separate two tokens, including new-lines."
)
(defvar enode-pls-white-space-maybe-regexp
(concat "\\(\\s-\\)*")
"The possibility of white space"
)
(defvar enode-pls-white-space-newline-maybe-regexp
(replace-regexp-in-string
"\+$" "*" enode-pls-white-space-newline-regexp)
"The possibility of white space, including newlines"
)
(defvar enode-declare-regexp
(concat "^" enode-pls-white-space-maybe-regexp
"declare" enode-pls-white-space-maybe-regexp )
"The DECLARE of an anonymous block"
)
(defvar enode-create-regexp
(concat "^" enode-pls-white-space-maybe-regexp "create\\("
enode-pls-white-space-regexp "or" enode-pls-white-space-regexp
"replace\\)*" enode-pls-white-space-regexp)
"The CREATE... of a named block"
)
(defvar enode-block-type-regexp
(concat "\\(function\\|procedure\\|package\\("
enode-pls-white-space-regexp "body\\)\\{0,1\\}\\)"
enode-pls-white-space-regexp)
"The types of named blocks"
)
(defvar enode-type-spec-regexp
;; This could be a lot better spec'd
(concat "\\(" enode-pls-name-regexp "%type\\|" enode-pls-identifier-regexp "\\)")
"The type of an identifier"
)
(defvar enode-param-inout-spec-regexp
;; This could be a lot better spec'd
(concat "\\(in\\|out\\|in" enode-pls-white-space-regexp "out\\)")
"The type of an identifier"
)
(defvar enode-param-spec-regexp
(concat enode-pls-identifier-regexp
enode-pls-white-space-regexp
"\\(" enode-param-inout-spec-regexp
enode-pls-white-space-maybe-regexp "\\)*"
enode-pls-white-space-maybe-regexp
enode-type-spec-regexp)
"A parameter in a function/procedure/etc."
)
(defvar enode-authid-spec-regexp
(concat "authid" enode-pls-white-space-regexp
"\\(current_user\\|definer\\)"
enode-pls-white-space-newline-maybe-regexp)
)
(defvar enode-decl-return-regexp
(concat "return" enode-pls-white-space-regexp enode-type-spec-regexp
enode-pls-white-space-newline-maybe-regexp)
"The RETURN clause of a function"
)
(defvar enode-is-as-regexp
(concat enode-pls-white-space-newline-maybe-regexp
"[ai]s"
enode-pls-white-space-newline-maybe-regexp)
"The IS/AS clause"
)
(defvar enode-block-name-regexp
(concat "\\(" enode-pls-name-regexp "\\)"
enode-pls-white-space-newline-regexp)
"The format of a name for a block"
)
(defvar enode-block-params-decl-regexp
(concat "(" enode-pls-white-space-newline-maybe-regexp "\\("
enode-param-spec-regexp
enode-pls-white-space-newline-maybe-regexp ",*"
enode-pls-white-space-newline-maybe-regexp "\\)+"
enode-pls-white-space-newline-maybe-regexp ")"
enode-pls-white-space-newline-maybe-regexp)
"The format of a set of parameters for a function or procedure"
)
(defvar enode-block-start-regexp
(concat "\\(" enode-declare-regexp "\\|" enode-create-regexp
enode-block-type-regexp enode-block-name-regexp "\\("
enode-block-params-decl-regexp "\\)*\\(" enode-decl-return-regexp
"\\)*\\(" enode-authid-spec-regexp "\\)*" enode-is-as-regexp "\\)" )
"The whole \"phrase\" that starts a block"
)
(defvar enode-block-name-match-position 8)
(defun enode-block-bounds ()
"Determine whether we're in a package spec or body. Returns a list of the
format (TYPE BEG END) where TYPE is 0 for spec and 1 for body and BEG and END
are the beginning and end points of whichever.
Returns NIL if neither."
;; Variables for the start of the current block, its name, its end and where
;; the point currently is.
(let (block-start
block-name
block-end
(position (point)))
;; Don't go anywhere now....
(save-excursion
;; Locate the beginning of the enclosing block
(setq block-start
(re-search-backward enode-block-start-regexp nil t))
;; If one exists...
(if block-start
;; ... get the block's name and where it ends.
(progn
(setq block-name (match-string enode-block-name-match-position))
(setq block-end
(re-search-forward
(format
"^ *end %s *;"
(if block-name block-name "*")
)
))
)
)
;; If a block exists and we're in it, return the list of its start and
;; end
(if (and block-start (and (> position block-start)
(< position block-end)))
(list block-start block-end)
;; Reasons for not being in a block:
;; 1. We're outside the block
;; 2. There are no blocks in the buffer.
;; 3. We're actually in the parameter section of the block, but
;; the preceding code compared us with the previous block
;;
;; We need to be certain we're not in case 3.
;; Go to the end of the block we we just looked at or the first
;; character.
(goto-char (if block-end block-end 1))
;; Look for the next block start
(let ((next-block-start (re-search-forward
enode-block-start-regexp nil t))
next-block-start-size)
;; If there is one, determine its size and see if were in the
;; middle of it.
(if (and next-block-start
(setq next-block-start-size (length (match-string 0)))
(and (> position (- next-block-start next-block-start-size))
(< position next-block-start)
))
;; If we are in it, move point on a bit and try again.
(progn
(goto-char (+ position next-block-start-size))
(enode-block-bounds)
)
;; Otherwise we're on a wild goose chase.
nil)
)
)
)
)
)
(defun enode-line-number ()
"A function to tell you which line you're on in the PL/SQL block"
;; (interactive)
(let ((bounds (enode-block-bounds)))
(if bounds
(+ (count-lines (car bounds) (point))
(if (looking-at "^") 1 0))
bounds)
)
)
(defun enode-goto-line (line-numb &optional char-numb)
"A function to bring the point to a specific line in the named or anonymous PL/SQL block
Produces an error if in neither.
The optional argument CHAR-NUMB also brings you to the column"
(interactive (list (read-from-minibuffer "Line: ")
(read-from-minibuffer "Character: ")))
;; Go to the line where the block starts...
(goto-char (car (enode-block-bounds)))
;; Move the the LINE-NUMBth line.
(beginning-of-line (string-to-number line-numb))
;; If we want to go to the column, move to it too.
(if (not (equal char-numb ""))
(forward-char (- (string-to-number char-numb) 1) )
)
)
(defun enode-goto-pasted-line (pasted-line)
"A function to navigate to a specific line and column of a PL/SQL block
using the <linenumber>/<columnnuber> notation (e.g. 679/13)"
(interactive (list (read-from-minibuffer "Line: ")))
(let ((my-line (car (split-string pasted-line "/")))
(my-char (cadr (split-string pasted-line "/")))
)
(enode-goto-line my-line my-char)
)
)
(defun enode-pls-compile ()
"A function to compile a named or anonymous PL/SQL block"
(interactive)
;; Determine the range of the enclosing block
;; Prepare a variable for the full statement
;; Get the process buffer to send it to.
(let ((compilable-region (enode-block-bounds))
full-statement
(sql-process (get-buffer-process "*SQL*")))
;; If we're in a valid block...
(if compilable-region
;; ... prepare the statement, including a "SHOW ERRORS" command if
;; we're dealing with a named block (i.e. a "CREATE..." statement)
(progn
(setq full-statement
(format "%s\n/\n%s"
(buffer-substring (car compilable-region)
(car (cdr compilable-region)))
(save-excursion
(let (start-str)
(setq start-str
(re-search-backward enode-declare-regexp
nil t))
(if start-str
""
"show errors\n"))
)
)
)
;; Send the statement to the process
(comint-send-string sql-process full-statement)
)
)
;; Display the results
(display-buffer (get-buffer "*SQL*") t)
)
)
;; Some handy PL/SQL template builders.
(defun enode-new-pls-package (pkg-name)
"A command to create a PL/SQL package, taking only it's name in PKG-NAME.
It creates a file (in the current buffer's location) using the name. It then
creates the outline of both a package spec and a package body, adding helpful
\"show errors\" commands along the way."
;; Get the name of the package.
(interactive "sPackage name: ")
;; Set the name of the file containing the package.
(let ((filename
(concat (file-name-directory (buffer-file-name))
"/" (downcase pkg-name) ".pls")
))
;; If the file already exists, we have a problem...
(if (file-exists-p filename)
;; ... go no further.
(error (format "File (%s) for package already exists" filename))
;; Open the file
(find-file-other-window filename)
;; Create the package spec outline
(insert (format "\n"))
(insert (format "create or replace package %s is\n\n" pkg-name))
(insert (format "end %s;\n/\n\n" pkg-name))
;; Add a little for compilation purposes (i.e. when the file is being
;; run as a script)
(insert (format "show errors;\n\n"))
;; Create the package body outline
(insert (format "create or replace package body %s is\n\n" pkg-name))
(insert (format "end %s;\n/\n\n" pkg-name))
(insert (format "show errors;\n"))
;; Indent the file as preferred
(pls-indent-region (point-min) (point-max))
;; Adjust the code's case as preferred.
(pls-adjust-case-region (point-min) (point-max))
;; Go to the first empty line of code in the package spec.
(goto-char (search-backward
(format "create or replace package %s is" pkg-name))
)
(forward-line 1)
(pls-tab)
(end-of-line)
;; Save the file and return to the user.
(save-buffer)
)
)
)
(defun enode-format-parameters (params-list)
"A function to take a list of PL/SQL parameter specs and return them
as a string that would properly be a set of PL/SQL function/procedure
parameters.
A parameter spec is itself a list of the following format:
(param-name param-direction by-ref data-type default-value)
where
PARAM-NAME is self-explanatory;
PARAM-DIRECTION is either NIL, \"IN\", \"OUT\" or \"IN OUT\". If NIL, it's
not used;
BY-REF is either NIL or T. If PARAM-DIRECTION is neither \"OUT\"
nor \"IN OUT\", this value is meaningless;
DATA-TYPE is the PL/SQL data type of the parameter or a reference to
a table column;
DEFAULT-VALUE is the default value for the parameter. If it's NIL, it's not
used."
;; Localise the passed list of parameter definitions.
(let ((local-params-list params-list)
;; Prepare the actual string to return
params-string)
;; For as long as there is a list of parameters...
(while local-params-list
;; If the string to return has something, append a comma and a newline
;; to it. Otherwise, initialise it.
(setq params-string (if params-string (format "%s,\n" params-string) ""))
;; Grab the parameter at the top of the list
(let ((current-param (car local-params-list)))
;; Set the string to return to...
(setq params-string
(format "%s%s%s%s%s"
;; what it is, followed by...
params-string
;; the name of the new parameter, following by...
(format "%s " (car current-param))
;; the parameter direction, and whether it's NOCOPY,
;; followed by...
(if (car (cdr current-param))
(let ((direction (car (cdr current-param)))
(ref (car (cdr (cdr current-param)))))
(format "%s%s "
(car (cdr current-param))
(if ref " NOCOPY" "")))
"")
;; the parameter's type, followed by...
(setq data-type (car (cdr (cdr (cdr current-param)))))
;; the parameter's default value, if specified.
(if (car (cdr (cdr (cdr (cdr current-param)))))
(format " DEFAULT %s"
(if (string= data-type "NUMBER")
default-value
(format "'%s'" default-value)))
"")
)
)
)
;; Prepare the list for the next iteration of the loop
(setq local-params-list (cdr local-params-list))
)
;; Couch the parameter list in brackets.
(format "( %s\n) " params-string)
)
)
(defun enode-pls-procedure-starter
(proc-name return-type pkg-body-point pkg-spec-point &rest passed-params)
"A function to create a new PL/SQL procedure.
If RETURN-TYPE is non-nil, then it creates a PL/SQL function.
If PKG-BODY-POINT is non-nil, it creates the procedure in a PL/SQL package.
If PKG-SPEC-POINT is non-nil, it puts a mention of it in the package spec.
PKG-SPEC-POINT is useless if PKG-BODY-POINT is nil.
PASSED-PARAMS is the list of parameters.
This function should only be called by another function that has determined
the parameters for it programatically."
;; The starting statement...
(let ((start-stmt (format "%s%s%s%s%s"
;; If we're are creating a stand-alone thing
(if (not pkg-body-point) "create or replace " "")
;; What the thing is
(if return-type "function " "procedure ")
;; Its name
(format "%s\n" proc-name)
;; The parameters, if any
(if passed-params (enode-format-parameters
passed-params) "")
;; What it returns, if applicable.
(if return-type (format "return %s" return-type)
"")
))
;; The ending statement.
(end-stmt (format "end %s;\n" proc-name))
(start-point (if (not pkg-body-point)
(point-min)
(save-excursion
(goto-char pkg-body-point)
(forward-line 1)
(point))))
end-point
)
;; Go to where we're going to put the information
(goto-char start-point)
;; Insert the generated lines.
(insert (format "\n%s is\n\n" start-stmt))
(insert (format "begin\n\n"))
(insert (format "%s" end-stmt))
(pls-indent-region start-point (point))
(pls-adjust-case-region start-point (point))
;; If we're in a package and we want to expose the thing through
;; its spec...
(if (and pkg-body-point pkg-spec-point)
(progn
;; ... go to the first line after the declaration of the spec,
(goto-char pkg-spec-point)
(forward-line 1)
(setq start-point (point))
;; and insert the generated line.
(insert (format "\n%s;\n" start-stmt))
(pls-indent-region start-point (point))
(pls-adjust-case-region start-point (point))
)
)
)
)
(defun enode-pls-function ()
"A function to take information on a new PL/SQL function"
;; Get the function's name
(interactive)
(let ((function-name (read-from-minibuffer "Function name: "))
;; Get the return type
(return-type (read-from-minibuffer "Function returns: "))
;; Get the list of parameters.
(params-list (enode-get-parameters))
)
;; Are we in a package?
(let ((pkg-points (enode-in-pls-package))
in-spec
)
;; If we're in a package
(if (cdr pkg-points)
;; Find out if we want to expose the function
(let (have-it)
(while (not have-it)
(setq in-spec (read-from-minibuffer
"In package spec? (Y/N): " "N"))
(if (or (string= in-spec "Y") (string= in-spec "y")
(string= in-spec "N") (string= in-spec "n"))
(setq have-it t)
)
)
(if (or (string= in-spec "N") (string= in-spec "n"))
(setq in-spec nil)
)
)
)
;; Call enode-pls-procedure-starter with the proper parameters.
(apply
'enode-pls-procedure-starter
function-name
return-type
(cdr pkg-points)
(if in-spec (car pkg-points) nil)
params-list)
)
)
)
(defun enode-get-parameters ()
"A function to get a list of parameters"
(interactive)
;; Some intialisations
;; The list to return
(let (params-list
;; Whether we're done gathering parameters
finished
;; The name of the first parameter
(param-name (read-from-minibuffer
"Parameter name (blank for no more parameters): "))
)
;; If the first name is blank, we came in here by accident
(if (string= param-name "")
(setq finished t)
)
;; Until we're finished...
(while (not finished)
;; Get the parameter's direction
(setq param-direction (read-from-minibuffer
"IN, OUT, IN OUT? (blank for nothing) "))
;; If the direction is blank, nilify it.
(if (string= param-direction "") (setq param-direction nil))
;; If we're creating an OUT or IN OUT parameter, get the NOCOPY
;; requirements
(setq by-ref (if (or (string= param-direction "OUT")
(string= param-direction "IN OUT"))
(if (string= (read-from-minibuffer "NOCOPY? " "N") "Y")
t)
nil))
;; Get the return type.
(setq data-type (read-from-minibuffer "Data type: " "NUMBER"))
;; Get the default value.
(setq default-value (read-from-minibuffer "Default value: "))
;; If the default value is blank, nilify it.
(if (string= default-value "") (setq default-value nil))
;; Add the new parameter to the list
(setq params-list
(cons (list param-name
param-direction
by-ref
data-type
default-value)
params-list))
;; Get the name of the next parameter.
(setq param-name (read-from-minibuffer
"Parameter name (blank for no more parameters): "))
;; If that's blank, we're done.
(if (string= param-name "")
(setq finished t)
)
)
;; If we have a list of parameters, return it reversed.
(if params-list
(nreverse params-list)
nil)
)
)
(defun enode-in-pls-package ()
"A function to determine whether we're in a PL/SQL package file.
It returns a list of (spec-start-point . body-start-point)"
(let ((package-body-regexp
(concat enode-create-regexp
"package"
enode-pls-white-space-regexp
"body"
enode-pls-white-space-regexp
enode-block-name-regexp
enode-is-as-regexp)
)
(package-spec-regexp
(concat enode-create-regexp
"package"
enode-pls-white-space-regexp
enode-block-name-regexp
enode-is-as-regexp)
)
body-start-point
spec-start-point
)
(save-excursion
(setq body-start-point (re-search-backward package-body-regexp nil t)))
(save-excursion
(setq spec-start-point (re-search-backward package-spec-regexp nil t)))
(if (and (null body-start-point) (null spec-start-point))
nil
(cons spec-start-point body-start-point)
)
)
)
(defun enode-pls-procedure ()
"A function to take information on a new PL/SQL procedure"
;; Get the procedure's name
(interactive)
(let ((procedure-name (read-from-minibuffer "Procedure name: "))
;; Get the list of parameters.
(params-list (enode-get-parameters))
)
;; Are we in a package?
(let ((pkg-points (enode-in-pls-package))
in-spec
)
;; If we're in a package
(if (cdr pkg-points)
;; Find out if we want to expose the procedure
(let (have-it)
(while (not have-it)
(setq in-spec (read-from-minibuffer
"In package spec? (Y/N): " "N"))
(if (or (string= in-spec "Y") (string= in-spec "y")
(string= in-spec "N") (string= in-spec "n"))
(setq have-it t)
)
)
(if (or (string= in-spec "N") (string= in-spec "n"))
(setq in-spec nil)
)
)
)
;; Call enode-pls-procedure-starter with the proper parameters.
(apply
'enode-pls-procedure-starter
procedure-name
nil
(cdr pkg-points)
(if in-spec (car pkg-points) nil)
params-list)
)
)
)
(defun pls-present-code-region (beg end &optional reverse)
"A function to highligh a region of code. Net really necessary here, and
I suppose it's likely to be implemented elsewhere, but I can't find it at
present. If REVERSE is true, it unpresents the code."
(interactive "r")
;; What to start the highlighting with.
(let ((present-begin "===> ")
;; What to end the highlighting with.
(present-end " <===")
;; The piece of code of interest
(code-chunk (if (not reverse)
(buffer-substring beg end)
(buffer-substring (+ beg 5) (- end 5)))))
;; Remove the region passed.
(delete-region beg end)
;; Insert the code section again, adding or removing highlights as
;; required.
(insert (format "%s%s%s"
(if reverse "" present-begin)
code-chunk
(if reverse "" present-end)))
;; Return the new end position of the relevant section
(if reverse (- end 10) (+ end 10))
))
(defun pls-convert-comments (beg end &optional do-query)
"To convert c-style comments to preferred PL/SQL style comments. Does this
with comments from point to the end. If prefix option DO-QUERY is passed,
user is prompted before making change."
(interactive "r
P")
;; Go to the beginning of the region
(goto-char beg)
(setq region-end end)
;; Look for all openings of comment blocks
(while (re-search-forward "/\\*" region-end t)
;; Go back two characters to determine the starting position of the comment
(backward-char 2)
(setq my-comment-start (point))
;; Determine the end position of the comment.
(setq my-comment-end (save-excursion (re-search-forward "\\*/" nil t)))
;; We want to convert this comment.
(let ((do-conv t))
;; If we want to ask about all the comments...
(if do-query
;; ...highligh the block and determine the new end position
(let ((new-end
(pls-present-code-region my-comment-start my-comment-end))
;; Ask the question
(my-ans (y-or-n-p
"Convert this comment? ")))
;; If the answer is "no"...
(if (not my-ans)
;; ... mark the do-conv flag as nil
(setq do-conv nil))
;; un-highlight the block
(pls-present-code-region my-comment-start new-end t)
))
;; If we are to convert the block...
(if do-conv
(let ((current-region-size (- my-comment-end my-comment-start))
new-region-size)
;; ... go to the start of the comment...
(goto-char my-comment-start)
;; ... and delete the next two charaters (the "/*")
(delete-char 2)
;; Go to the end of the block now that the first two
;; characters have been deleted, and come back another two...
(goto-char (- my-comment-end 4))
;; ... and delete them too.
(delete-char 2)
;; Reset the end position of this comment.
(setq my-comment-end (point))
;; Use the in-built commenting function to comment out
;; the defined region. This satisfies my requirements
;; beautifully.
(comment-region my-comment-start my-comment-end)
;; Commenting this out. We need to track the change to the
;; size of the buffer, and until I get a good example of
;; why the unwind-protect is required, I can't cater for this.
;; (let ((do-commenting nil))
;; (unwind-protect
;; (setq do-commenting (comment-region my-comment-start my-comment-end))
;; (if (not do-commenting)
;; (progn
;; (goto-char my-comment-start)
;; (beginning-of-line)
;; (while (< (point) my-comment-end)
;; (insert "-- ")
;; (forward-line 1)
;; )
;; )
;; )
;; )
;; )
;; Get the new region end.
(setq new-region-size (- (point) my-comment-start))
(setq region-end
(+ region-end (- new-region-size current-region-size)))
) ;; end let
) ;; end if
) ;; end let
) ;; end file
(message "Done.")
region-end
)
(defun pls-convert-comments-buffer (&optional do-query)
"Convert the /* ... */ comments for the whole buffer"
(interactive "P")
(pls-convert-comments (point-min) (point-max) do-query)
)
(defun pls-prepare-for-comparison (beg end)
"Prepare a PLSQL region for comparison. Should really be done on the whole
buffer"
(interactive "r")
(pls-mode)
(save-excursion
;; Remove trailing spaces at the end of lines.
(goto-char beg)
(while (re-search-forward "[ ]+$" end t)
(replace-match "")
(setq end (- end (length (match-string 0))))
)
;; Replace tab characters with space characters
(goto-char beg)
(while (re-search-forward "[ ]+" end t)
(replace-match " ")
(setq end (- end (- (length (match-string 0)) 1)))
)
;; Convert comments. I want to make this interactive as
;; hints probably shouldn't be converted.
(setq end (pls-convert-comments beg end t))
;; Change the case of the region
(pls-adjust-case-region beg end)
;; Indent the region
(indent-region beg end nil)
)
)
(defun pls-prepare-for-comparison-buffer ()
"Prepare a PLSQL buffer for comparison."
(interactive)
(pls-prepare-for-comparison (point-min) (point-max))
)
(provide 'pls-extras)

24
enode-lisp/sql-extras.el Executable file
View file

@ -0,0 +1,24 @@
(defun sql-area-add-table (table-name)
"A simple function to add a new table to the SQL file."
(interactive "sTable name: ")
(let ((table-name (upcase table-name)))
(if (eq major-mode 'sql-mode)
(if (progn
(goto-char (point-min))
(re-search-forward (format "^-- Table: %s$" table-name) nil t))
(error "Table %s is already there" table-name)
(goto-char (point-max))
(goto-char (re-search-backward "^-- Table: .+"))
(insert (format "-- Table: %s\n\n" table-name))
(insert (format "desc %s\n\n" table-name))
(insert (format "select count(*) %s\nfrom %s;\n\n"
table-name table-name))
)
(error "Are you in an sql-mode buffer?")
)
)
)
(provide 'sql-extras)