Some more files:

+ contrib/pls-mode.el: pls-mode for emacs. Used for building PL/SQL files.
+ docs/oracle-lisp-functions.txt: Another document file
+ For creating explain plans.
This commit is contained in:
Éibhear Ó hAnluain 2016-10-11 21:39:24 +01:00
parent af1b40838a
commit f33add7663
3 changed files with 4504 additions and 0 deletions

4249
contrib/pls-mode.el Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,71 @@
- get-explain-plan-for-region
+ determine enode-stage-buffer
~ create a buffer called " *enode-stage-buffer*"
~ empty it
+ go to that buffer
+ add the SQL text to plan
+ get-explain-plan
~ set the progress message
~ Determine the get-statement-id
* Return a string of the format ENODE_YYYYMMDD_HH24MMSS
~ prepare the plan with enode-prepare-explain-plan
* Determine the full explain plan command with
get-sql-explain-plan-command
$ return the string starting with "explain plan..." and finishing
with get-sql-command-to-explain
> return the SQL command to explain with blank lines and ';'
characters removed.
* Send the explain plan command to the SQL buffer and redirect output
$ to a buffer determined by enode-temp-output-buffer
$ create a buffer named " *enode-comint-sql-output*"
$ empty it
* wait for command to complete with enode-oracle-wait-for-command
~ enode-output-explain-plan
* Get the line size
$ run "show linesize" through enode-oracle-get-sqlplus-param
* Get the page size
$ run "show pagesize" through enode-oracle-get-sqlplus-param
* get the explain plan output command from
get-explain-plan-output-command
$ return the SQL command to output an explain plan.
* get the SQL buffer
* clean output buffer
* prepare the sql buffer with prepare-sql-buffer-for-command
$ set the SQL parameters heading(off), linesize(1024) and
pagesize(0) with enode-oracle-set-sqlplus-param
> send the "set" command to the SQL buffer redirecting any output
* send the command, redirecting the output
* wait for command to complete with enode-oracle-wait-for-command
* Set the SQL buffer back to it's standard output presentation with
reset-sql-buffer-after-command
$ Sets the heading(on), pagesize(original_val) and
linesize(original_val) SQL*Plus parameters.
~ enode-oracle-remove-prompt-from-plan-output
* Get the prompt from enode-oracle-get-sql-prompt
$ Return the sqlprompt parameter through
enode-oracle-get-sqlplus-param
* replace every instance of the prompt with "" in the buffer.
~ present the buffer with the plan
- Present the PL/SQL code
+ Determine a buffer to take the code.
~ enode-pls-code-buffer
+ Determine SQL buffer settings
~ line size
~ page size
+ Query the longest line in the PL/SQL block sending the output to the
prepared buffer
~ enode-oracle-plsql-max-line-length
+ Prepare the SQL buffer for the output
~ set heading off
~ set linesize to the longest line
~ set pagesize 0
+ Send the select statement to the SQL buffer sending output to the
prepared buffer
~ comint...
+ Reset the SQL buffer.
~ set heading on
~ set linesize to original value
~ set pagesize to original value
+ Present the buffer with the PL/SQL code

184
enode-lisp/planner.el Executable file
View file

@ -0,0 +1,184 @@
;; (load-file "enode-experiments.el")
;; The customisation group. Will in the ENODE group.
(defgroup enode-planner nil
"A group for customising the ENODE-PLANNER functionality."
:group 'ENODE
:version "21.2"
)
;; What table the execution plan should be made from
(defcustom enode-planner-plan-table "PLAN_TABLE"
"The table that the will be used for generating an execution plan for
queries. Defaults to PLAN_TABLE, but can, of course, be anything else."
:type 'string
:group 'enode-planner
:version "21.2"
)
(defun enode-oracle-remove-prompt-from-plan-output (plan-buffer)
"A function to clean the explain plan output of the sqlprompt string"
(let ((sql-prompt (enode-oracle-get-sql-prompt)))
(save-excursion
(set-buffer plan-buffer)
(goto-char (point-min))
(while (search-forward sql-prompt nil t)
(replace-match "" nil nil)
)
)
)
)
(defun enode-plan-buffer ()
"A function to return the buffer assigned for the explain plan output"
(get-buffer-create "*enode-explain-plan*"))
(defun get-statement-id ()
"A function to generate a unique statement id for the explain plan"
(format "ENODE_%s_%s"
(format-time-string "%Y%m%d")
(format-time-string "%H%M%S"))
)
(defun prepare-sql-buffer-for-command ()
"A function to prepare the SQLi buffer for an outputting command. It sets
properties of the SQL*Plus process to value that make an explain plan output
somewhat pretty."
(enode-oracle-sqlplus-set-param "heading" "off")
(enode-oracle-sqlplus-set-param "linesize" "1024")
(enode-oracle-sqlplus-set-param "pagesize" "0")
)
(defun reset-sql-buffer-after-command (page-size line-size)
"A function to return the SQL*Plus process' setting to 'original' values. As
well as setting PAGE-SIZE and LINE-SIZE, it also turns 'heading'
on and 'sqlnumber' on."
(enode-oracle-sqlplus-set-param "heading" "on")
(enode-oracle-sqlplus-set-param "pagesize" page-size)
(enode-oracle-sqlplus-set-param "linesize" line-size)
)
(defun get-sql-explain-plan-command (enode-plan-statement-id)
"A function to return the 'explain plan...' statement. It sets the
statement_id to ENODE-PLAN-STATEMENT-ID. It also includes the sql command from
the current buffer -- i.e. the command you want to analyse."
(format
"explain plan\nset statement_id = '%s'\ninto %s\nfor\n%s;"
enode-plan-statement-id
enode-planner-plan-table
(get-sql-command-to-explain)
)
)
(defun get-sql-command-to-explain ()
"A function to return as a string the SQL command in the current buffer.
It assumes there is only one command. It replaces empty lines with a space and
the ';' character with nothing."
(replace-regexp-in-string "^[$\n]" " "
(replace-regexp-in-string ";" "" (buffer-string)))
)
(defun get-explain-plan-output-command (enode-plan-statement-id)
"A function to return the command to generate the nice explain plan output.
It uses ENODE-PLAN-STATEMENT-ID to determine which explain plan we want to
look at."
(format "SELECT LPAD ( ' ', LEVEL - 1 ) || decode ( position, null, '', position || '-' ) || operation || decode ( options, null, '', ' ' || options ) || decode ( object_name, null, '', ' ' || object_name ) || decode ( optimizer, null, '', ' Optimiser=''' || optimizer || '''' ) || decode ( cost, null, '', ' Cost=' || cost ) || decode ( cardinality, null, '', ' Cardinality=' || cardinality ) FROM %s START WITH id = 0 AND statement_id = '%s' CONNECT BY PRIOR id = parent_id AND statement_id = '%s';"
enode-planner-plan-table
enode-plan-statement-id
enode-plan-statement-id)
)
;;;; Change this to use enode-oracle-run-sql-command
(defun enode-prepare-explain-plan (enode-plan-statement-id)
"A function to prepare an explain plan. That is, it takes the SQL command
in the current buffer and generates an explain plan in the PLAN_TABLE in it,
using ENODE-PLAN-STATEMENT-ID as the statement_id value."
(save-excursion
;; Get the full explain plan command and the SQLi buffer to run it in.
(let ((enode-sql-command
(get-sql-explain-plan-command enode-plan-statement-id))
(enode-sql-buffer sql-buffer)
)
;; Run the command.
(comint-redirect-send-command-to-process
enode-sql-command
(enode-temp-output-buffer)
enode-sql-buffer
nil
t
)
;; Allow the command to complete.
(enode-wait-for-command)
)
)
)
;;;; Change this to use enode-oracle-run-sql-command
(defun enode-output-explain-plan (enode-plan-statement-id)
"A function to display an explain plan that is already in the PLAN_TABLE. It
identifies the plan with ENODE-PLAN-STATEMENT-ID."
(save-excursion
;; Get the linesize and pagesize values the command to run
;; to generate the output and the SQLi buffer in which to run it.
(let ((enode-line-size (enode-oracle-sqlplus-get-linesize))
(enode-page-size (enode-oracle-sqlplus-get-pagesize))
(enode-plan-output-command
(get-explain-plan-output-command enode-plan-statement-id))
(enode-sql-buffer sql-buffer)
)
;; Empty the explain plan output buffer.
(enode-clean-buffer (enode-plan-buffer))
;; Tell SQL*Plus we want pretty output for this command.
(prepare-sql-buffer-for-command)
;; Run the command.
(comint-redirect-send-command-to-process
enode-plan-output-command
(enode-plan-buffer)
enode-sql-buffer
nil
t)
;; Allow the command to complete.
(enode-wait-for-command)
;; We're done with the nice output. Return SQL*Plus to it regular ugly
;; stuff.
(reset-sql-buffer-after-command
enode-page-size enode-line-size)
)
)
)
(defun get-explain-plan (&optional present-plan-command-output-p)
"A function to display an explain plan for an SQL command in the current
buffer."
;; We want to call this as a command
(interactive "P")
;; For feedback purposes
(setq enode-oracle-progress-message ".")
;; Generate a statement_id value for this plan.
(let ((plan-statement-id (get-statement-id)))
;; Generate the plan in the PLAN_TABLE
(enode-prepare-explain-plan plan-statement-id)
(if present-plan-command-output-p
(save-excursion
(display-buffer (get-buffer " *enode-comint-sql-output*"))
(read-from-minibuffer "Hit return to continue...")))
;; Send a nice representation of the plan to the plan buffer.
(enode-output-explain-plan plan-statement-id)
;; Clean up the buffer
(enode-oracle-remove-prompt-from-plan-output (enode-plan-buffer))
;; Show us the plan in another window.
(pop-to-buffer (enode-plan-buffer))
)
)
(defun get-explain-plan-for-region (beg end &optional present-plan-command-output-p)
"A function to take an SQL statement from the region and to
get an explain plan for it."
(interactive "r\nP")
(let ((plan-command-buffer (enode-stage-buffer))
(plan-command (buffer-substring beg end)))
(set-buffer plan-command-buffer)
(insert plan-command)
(get-explain-plan present-plan-command-output-p)
)
)