[tarantool-patches] [PATCH v1 1/2] sql: get rid off sqlite3NestedParse in clean stats

  • From: Kirill Shcherbatov <kshcherbatov@xxxxxxxxxxxxx>
  • To: tarantool-patches@xxxxxxxxxxxxx
  • Date: Wed, 4 Jul 2018 20:17:54 +0300

Now we manually generate AST structures to drop outdated
stats from _sql_stat1 and _sql_stat4 spaces instead of
starting sqlite3NestedParse. This function become totally
useless and could be removed.

Part of #3496.
---
 src/box/sql/analyze.c   | 39 +++++++++++------------
 src/box/sql/build.c     | 82 ++++++++++++++++++++++++++++++++++++-------------
 src/box/sql/sqliteInt.h | 13 ++++++++
 3 files changed, 94 insertions(+), 40 deletions(-)

diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index 5f73f02..e08c151 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -116,7 +116,7 @@
 #include "tarantoolInt.h"
 #include "vdbeInt.h"
 
-/*
+/**
  * This routine generates code that opens the sql_statN tables.
  * The _sql_stat1 table is always relevant. _sql_stat4 is only opened when
  * appropriate compile-time options are provided.
@@ -127,21 +127,24 @@
  * or it may be a NULL pointer. If it is not NULL, then all entries in
  * the sql_statN tables associated with the named table are deleted.
  * If zWhere==0, then code is generated to delete all stat table entries.
+ *
+ * @param parse Parsing context.
+ * @param stat_cursor Open the _sql_stat1 table on this cursor.
+ * @param index_name Delete records of this table if specified.
+ * @param table_name Delete records of this index if specified.
  */
 static void
-openStatTable(Parse * pParse,  /* Parsing context */
-             int iStatCur,     /* Open the _sql_stat1 table on this cursor */
-             const char *zWhere,       /* Delete entries for this table or 
index */
-             const char *zWhereType    /* Either "tbl" or "idx" */
-    )
+vdbe_stat_space_open(struct Parse *parse, int stat_cursor,
+                    const char *index_name, const char *table_name)
 {
        const char *aTable[] = {
                "_sql_stat1",
                "_sql_stat4",
                NULL};
        int i;
-       sqlite3 *db = pParse->db;
-       Vdbe *v = sqlite3GetVdbe(pParse);
+       struct sqlite3 *db = parse->db;
+       struct Vdbe *v = sqlite3GetVdbe(parse);
+       assert(v != NULL);
        int aRoot[ArraySize(aTable)];
        u8 aCreateTbl[ArraySize(aTable)];
 
@@ -160,10 +163,9 @@ openStatTable(Parse * pParse,      /* Parsing context */
                assert(pStat != NULL);
                aRoot[i] = pStat->tnum;
                aCreateTbl[i] = 0;
-               if (zWhere) {
-                       sqlite3NestedParse(pParse,
-                                          "DELETE FROM \"%s\" WHERE \"%s\"=%Q",
-                                          zTab, zWhereType, zWhere);
+               if (table_name != NULL || index_name != NULL) {
+                       vdbe_stat_space_clear(parse, zTab, index_name,
+                                             table_name);
                } else {
                        /*
                         * The sql_stat[134] table already exists.
@@ -178,7 +180,7 @@ openStatTable(Parse * pParse,       /* Parsing context */
        for (i = 0; aTable[i]; i++) {
                struct space *space =
                        space_by_id(SQLITE_PAGENO_TO_SPACEID(aRoot[i]));
-               vdbe_emit_open_cursor(pParse, iStatCur + i, aRoot[i], space);
+               vdbe_emit_open_cursor(parse, stat_cursor + i, aRoot[i], space);
                sqlite3VdbeChangeP5(v, aCreateTbl[i]);
                VdbeComment((v, aTable[i]));
        }
@@ -1117,7 +1119,7 @@ sql_analyze_database(Parse *parser)
        sql_set_multi_write(parser, false);
        int stat_cursor = parser->nTab;
        parser->nTab += 3;
-       openStatTable(parser, stat_cursor, NULL, NULL);
+       vdbe_stat_space_open(parser, stat_cursor, NULL, NULL);
        int reg = parser->nMem + 1;
        int tab_cursor = parser->nTab;
        for (struct HashElem *k = sqliteHashFirst(&schema->tblHash); k != NULL;
@@ -1145,11 +1147,10 @@ analyzeTable(Parse * pParse, Table * pTab, Index * 
pOnlyIdx)
        sql_set_multi_write(pParse, false);
        iStatCur = pParse->nTab;
        pParse->nTab += 3;
-       if (pOnlyIdx) {
-               openStatTable(pParse, iStatCur, pOnlyIdx->zName, "idx");
-       } else {
-               openStatTable(pParse, iStatCur, pTab->def->name, "tbl");
-       }
+       if (pOnlyIdx != NULL)
+               vdbe_stat_space_open(pParse, iStatCur, pOnlyIdx->zName, NULL);
+       else
+               vdbe_stat_space_open(pParse, iStatCur, NULL, pTab->def->name);
        analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur, pParse->nMem + 1,
                        pParse->nTab);
        loadAnalysis(pParse);
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 0072f84..ac53906 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -2050,6 +2050,63 @@ sql_store_select(struct Parse *parse_context, struct 
Select *select)
 }
 
 /**
+ * Create expression record of with struct ID EQ STRING.
+ *
+ * @param parse The parsing context.
+ * @param col_type_name Name of column.
+ * @param col_name Name of row.
+ * @retval not NULL on success.
+ * @retval NULL on failure.
+ */
+static struct Expr *
+sql_id_eq_str_expr(struct Parse *parse, const char *col_type_name,
+                  const char *col_name)
+{
+       struct sqlite3 *db = parse->db;
+
+       struct Expr *col_type_expr =
+               sqlite3Expr(db, TK_ID, col_type_name);
+       struct Expr *col_name_expr =
+               sqlite3Expr(db, TK_STRING, col_name);
+       struct Expr *col_eq_expr =
+               sqlite3PExpr(parse, TK_EQ, col_type_expr, col_name_expr);
+       if (col_type_expr == NULL || col_name_expr == NULL) {
+               sql_expr_delete(db, col_eq_expr, false);
+               col_eq_expr = NULL;
+       }
+       return col_eq_expr;
+}
+
+void
+vdbe_stat_space_clear(struct Parse *parse, const char *stat_table_name,
+                     const char *idx_name, const char *table_name)
+{
+       assert(idx_name != NULL || table_name != NULL);
+       struct sqlite3 *db = parse->db;
+       assert(!db->mallocFailed);
+       struct SrcList *src_list = sql_alloc_src_list(db);
+       if (src_list != NULL)
+               src_list->a[0].zName = sqlite3DbStrDup(db, stat_table_name);
+       struct Expr *where = NULL;
+       if (idx_name != NULL) {
+               struct Expr *expr = sql_id_eq_str_expr(parse, "idx", idx_name);
+               if (expr != NULL)
+                       where = sqlite3ExprAnd(db, expr, where);
+       }
+       if (table_name != NULL) {
+               struct Expr *expr = sql_id_eq_str_expr(parse, "tbl", 
table_name);
+               if (expr != NULL)
+                       where = sqlite3ExprAnd(db, expr, where);
+       }
+       /**
+        * On memory allocation error
+        * sql_table delete_from releases memory
+        * for its own.
+        */
+       sql_table_delete_from(parse, src_list, where);
+}
+
+/**
  * Remove entries from the _sql_stat1 and _sql_stat4
  * system spaces after a DROP INDEX or DROP TABLE command.
  *
@@ -2062,27 +2119,10 @@ static void
 sql_clear_stat_spaces(Parse *parse, const char *table_name,
                      const char *idx_name)
 {
-       if (idx_name != NULL) {
-               sqlite3NestedParse(parse,
-                                  "DELETE FROM \"_sql_stat1\" "
-                                  "WHERE (\"idx\"=%Q AND "
-                                  "\"tbl\"=%Q)",
-                                  idx_name, table_name);
-               sqlite3NestedParse(parse,
-                                  "DELETE FROM \"_sql_stat4\" "
-                                  "WHERE (\"idx\"=%Q AND "
-                                  "\"tbl\"=%Q)",
-                                  idx_name, table_name);
-       } else {
-               sqlite3NestedParse(parse,
-                                  "DELETE FROM \"_sql_stat1\" "
-                                  "WHERE \"tbl\"=%Q",
-                                  table_name);
-               sqlite3NestedParse(parse,
-                                  "DELETE FROM \"_sql_stat4\" "
-                                  "WHERE \"tbl\"=%Q",
-                                  table_name);
-       }
+       vdbe_stat_space_clear(parse, "_sql_stat4", idx_name,
+                             table_name);
+       vdbe_stat_space_clear(parse, "_sql_stat1", idx_name,
+                             table_name);
 }
 
 /**
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 8b75ae8..a0a874c 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -4847,4 +4847,17 @@ vdbe_emit_halt_with_presence_test(struct Parse *parser, 
int space_id,
                                  const char *error_src, bool no_error,
                                  int cond_opcode);
 
+/**
+ * Generate VDBE code to delete records from system _sql_stat1 or
+ * _sql_stat4 table.
+ *
+ * @param parse The parsing context.
+ * @param stat_table_name System stat table name.
+ * @param idx_name Index name.
+ * @param table_name Table name.
+ */
+void
+vdbe_stat_space_clear(struct Parse *parse, const char *stat_table_name,
+                     const char *idx_name, const char *table_name);
+
 #endif                         /* SQLITEINT_H */
-- 
2.7.4


Other related posts: