Tarantool development patches archive
 help / color / mirror / Atom feed
From: Kirill Shcherbatov <kshcherbatov@tarantool.org>
To: tarantool-patches@freelists.org
Cc: korablev@tarantool.org, Kirill Shcherbatov <kshcherbatov@tarantool.org>
Subject: [tarantool-patches] [PATCH v2 1/4] sql: get rid off sqlite3NestedParse in clean stats
Date: Tue, 10 Jul 2018 20:08:08 +0300	[thread overview]
Message-ID: <3017d0e640eebdc6c3f28b5b4a4cbd2ef5646882.1531242355.git.kshcherbatov@tarantool.org> (raw)
In-Reply-To: <cover.1531242355.git.kshcherbatov@tarantool.org>
In-Reply-To: <cover.1531242355.git.kshcherbatov@tarantool.org>

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   | 102 ++++++++++++++++++++----------------------------
 src/box/sql/build.c     |  79 ++++++++++++++++++++++++++-----------
 src/box/sql/sqliteInt.h |  13 ++++++
 3 files changed, 113 insertions(+), 81 deletions(-)

diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index 5f73f02..336d146 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -116,71 +116,53 @@
 #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.
- *
- * If the sql_statN tables do not previously exist, it is created.
+/**
+ * This routine generates code that opens the sql_stat1/4 tables.
+ * If the sql_statN tables do not previously exist, they are
+ * created.
  *
- * Argument zWhere may be a pointer to a buffer containing a table name,
- * 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_emit_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);
-	int aRoot[ArraySize(aTable)];
-	u8 aCreateTbl[ArraySize(aTable)];
+	const char *space_names[] = {"_sql_stat1", "_sql_stat4"};
+	const uint32_t space_ids[] = {BOX_SQL_STAT1_ID, BOX_SQL_STAT4_ID};
+	struct Vdbe *v = sqlite3GetVdbe(parse);
+	assert(v != NULL);
+	assert(sqlite3VdbeDb(v) == parse->db);
 
-	if (v == 0)
-		return;
-	assert(sqlite3VdbeDb(v) == db);
-
-	/* Create new statistic tables if they do not exist, or clear them
-	 * if they do already exist.
+	/*
+	 * Create new statistic tables if they do not exist, or
+	 * clear them if they do already exist.
 	 */
-	for (i = 0; aTable[i]; i++) {
-		const char *zTab = aTable[i];
-		Table *pStat;
-		/* The table already exists, because it is a system space */
-		pStat = sqlite3HashFind(&db->pSchema->tblHash, zTab);
-		assert(pStat != NULL);
-		aRoot[i] = pStat->tnum;
-		aCreateTbl[i] = 0;
-		if (zWhere) {
-			sqlite3NestedParse(pParse,
-					   "DELETE FROM \"%s\" WHERE \"%s\"=%Q",
-					   zTab, zWhereType, zWhere);
+	for (uint i = 0; i < lengthof(space_names); ++i) {
+		const char *space_name = space_names[i];
+		/*
+		 * The table already exists, because it is a
+		 * system space.
+		 */
+		assert(sqlite3HashFind(&parse->db->pSchema->tblHash,
+				       space_name) != NULL);
+		if (table_name != NULL || index_name != NULL) {
+			vdbe_emit_stat_space_clear(parse, space_name,
+						   index_name, table_name);
 		} else {
-			/*
-			 * The sql_stat[134] table already exists.
-			 * Delete all rows.
-			 */
-			sqlite3VdbeAddOp2(v, OP_Clear,
-					  SQLITE_PAGENO_TO_SPACEID(aRoot[i]), 0);
+			sqlite3VdbeAddOp2(v, OP_Clear, space_ids[i], 0);
 		}
 	}
 
-	/* Open the sql_stat[134] tables for writing. */
-	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);
-		sqlite3VdbeChangeP5(v, aCreateTbl[i]);
-		VdbeComment((v, aTable[i]));
+	/* Open the sql_stat tables for writing. */
+	for (uint i = 0; i < lengthof(space_names); ++i) {
+		uint32_t id = space_ids[i];
+		int tnum = SQLITE_PAGENO_FROM_SPACEID_AND_INDEXID(id, 0);
+		vdbe_emit_open_cursor(parse, stat_cursor + i, tnum,
+				      space_by_id(id));
+		VdbeComment((v, space_names[i]));
 	}
 }
 
@@ -1117,7 +1099,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_emit_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,10 +1127,12 @@ 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");
+	if (pOnlyIdx != NULL) {
+		vdbe_emit_stat_space_open(pParse, iStatCur, pOnlyIdx->zName,
+					  NULL);
 	} else {
-		openStatTable(pParse, iStatCur, pTab->def->name, "tbl");
+		vdbe_emit_stat_space_open(pParse, iStatCur, NULL,
+					  pTab->def->name);
 	}
 	analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur, pParse->nMem + 1,
 			pParse->nTab);
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 0072f84..21791a4 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -2050,6 +2050,60 @@ sql_store_select(struct Parse *parse_context, struct Select *select)
 }
 
 /**
+ * Create expression record "@col_name = '@col_value'".
+ *
+ * @param parse The parsing context.
+ * @param col_name Name of column.
+ * @param col_value 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_name,
+		   const char *col_value)
+{
+	struct sqlite3 *db = parse->db;
+
+	struct Expr *col_name_expr = sqlite3Expr(db, TK_ID, col_name);
+	if (col_name_expr == NULL)
+		return NULL;
+	struct Expr *col_value_expr = sqlite3Expr(db, TK_STRING, col_value);
+	if (col_value_expr == NULL) {
+		sql_expr_delete(db, col_name_expr, false);
+		return NULL;
+	}
+	return sqlite3PExpr(parse, TK_EQ, col_name_expr, col_value_expr);
+}
+
+void
+vdbe_emit_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.
  *
@@ -2059,30 +2113,11 @@ sql_store_select(struct Parse *parse_context, struct Select *select)
  * @param idx_name   Index to be dropped.
  */
 static void
-sql_clear_stat_spaces(Parse *parse, const char *table_name,
+sql_clear_stat_spaces(struct 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_emit_stat_space_clear(parse, "_sql_stat4", idx_name, table_name);
+	vdbe_emit_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..d76d173 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_emit_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

  reply	other threads:[~2018-07-10 17:08 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-10 17:08 [tarantool-patches] [PATCH v2 0/4] sql: get rid off sqlite3NestedParse Kirill Shcherbatov
2018-07-10 17:08 ` Kirill Shcherbatov [this message]
2018-07-10 17:52   ` [tarantool-patches] Re: [PATCH v2 1/4] sql: get rid off sqlite3NestedParse in clean stats n.pettik
2018-07-11  7:22     ` Kirill Shcherbatov
2018-07-11 12:19       ` n.pettik
2018-07-11 12:23         ` Kirill Shcherbatov
2018-07-11 13:16           ` n.pettik
2018-07-10 17:08 ` [tarantool-patches] [PATCH v2 2/4] sql: remove usless sqlite3NestedParse function Kirill Shcherbatov
2018-07-10 18:22   ` [tarantool-patches] " n.pettik
2018-07-11  7:22     ` Kirill Shcherbatov
2018-07-10 17:08 ` [tarantool-patches] [PATCH v2 3/4] sql: refactor vdbe_emit_open_cursor calls Kirill Shcherbatov
2018-07-10 18:22   ` [tarantool-patches] " n.pettik
2018-07-11  7:22     ` Kirill Shcherbatov
2018-07-10 17:08 ` [tarantool-patches] [PATCH v2 4/4] sql: remove OP_LoadPtr Kirill Shcherbatov
2018-07-10 18:34   ` [tarantool-patches] " n.pettik
2018-07-10 20:23     ` Vladislav Shpilevoy
2018-07-10 20:34       ` n.pettik
2018-07-11 13:45 ` [tarantool-patches] Re: [PATCH v2 0/4] sql: get rid off sqlite3NestedParse Kirill Yukhin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3017d0e640eebdc6c3f28b5b4a4cbd2ef5646882.1531242355.git.kshcherbatov@tarantool.org \
    --to=kshcherbatov@tarantool.org \
    --cc=korablev@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --subject='Re: [tarantool-patches] [PATCH v2 1/4] sql: get rid off sqlite3NestedParse in clean stats' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox