[tarantool-patches] Re: [PATCH v1 1/1] sql: set column types for EXPLAIN and PRAGMA

  • From: Vladislav Shpilevoy <v.shpilevoy@xxxxxxxxxxxxx>
  • To: imeevma@xxxxxxxxxxxxx, tarantool-patches@xxxxxxxxxxxxx
  • Date: Wed, 12 Dec 2018 16:21:16 +0300

Hi! Thanks for the patch! See 3 comments below,
review fixes at the end of the email and on the
branch.

On 11/12/2018 23:41, imeevma@xxxxxxxxxxxxx wrote:

Currently, EXPLAIN and PRAGMA do not set the column types for the
result. This is incorrect, since any returned row must have a
column type. This patch defines the types for these columns.

Closes #3832
---
https://github.com/tarantool/tarantool/issues/3832
https://github.com/tarantool/tarantool/tree/imeevma/gh-3832-no-column-types

  src/box/execute.c        |   5 +-
  src/box/sql/pragma.c     |  29 +++----
  src/box/sql/pragma.h     | 214 +++++++++++++++++++++++++++++++++--------------
  src/box/sql/prepare.c    |  52 ++++++++----
  test/sql/iproto.result   |  69 +++++++++++++++
  test/sql/iproto.test.lua |  18 +++-
  6 files changed, 295 insertions(+), 92 deletions(-)

diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 5c35017..e1598d9 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -112,25 +112,26 @@ sqlite3GetBoolean(const char *z, u8 dflt)
   * the rest of the file if PRAGMAs are omitted from the build.
   */
-/*
- * Set result column names for a pragma.
+/**
+ * Set result column names and types for a pragma.
+ *
+ * @param v the query under construction.
+ * @param pPragma the pragma.
   */
  static void
-setPragmaResultColumnNames(Vdbe * v,   /* The query under construction */
-                          const PragmaName * pPragma   /* The pragma */
-    )
+setPragmaResultColumnNames(Vdbe *v, const PragmaName *pPragma)
  {
        u8 n = pPragma->nPragCName;
-       sqlite3VdbeSetNumCols(v, n == 0 ? 1 : n);
-       if (n == 0) {
-               sqlite3VdbeSetColName(v, 0, COLNAME_NAME, pPragma->zName,
+       assert(n > 0);
+       sqlite3VdbeSetNumCols(v, n);
+       int i, j;
+       for (i = 0, j = pPragma->iPragCName; i < n; i++, j++) {
+               /* Value of j is index of column name in array */
+               sqlite3VdbeSetColName(v, i, COLNAME_NAME, pragCName[j++],
+                                     SQLITE_STATIC);
+               /* Value of j is index of column type in array */
+               sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, pragCName[j],
                                      SQLITE_STATIC);
-       } else {
-               int i, j;
-               for (i = 0, j = pPragma->iPragCName; i < n; i++, j++) {
-                       sqlite3VdbeSetColName(v, i, COLNAME_NAME, pragCName[j],
-                                             SQLITE_STATIC);
-               }
        }
  }

1. You rewrote this function almost completely. Usually in
such a case we reformat the function into Tarantool code style.

diff --git a/src/box/sql/pragma.h b/src/box/sql/pragma.h
index e608016..c6c3e63 100644
--- a/src/box/sql/pragma.h
+++ b/src/box/sql/pragma.h
@@ -27,50 +27,142 @@
  #define PragFlg_SchemaOpt  0x40       /* Schema restricts name search if 
present */
  #define PragFlg_SchemaReq  0x80       /* Schema required - "main" is default 
*/
-/* Names of columns for pragmas that return multi-column result
- * or that return single-column results where the name of the
- * result column is different from the name of the pragma
+/**
+ * Column names and types for pragmas. The type of the column is
+ * the following value after its name.
   */
  static const char *const pragCName[] = {
        /* Used by: table_info */
        /*   0 */ "cid",
-       /*   1 */ "name",
-       /*   2 */ "type",
-       /*   3 */ "notnull",
-       /*   4 */ "dflt_value",
-       /*   5 */ "pk",
+       /*   1 */ "INTEGER",
+       /*   2 */ "name",
+       /*   3 */ "TEXT",
+       /*   4 */ "type",
+       /*   3 */ "TEXT",
+       /*   6 */ "notnull",
+       /*   1 */ "INTEGER",
+       /*   8 */ "dflt_value",
+       /*   9 */ "TEXT",
+       /*  10 */ "pk",
+       /*  11 */ "INTEGER",
        /* Used by: stats */
-       /*   6 */ "table",
-       /*   7 */ "index",
-       /*   8 */ "width",
-       /*   9 */ "height",
+       /*  12 */ "table",
+       /*  13 */ "TEXT",
+       /*  14 */ "index",
+       /*  15 */ "TEXT",
+       /*  16 */ "width",
+       /*  17 */ "INTEGER",
+       /*  18 */ "height",
+       /*  19 */ "INTEGER",

2. I see that sql_pragma_table_stats returns rows of different types
of the same columns. First row has 4 columns with types "ssii", other
rows have 3 columns "sii". I think, all rows should have the same
number of columns of the same types. Also, the first row actually
duplicates the second - they both describe the primary index.

Please, consult server team chat what to do with it. I think, that we
should always return 3 columns "sii": index name, avg tuple size, index size.
So we just should delete the current first row.

        /* Used by: index_info */
-       /*  10 */ "seqno",
-       /*  11 */ "cid",
-       /*  12 */ "name",
-       /*  13 */ "desc",
-       /*  14 */ "coll",
-       /*  15 */ "type",
+       /*  20 */ "seqno",
+       /*  21 */ "INTEGER",
+       /*  22 */ "cid",
+       /*  23 */ "INTEGER",
+       /*  24 */ "name",
+       /*  25 */ "TEXT",
+       /*  26 */ "desc",
+       /*  27 */ "INTEGER",
+       /*  28 */ "coll",
+       /*  29 */ "TEXT",
+       /*  30 */ "type",
+       /*  31 */ "TEXT",
        /* Used by: index_list */
-       /*  16 */ "seq",
-       /*  17 */ "name",
-       /*  18 */ "unique",
-       /*  19 */ "origin",
-       /*  20 */ "partial",
+       /*  32 */ "seq",
+       /*  33 */ "INTEGER",
+       /*  34 */ "name",
+       /*  35 */ "TEXT",
+       /*  36 */ "unique",
+       /*  37 */ "INTEGER",
+       /*  38 */ "origin",
+       /*  39 */ "TEXT",
+       /*  40 */ "partial",
+       /*  41 */ "INTEGER",
        /* Used by: collation_list */
-       /*  21 */ "seq",
-       /*  22 */ "name",
+       /*  42 */ "seq",
+       /*  43 */ "INTEGER",
+       /*  44 */ "name",
+       /*  45 */ "TEXT",
        /* Used by: foreign_key_list */
-       /*  23 */ "id",
-       /*  24 */ "seq",
-       /*  25 */ "table",
-       /*  26 */ "from",
-       /*  27 */ "to",
-       /*  28 */ "on_update",
-       /*  29 */ "on_delete",
-       /*  30 */ "match",
+       /*  46 */ "id",
+       /*  47 */ "INTEGER",
+       /*  48 */ "seq",
+       /*  49 */ "INTEGER",
+       /*  50 */ "table",
+       /*  51 */ "TEXT",
+       /*  52 */ "from",
+       /*  53 */ "TEXT",
+       /*  54 */ "to",
+       /*  55 */ "TEXT",
+       /*  56 */ "on_update",
+       /*  57 */ "TEXT",
+       /*  58 */ "on_delete",
+       /*  59 */ "TEXT",
+       /*  60 */ "match",
+       /*  61 */ "TEXT",
        /* Used by: busy_timeout */
-       /*  31 */ "timeout",
+       /*  62 */ "timeout",
+       /*  63 */ "INTEGER",
+       /* Used by: case_sensitive_like */
+       /*  64 */ "case_sensitive_like",
+       /*  65 */ "INTEGER",

3. I do not see where case_sensitive_like returns anything.
Looks like it is has 'void' return type. So it should not
have any out names/types. The same about all other pragmas
below. Or am I wrong?

+       /* Used by: count_changes */
+       /*  66 */ "count_changes",
+       /*  67 */ "INTEGER",
+       /* Used by: defer_foreign_keys */
+       /*  68 */ "defer_foreign_keys",
+       /*  69 */ "INTEGER",
+       /* Used by: full_column_names */
+       /*  70 */ "full_column_names",
+       /*  71 */ "INTEGER",
+       /* Used by: parser_trace */
+       /*  72 */ "parser_trace",
+       /*  73 */ "INTEGER",
+       /* Used by: query_only */
+       /*  74 */ "query_only",
+       /*  75 */ "INTEGER",
+       /* Used by: read_uncommitted */
+       /*  76 */ "read_uncommitted",
+       /*  77 */ "INTEGER",
+       /* Used by: recursive_triggers */
+       /*  78 */ "recursive_triggers",
+       /*  79 */ "INTEGER",
+       /* Used by: reverse_unordered_selects */
+       /*  80 */ "reverse_unordered_selects",
+       /*  81 */ "INTEGER",
+       /* Used by: select_trace */
+       /*  82 */ "select_trace",
+       /*  83 */ "INTEGER",
+       /* Used by: short_column_names */
+       /*  84 */ "short_column_names",
+       /*  85 */ "INTEGER",
+       /* Used by: sql_compound_select_limit */
+       /*  86 */ "sql_compound_select_limit",
+       /*  87 */ "INTEGER",
+       /* Used by: sql_default_engine */
+       /*  88 */ "sql_default_engine",
+       /*  89 */ "INTEGER",
+       /* Used by: sql_trace */
+       /*  90 */ "sql_trace",
+       /*  91 */ "INTEGER",
+       /* Used by: vdbe_addoptrace */
+       /*  92 */ "vdbe_addoptrace",
+       /*  93 */ "INTEGER",
+       /* Used by: vdbe_debug */
+       /*  94 */ "vdbe_debug",
+       /*  95 */ "INTEGER",
+       /* Used by: vdbe_eqp */
+       /*  96 */ "vdbe_eqp",
+       /*  97 */ "INTEGER",
+       /* Used by: vdbe_listing */
+       /*  98 */ "vdbe_listing",
+       /*  99 */ "INTEGER",
+       /* Used by: vdbe_trace */
+       /*  100 */ "vdbe_trace",
+       /*  101 */ "INTEGER",
+       /* Used by: where_trace */
+       /*  102 */ "where_trace",
+       /*  103 */ "INTEGER",
  };

=======================================================

commit 2b019a9be547484036a8e666a2cf8b1941ce0b30
Author: Vladislav Shpilevoy <v.shpilevoy@xxxxxxxxxxxxx>
Date:   Wed Dec 12 16:19:27 2018 +0300

    Review fixes

diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index e1598d951..ef80bf801 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -112,25 +112,19 @@ sqlite3GetBoolean(const char *z, u8 dflt)
  * the rest of the file if PRAGMAs are omitted from the build.
  */
-/**
- * Set result column names and types for a pragma.
- *
- * @param v the query under construction.
- * @param pPragma the pragma.
- */
+/** Set result column names and types for a pragma. */
 static void
-setPragmaResultColumnNames(Vdbe *v, const PragmaName *pPragma)
+vdbe_set_pragma_result_columns(struct Vdbe *v, const struct PragmaName *pragma)
 {
-       u8 n = pPragma->nPragCName;
+       int n = pragma->nPragCName;
        assert(n > 0);
        sqlite3VdbeSetNumCols(v, n);
-       int i, j;
-       for (i = 0, j = pPragma->iPragCName; i < n; i++, j++) {
+       for (int i = 0, j = pragma->iPragCName; i < n; ++i) {
                /* Value of j is index of column name in array */
                sqlite3VdbeSetColName(v, i, COLNAME_NAME, pragCName[j++],
                                      SQLITE_STATIC);
                /* Value of j is index of column type in array */
-               sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, pragCName[j],
+               sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, pragCName[j++],
                                      SQLITE_STATIC);
        }
 }
@@ -461,17 +455,15 @@ sqlite3Pragma(Parse * pParse, Token * pId,        /* 
First part of [schema.]id field */
        }
        /* Register the result column names for pragmas that return results */
        if ((pPragma->mPragFlg & PragFlg_NoColumns) == 0
-           && ((pPragma->mPragFlg & PragFlg_NoColumns1) == 0 || zRight == 0)
-           ) {
-               setPragmaResultColumnNames(v, pPragma);
-       }
+           && ((pPragma->mPragFlg & PragFlg_NoColumns1) == 0 || zRight == 0))
+               vdbe_set_pragma_result_columns(v, pPragma);
        /* Jump to the appropriate pragma handler */
        switch (pPragma->ePragTyp) {
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
        case PragTyp_FLAG:{
                        if (zRight == 0) {
-                               setPragmaResultColumnNames(v, pPragma);
+                               vdbe_set_pragma_result_columns(v, pPragma);
                                returnSingleInt(v,
                                                (user_session->
                                                 sql_flags & pPragma->iArg) !=


Other related posts: