emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/sql-indent 7a103c2 1/3: Recognize MySQL optional clause


From: Stefan Monnier
Subject: [elpa] externals/sql-indent 7a103c2 1/3: Recognize MySQL optional clauses, #60 (#61)
Date: Mon, 7 May 2018 12:02:59 -0400 (EDT)

branch: externals/sql-indent
commit 7a103c2d5a9c0353483c4e582be8d3d955d4802e
Author: Alex Harsányi <address@hidden>
Commit: GitHub <address@hidden>

    Recognize MySQL optional clauses, #60 (#61)
    
    (sqlind-maybe-skip-mysql-create-options): skip over optional clauses between
    CREATE and the thing being created -- this allows correct identification of
    the create statement
    
    (sqlind-maybe-create-statement): skip over any "if not exist" keywords 
between
    the thing being created and its name -- this allows correct identification 
of
    the view or table name.
    
    (sqlind-refine-syntax): refine SELECT statements inside table declarations, 
as
    in "CREATE TABLE AS SELECT..."
    
    also recognize tabs as whitespace syntax in various regexps.
    
    add tests, also update the `if-exists.sql` test as the view name is 
correctly
    determined now.
---
 sql-indent-test.el          |  3 +++
 sql-indent.el               | 61 +++++++++++++++++++++++++++++++++++++--------
 test-data/if-exists-syn.eld | 11 +++-----
 test-data/if-exists.sql     |  2 --
 test-data/pr60-syn.eld      | 44 ++++++++++++++++++++++++++++++++
 test-data/pr60.sql          | 20 +++++++++++++++
 6 files changed, 121 insertions(+), 20 deletions(-)

diff --git a/sql-indent-test.el b/sql-indent-test.el
index ebe8dba..4152c0a 100644
--- a/sql-indent-test.el
+++ b/sql-indent-test.el
@@ -366,4 +366,7 @@ information read from DATA-FILE (as generated by
 (ert-deftest sqlind-ert-pr54 ()
   (sqlind-ert-check-file-syntax "test-data/pr54.sql" "test-data/pr54-syn.eld"))
 
+(ert-deftest sqlind-ert-pr60 ()
+  (sqlind-ert-check-file-syntax "test-data/pr60.sql" "test-data/pr60-syn.eld"))
+
 ;;; sql-indent-test.el ends here
diff --git a/sql-indent.el b/sql-indent.el
index e4c383c..e49998a 100644
--- a/sql-indent.el
+++ b/sql-indent.el
@@ -371,7 +371,7 @@ But don't go before LIMIT."
 ;;;;; Find the syntax and beginning of the current block
 
 (defconst sqlind-end-statement-regexp
-  "\\_<end\\_>\\(?:[ \n\r\t]*\\)\\(if\\_>\\|loop\\_>\\|case\\_>\\)?\\(?:[ 
\n\r\f]*\\)\\([a-z0-9_]+\\)?"
+  "\\_<end\\_>\\(?:[ \t\n\r\t]*\\)\\(if\\_>\\|loop\\_>\\|case\\_>\\)?\\(?:[ 
\t\n\r\f]*\\)\\([a-z0-9_]+\\)?"
   "Match an end of statement.
 Matches a string like \"end if|loop|case MAYBE-LABEL\".")
 
@@ -421,7 +421,7 @@ See also `sqlind-beginning-of-block'"
        ;; a then keyword only starts a block when it is part of an
        ;; if, case/when or exception statement
        (cond
-         ((looking-at "\\(<<[a-z0-9_]+>>\\)?\\(?:[ 
\n\r\f]*\\)\\(\\(?:els\\)?if\\)\\_>")
+         ((looking-at "\\(<<[a-z0-9_]+>>\\)?\\(?:[ 
\t\n\r\f]*\\)\\(\\(?:els\\)?if\\)\\_>")
           (let ((if-label (sqlind-match-string 1))
                 (if-kind (intern (sqlind-match-string 2)))) ; can be if or 
elsif
             (setq if-label (if if-label (substring if-label 2 -2) ""))
@@ -437,7 +437,7 @@ See also `sqlind-beginning-of-block'"
                       (throw 'finished
                         (list 'syntax-error
                               "bad closing for if block" (point) pos))))))))
-         ((looking-at "\\(<<[a-z0-9_]+>>\\)?\\(?:[ \n\r\f]*\\)case\\_>")
+         ((looking-at "\\(<<[a-z0-9_]+>>\\)?\\(?:[ \t\n\r\f]*\\)case\\_>")
           ;; find the nearest when block, but only if there are no
           ;; end statements in the stack
           (let ((case-label (sqlind-match-string 1)))
@@ -624,23 +624,63 @@ See also `sqlind-beginning-of-block'"
     (throw 'finished
       (if (null sqlind-end-stmt-stack)
          'declare-statement
-         (list 'syntax-error "nested declare block" (point) (point))))))
+        (list 'syntax-error "nested declare block" (point) (point))))))
+
+(defun sqlind-maybe-skip-mysql-create-options ()
+  "Move point past any MySQL option declarations.
+
+Statements like \"CREATE VIEW\" or \"CREATE TABLE\" can have
+various options betwen the CREATE keyword and the thing being
+created.  If such options exist at (point) the cursor is moved
+past them.
+
+Currently we move over the following options:
+
+  TEMPORARY
+  ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}
+  DEFINER = { user | CURENT_USER }
+  SQL SECURITY { DEFINER | INVOKER }
+
+We don't consider if the options are valid or not for the thing
+being created.  We just skip any and all of them that are
+present."
+  (when (eq sql-product 'mysql)
+    (catch 'finished
+      (while t
+        (cond
+          ((looking-at "temporary\\_>")
+           (goto-char (match-end 0))
+           (sqlind-forward-syntactic-ws))
+          ((looking-at 
"\\(definer\\|algorithm\\)\\(\\s-\\|[\n]\\)*=\\(\\s-\\|[\n]\\)*\\S-+")
+           (goto-char (match-end 0))
+           (sqlind-forward-syntactic-ws))
+          ((looking-at "sql\\(\\s-\\|[\n]\\)+security\\(\\s-\\|[\n]\\)+\\S-+")
+           (goto-char (match-end 0))
+           (sqlind-forward-syntactic-ws))
+          (t (throw 'finished nil)))))))
 
 (defun sqlind-maybe-create-statement ()
   "If (point) is on a CREATE statement, report its syntax.
 See also `sqlind-beginning-of-block'"
-  (when (or (looking-at "create\\_>\\(?:[ \n\r\f]+\\)\\(or\\(?:[ 
\n\r\f]+\\)replace\\_>\\)?")
+  (when (or (looking-at "create\\_>\\(?:[ \t\n\r\f]+\\)\\(or\\(?:[ 
\t\n\r\f]+\\)replace\\_>\\)?")
             (looking-at "alter\\_>"))
     (prog1 t                            ; make sure we return t
       (save-excursion
        ;; let's see what are we creating
        (goto-char (match-end 0))
         (sqlind-forward-syntactic-ws)
+        (sqlind-maybe-skip-mysql-create-options)
        (let ((what (intern (downcase (buffer-substring-no-properties
                                       (point)
                                       (progn (forward-word) (point))))))
              (name (downcase (buffer-substring-no-properties
-                              (progn (sqlind-forward-syntactic-ws) (point))
+                              (progn (sqlind-forward-syntactic-ws)
+                                      ;; Skip over a possible "if (not)
+                                      ;; exists", to get the actual name
+                                      (when (looking-at 
"if\\(\\s-\\|[\n]\\)+\\(not\\)?\\(\\s-\\|[\n]\\)exists")
+                                        (goto-char (match-end 0))
+                                        (sqlind-forward-syntactic-ws))
+                                      (point))
                               (progn (skip-syntax-forward "w_()") (point))))))
          (when (and (eq what 'package) (equal name "body"))
            (setq what 'package-body)
@@ -678,7 +718,7 @@ See also `sqlind-beginning-of-block'"
   "If (point) is on a procedure definition statement, report its syntax.
 See also `sqlind-beginning-of-block'"
   (catch 'exit
-    (when (looking-at "\\(procedure\\|function\\)\\(?:[ 
\n\r\f]+\\)\\([a-z0-9_]+\\)")
+    (when (looking-at "\\(procedure\\|function\\)\\(?:[ 
\t\n\r\f]+\\)\\([a-z0-9_]+\\)")
       (prog1 t                          ; make sure we return t
        (let ((proc-name (sqlind-match-string 2)))
          ;; need to find out if this is a procedure/function
@@ -690,7 +730,7 @@ See also `sqlind-beginning-of-block'"
            (when (looking-at "(")
              (ignore-errors (forward-sexp 1))
              (sqlind-forward-syntactic-ws))
-           (when (looking-at "return\\(?:[ 
\n\r\f]+\\)\\([a-z0-9_.]+\\(?:%\\(?:row\\)?type\\)?\\)")
+           (when (looking-at "return\\(?:[ 
\t\n\r\f]+\\)\\([a-z0-9_.]+\\(?:%\\(?:row\\)?type\\)?\\)")
              (goto-char (match-end 0))
              (sqlind-forward-syntactic-ws))
            (when (looking-at ";")
@@ -1390,9 +1430,10 @@ not a statement-continuation POS is the same as the
        (when (sqlind-search-backward pos "when\\_>" anchor)
          (push (cons '(in-block when) (point)) context))))
 
-    ;; indenting the select clause inside a view
+    ;; indenting the select clause inside a view or a "create table as"
+    ;; statement.
     ((and (eq syntax-symbol 'create-statement)
-          (eq (nth 1 syntax) 'view))
+          (memq (nth 1 syntax) '(view table)))
      (goto-char anchor)
      (catch 'done
        (while (re-search-forward "\\bselect\\b" pos 'noerror)
diff --git a/test-data/if-exists-syn.eld b/test-data/if-exists-syn.eld
index b133374..80ceb59 100644
--- a/test-data/if-exists-syn.eld
+++ b/test-data/if-exists-syn.eld
@@ -4,16 +4,11 @@
  (((create-statement index "ix1_some_table")
    . 39))
  ((toplevel . 1))
- ((comment-start . 1)
-  (toplevel . 1))
- ((comment-start . 1)
-  (toplevel . 1))
  ((toplevel . 1))
- (((create-statement index "if")
-   . 190))
+ (((create-statement index "ix2_some_table")
+   . 98))
  ((toplevel . 1))
  ((toplevel . 1))
  (((create-statement index "ix3_some_table")
-   . 269))
+   . 177))
  ((toplevel . 1)))
- 
\ No newline at end of file
diff --git a/test-data/if-exists.sql b/test-data/if-exists.sql
index 3e7e631..cdced66 100644
--- a/test-data/if-exists.sql
+++ b/test-data/if-exists.sql
@@ -3,8 +3,6 @@ drop index if exists IX1_SOME_TABLE;
 create index IX1_SOME_TABLE
   on SOME_TABLE(some_column);
 
--- NOTE: syntax incorrectly detects the name of the index as being "if".  will
--- fix later
 create index if not exists IX2_SOME_TABLE
   on SOME_TABLE(some_other_column);
 
diff --git a/test-data/pr60-syn.eld b/test-data/pr60-syn.eld
new file mode 100644
index 0000000..48b7290
--- /dev/null
+++ b/test-data/pr60-syn.eld
@@ -0,0 +1,44 @@
+(((toplevel . 1))
+ (((create-statement view "myview")
+   . 1))
+ (((create-statement view "myview")
+   . 1))
+ (((create-statement view "myview")
+   . 1))
+ (((create-statement view "myview")
+   . 1))
+ (((create-statement view "myview")
+   . 1))
+ ((select-column . 112)
+  ((create-statement view "myview")
+   . 1))
+ ((select-clause . 112)
+  ((create-statement view "myview")
+   . 1))
+ ((select-table-continuation . 208)
+  ((create-statement view "myview")
+   . 1))
+ ((toplevel . 1))
+ ((toplevel . 1))
+ (((create-statement table "foo")
+   . 282))
+ ((select-column . 328)
+  ((create-statement table "foo")
+   . 282))
+ ((select-clause . 328)
+  ((create-statement table "foo")
+   . 282))
+ ((select-table-continuation . 424)
+  ((create-statement table "foo")
+   . 282))
+ ((toplevel . 1))
+ ((comment-start . 1)
+  (toplevel . 1))
+ ((comment-start . 1)
+  (toplevel . 1))
+ ((comment-start . 1)
+  (toplevel . 1))
+ ((comment-start . 1)
+  (toplevel . 1))
+ ((toplevel . 1)))
+ 
\ No newline at end of file
diff --git a/test-data/pr60.sql b/test-data/pr60.sql
new file mode 100644
index 0000000..0830a84
--- /dev/null
+++ b/test-data/pr60.sql
@@ -0,0 +1,20 @@
+create or replace
+  algorithm = undefined
+  definer = address@hidden
+  sql security definer
+  view myview as
+  select distinct table1.fielda as firstfield,
+                  table2.fieldb as secondfield
+    from table1
+           join table2 on table1.table1id = table2.fktable1;
+
+create temporary table if not exists foo as
+  select distinct table1.fielda as firstfield,
+                  table2.fieldb as secondfield
+    from table1
+           join table2 on table1.table1id = table2.fktable1;
+
+-- local variables:
+-- mode: sql
+-- sql-product: mysql
+-- end:



reply via email to

[Prev in Thread] Current Thread [Next in Thread]