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

Kirill Shcherbatov kshcherbatov at tarantool.org
Wed Jul 4 20:17:54 MSK 2018


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





More information about the Tarantool-patches mailing list