[tarantool-patches] [PATCH v2 1/4] sql: get rid off sqlite3NestedParse in clean stats
Kirill Shcherbatov
kshcherbatov at tarantool.org
Tue Jul 10 20:08:08 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 | 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
More information about the Tarantool-patches
mailing list