[tarantool-patches] [PATCH v3] sql: prohibit type_def keywords in the VALUES statement

Stanislav Zudin szudin at tarantool.org
Tue Jan 29 16:10:24 MSK 2019


The "box.sql.execute('values(blob)')" causes an accert in the
expression processing, because the parser doesn't distinguish the
keyword "BLOB" from the binary value (in the form X'hex').

This fix adds an additional checks in the SQL grammar.
Thus the expressions such as "VALUES(BLOB)", "SELECT FLOAT"
and so on are treated as a syntax errors.

Closes #3888
---
Branch: https://github.com/tarantool/tarantool/tree/sz/gh-3888-values-blob-assert
Issue: https://github.com/tarantool/tarantool/issues/3888

 extra/mkkeywordhash.c                        |  6 +-
 src/box/sql/parse.y                          |  6 +-
 test/sql/gh-3888-values-blob-assert.result   | 61 ++++++++++++++++++++
 test/sql/gh-3888-values-blob-assert.test.lua | 33 +++++++++++
 4 files changed, 100 insertions(+), 6 deletions(-)
 create mode 100644 test/sql/gh-3888-values-blob-assert.result
 create mode 100644 test/sql/gh-3888-values-blob-assert.test.lua

diff --git a/extra/mkkeywordhash.c b/extra/mkkeywordhash.c
index d92b9eeb7..2b21cb863 100644
--- a/extra/mkkeywordhash.c
+++ b/extra/mkkeywordhash.c
@@ -109,7 +109,7 @@ static Keyword aKeywordTable[] = {
   { "BEFORE",                 "TK_BEFORE",      TRIGGER,          false },
   { "BEGIN",                  "TK_BEGIN",       TRIGGER,          true  },
   { "BETWEEN",                "TK_BETWEEN",     ALWAYS,           true  },
-  { "BLOB",                   "TK_BLOB",        RESERVED,         true  },
+  { "BLOB",                   "TK_BLOB_KW",     RESERVED,         true  },
   { "BY",                     "TK_BY",          ALWAYS,           true  },
   { "CASCADE",                "TK_CASCADE",     FKEY,             false },
   { "CASE",                   "TK_CASE",        ALWAYS,           true  },
@@ -235,12 +235,12 @@ static Keyword aKeywordTable[] = {
   { "DOUBLE",                 "TK_DOUBLE",      RESERVED,         true  },
   { "ELSEIF",                 "TK_STANDARD",    RESERVED,         true  },
   { "FETCH",                  "TK_STANDARD",    RESERVED,         true  },
-  { "FLOAT",                  "TK_FLOAT",       RESERVED,         true  },
+  { "FLOAT",                  "TK_FLOAT_KW",    RESERVED,         true  },
   { "FUNCTION",               "TK_STANDARD",    RESERVED,         true  },
   { "GET",                    "TK_STANDARD",    RESERVED,         true  },
   { "GRANT",                  "TK_STANDARD",    RESERVED,         true  },
   { "INT",                    "TK_INT",         RESERVED,         true  },
-  { "INTEGER",                "TK_INTEGER",     RESERVED,         true  },
+  { "INTEGER",                "TK_INTEGER_KW",  RESERVED,         true  },
   { "INOUT",                  "TK_STANDARD",    RESERVED,         true  },
   { "INSENSITIVE",            "TK_STANDARD",    RESERVED,         true  },
   { "ITERATE",                "TK_STANDARD",    RESERVED,         true  },
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index 0bcf41594..8e21b6fca 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -1469,7 +1469,7 @@ wqlist(A) ::= wqlist(A) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
 /* Primitive types. */
 %type typedef {struct type_def}
 typedef(A) ::= TEXT . { A.type = AFFINITY_TEXT; }
-typedef(A) ::= BLOB . { A.type = AFFINITY_BLOB; }
+typedef(A) ::= BLOB_KW . { A.type = AFFINITY_BLOB; }
 typedef(A) ::= DATE . { A.type = AFFINITY_REAL; }
 typedef(A) ::= TIME . { A.type = AFFINITY_REAL; }
 typedef(A) ::= DATETIME . { A.type = AFFINITY_REAL; }
@@ -1496,8 +1496,8 @@ typedef(A) ::= VARCHAR char_len(B) . {
 
 %type number_typedef {struct type_def}
 typedef(A) ::= number_typedef(A) .
-number_typedef(A) ::= FLOAT|REAL|DOUBLE . { A.type = AFFINITY_REAL; }
-number_typedef(A) ::= INT|INTEGER . { A.type = AFFINITY_INTEGER; }
+number_typedef(A) ::= FLOAT_KW|REAL|DOUBLE . { A.type = AFFINITY_REAL; }
+number_typedef(A) ::= INT|INTEGER_KW . { A.type = AFFINITY_INTEGER; }
 
 %type number_len_typedef {struct type_def}
 number_typedef(A) ::= DECIMAL|NUMERIC|NUM number_len_typedef(B) . {
diff --git a/test/sql/gh-3888-values-blob-assert.result b/test/sql/gh-3888-values-blob-assert.result
new file mode 100644
index 000000000..75152bb05
--- /dev/null
+++ b/test/sql/gh-3888-values-blob-assert.result
@@ -0,0 +1,61 @@
+-- sql: assertion fault on VALUES #3888
+--
+-- Make sure that tokens representing values of integer, float,
+-- and blob constants are different from tokens representing
+-- keywords of the same names.
+--
+test_run = require('test_run').new()
+---
+...
+engine = test_run:get_cfg('engine')
+---
+...
+box.sql.execute('pragma sql_default_engine=\''..engine..'\'')
+---
+...
+-- check 'VALUES' against typedef keywords (should fail)
+box.sql.execute('VALUES(blob)')
+---
+- error: 'near "blob": syntax error'
+...
+box.sql.execute('VALUES(float)')
+---
+- error: 'near "float": syntax error'
+...
+-- check 'SELECT' against typedef keywords (should fail)
+box.sql.execute('SELECT blob')
+---
+- error: 'near "blob": syntax error'
+...
+box.sql.execute('SELECT float')
+---
+- error: 'near "float": syntax error'
+...
+-- check 'VALUES' against ID (should fail)
+box.sql.execute('VALUES(TheColumnName)')
+---
+- error: 'no such column: THECOLUMNNAME'
+...
+-- check 'SELECT' against ID (should fail)
+box.sql.execute('SELECT TheColumnName')
+---
+- error: 'no such column: THECOLUMNNAME'
+...
+-- check 'VALUES' well-formed expression  (returns value)
+box.sql.execute('VALUES(-0.5e-2)')
+---
+- - [-0.005]
+...
+box.sql.execute('SELECT X\'507265766564\'')
+---
+- - ['Preved']
+...
+-- check 'SELECT' well-formed expression  (return value)
+box.sql.execute('SELECT 3.14')
+---
+- - [3.14]
+...
+box.sql.execute('SELECT X\'4D6564766564\'')
+---
+- - ['Medved']
+...
diff --git a/test/sql/gh-3888-values-blob-assert.test.lua b/test/sql/gh-3888-values-blob-assert.test.lua
new file mode 100644
index 000000000..9adab488c
--- /dev/null
+++ b/test/sql/gh-3888-values-blob-assert.test.lua
@@ -0,0 +1,33 @@
+-- sql: assertion fault on VALUES #3888
+--
+-- Make sure that tokens representing values of integer, float,
+-- and blob constants are different from tokens representing
+-- keywords of the same names.
+--
+test_run = require('test_run').new()
+engine = test_run:get_cfg('engine')
+box.sql.execute('pragma sql_default_engine=\''..engine..'\'')
+
+-- check 'VALUES' against typedef keywords (should fail)
+box.sql.execute('VALUES(blob)')
+box.sql.execute('VALUES(float)')
+
+-- check 'SELECT' against typedef keywords (should fail)
+box.sql.execute('SELECT blob')
+box.sql.execute('SELECT float')
+
+-- check 'VALUES' against ID (should fail)
+box.sql.execute('VALUES(TheColumnName)')
+
+-- check 'SELECT' against ID (should fail)
+box.sql.execute('SELECT TheColumnName')
+
+-- check 'VALUES' well-formed expression  (returns value)
+box.sql.execute('VALUES(-0.5e-2)')
+box.sql.execute('SELECT X\'507265766564\'')
+
+-- check 'SELECT' well-formed expression  (return value)
+box.sql.execute('SELECT 3.14')
+box.sql.execute('SELECT X\'4D6564766564\'')
+
+
-- 
2.17.1





More information about the Tarantool-patches mailing list