[tarantool-patches] [PATCH 3/7] sql: remove struct Table from analyze routine
Nikita Pettik
korablev at tarantool.org
Fri Aug 24 01:55:49 MSK 2018
Instead of using struct Table which is found by lookup in internal hash
lets use struct space from Tarantool DD.
Part of #3561
---
src/box/sql/analyze.c | 185 +++++++++++++++++++++++------------------
test/sql-tap/analyze1.test.lua | 2 +-
2 files changed, 107 insertions(+), 80 deletions(-)
diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index abed9d31b..e835a8697 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -124,7 +124,7 @@
* @param parse Parsing context.
* @param stat_cursor Open the _sql_stat1 table on this cursor.
* you should allocate |stat_names| cursors before call.
- * @param table_name Delete records of this index if specified.
+ * @param table_name Delete records of this table if specified.
*/
static void
vdbe_emit_stat_space_open(struct Parse *parse, int stat_cursor,
@@ -137,12 +137,6 @@ vdbe_emit_stat_space_open(struct Parse *parse, int stat_cursor,
assert(sqlite3VdbeDb(v) == parse->db);
for (uint i = 0; i < lengthof(stat_names); ++i) {
const char *space_name = stat_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) {
vdbe_emit_stat_space_clear(parse, space_name, NULL,
table_name);
@@ -770,61 +764,62 @@ callStatGet(Vdbe * v, int regStat4, int iParam, int regOut)
sqlite3VdbeChangeP5(v, 2);
}
-/*
+/**
* Generate code to do an analysis of all indices associated with
* a single table.
+ *
+ * @param pParse Current parsing context.
+ * @param space Space to be analyzed.
+ * @param stat_cursor Cursor pointing to spaces containing
+ * statistics: _sql_stat1 (stat_cursor) and
+ * _sql_stat4 (stat_cursor + 1).
*/
static void
-analyzeOneTable(Parse * pParse, /* Parser context */
- Table * pTab, /* Table whose indices are to be analyzed */
- int iStatCur, /* Index of VdbeCursor that writes the _sql_stat1 table */
- int iMem, /* Available memory locations begin here */
- int iTab /* Next available cursor */
- )
+vdbe_emit_analyze_space(struct Parse *pParse, struct space *space,
+ int stat_cursor)
{
sqlite3 *db = pParse->db; /* Database handle */
int iIdxCur; /* Cursor open on index being analyzed */
int iTabCur; /* Table cursor */
Vdbe *v; /* The virtual machine being built up */
int i; /* Loop counter */
- int regStat4 = iMem++; /* Register to hold Stat4Accum object */
- int regChng = iMem++; /* Index of changed index field */
- int regKey = iMem++; /* Key argument passed to stat_push() */
- int regTemp = iMem++; /* Temporary use register */
- int regTabname = iMem++; /* Register containing table name */
- int regIdxname = iMem++; /* Register containing index name */
- int regStat1 = iMem++; /* Value for the stat column of _sql_stat1 */
- int regPrev = iMem; /* MUST BE LAST (see below) */
-
- pParse->nMem = MAX(pParse->nMem, iMem);
+ /* Register to hold Stat4Accum object. */
+ int regStat4 = ++pParse->nMem;
+ /* Index of changed index field. */
+ int regChng = ++pParse->nMem;
+ /* Key argument passed to stat_push(). */
+ int regKey = ++pParse->nMem;
+ /* Temporary use register. */
+ int regTemp = ++pParse->nMem;
+ /* Register containing table name. */
+ int regTabname = ++pParse->nMem;
+ /* Register containing index name. */
+ int regIdxname = ++pParse->nMem;
+ /* Value for the stat column of _sql_stat1. */
+ int regStat1 = ++pParse->nMem;
+ /* MUST BE LAST (see below). */
+ int regPrev = ++pParse->nMem;
+
+ assert(space != NULL);
v = sqlite3GetVdbe(pParse);
- if (v == 0 || NEVER(pTab == 0)) {
- return;
- }
- assert(pTab->def->id != 0);
- if (sqlite3_strlike("\\_%", pTab->def->name, '\\') == 0) {
+ assert(v != NULL);
+ if (sqlite3_strlike("\\_%", space->def->name, '\\') == 0) {
/* Do not gather statistics on system tables */
return;
}
- /* Establish a read-lock on the table at the shared-cache level.
- * Open a read-only cursor on the table. Also allocate a cursor number
- * to use for scanning indexes (iIdxCur). No index cursor is opened at
- * this time though.
- */
- iTabCur = iTab++;
- iIdxCur = iTab++;
- pParse->nTab = MAX(pParse->nTab, iTab);
- sqlite3OpenTable(pParse, iTabCur, pTab, OP_OpenRead);
- sqlite3VdbeLoadString(v, regTabname, pTab->def->name);
/*
- * Here we need real space from Tarantool DD since
- * further it is passed to cursor opening routine.
+ * Open a read-only cursor on the table. Also allocate
+ * a cursor number to use for scanning indexes.
*/
- struct space *space = space_by_id(pTab->def->id);
- assert(space != NULL);
+ iTabCur = pParse->nTab;
+ pParse->nTab += 2;
+ assert(space->index_count != 0);
+ sqlite3VdbeAddOp4(v, OP_OpenRead, iTabCur, 0, 0, (void *) space,
+ P4_SPACEPTR);
+ sqlite3VdbeLoadString(v, regTabname, space->def->name);
for (uint32_t j = 0; j < space->index_count; ++j) {
- struct index *idx = pTab->space->index[j];
+ struct index *idx = space->index[j];
int addrRewind; /* Address of "OP_Rewind iIdxCur" */
int addrNextRow; /* Address of "next_row:" */
const char *idx_name; /* Name of the index */
@@ -834,14 +829,14 @@ analyzeOneTable(Parse * pParse, /* Parser context */
* instead more familiar table name.
*/
if (idx->def->iid == 0)
- idx_name = pTab->def->name;
+ idx_name = space->def->name;
else
idx_name = idx->def->name;
int part_count = idx->def->key_def->part_count;
/* Populate the register containing the index name. */
sqlite3VdbeLoadString(v, regIdxname, idx_name);
- VdbeComment((v, "Analysis for %s.%s", pTab->def->name,
+ VdbeComment((v, "Analysis for %s.%s", space->def->name,
idx_name));
/*
@@ -884,9 +879,16 @@ analyzeOneTable(Parse * pParse, /* Parser context */
pParse->nMem = MAX(pParse->nMem, regPrev + part_count);
/* Open a read-only cursor on the index being analyzed. */
- sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, idx->def->iid, 0,
- (void *) space, P4_SPACEPTR);
- VdbeComment((v, "%s", idx->def->name));
+ if (j != 0) {
+ iIdxCur = pParse->nTab - 1;
+ sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur,
+ idx->def->iid, 0,
+ (void *) space, P4_SPACEPTR);
+ VdbeComment((v, "%s", idx->def->name));
+ } else {
+ /* We have already opened cursor on PK. */
+ iIdxCur = iTabCur;
+ }
/* Invoke the stat_init() function. The arguments are:
*
@@ -989,7 +991,7 @@ analyzeOneTable(Parse * pParse, /* Parser context */
* if !eof(csr) goto next_row;
*/
assert(regKey == (regStat4 + 2));
- struct index *pPk = sql_table_primary_key(pTab);
+ struct index *pPk = space_index(space, 0);
int pk_part_count = pPk->def->key_def->part_count;
/* Allocate memory for array. */
pParse->nMem = MAX(pParse->nMem,
@@ -997,10 +999,10 @@ analyzeOneTable(Parse * pParse, /* Parser context */
int regKeyStat = regPrev + part_count;
for (i = 0; i < pk_part_count; i++) {
uint32_t k = pPk->def->key_def->parts[i].fieldno;
- assert(k < pTab->def->field_count);
+ assert(k < space->def->field_count);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k,
regKeyStat + i);
- VdbeComment((v, "%s", pTab->def->fields[k].name));
+ VdbeComment((v, "%s", space->def->fields[k].name));
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regKeyStat,
pk_part_count, regKey);
@@ -1017,7 +1019,7 @@ analyzeOneTable(Parse * pParse, /* Parser context */
assert("BBB"[0] == AFFINITY_TEXT);
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp,
"BBB", 0);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iStatCur, regTemp);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, stat_cursor, regTemp);
/* Add the entries to the stat4 table. */
@@ -1054,7 +1056,7 @@ analyzeOneTable(Parse * pParse, /* Parser context */
sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, part_count,
regSample);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp);
- sqlite3VdbeAddOp2(v, OP_IdxReplace, iStatCur + 1, regTemp);
+ sqlite3VdbeAddOp2(v, OP_IdxReplace, stat_cursor + 1, regTemp);
sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */
sqlite3VdbeJumpHere(v, addrIsNull);
@@ -1076,27 +1078,43 @@ loadAnalysis(Parse * pParse)
}
}
-/*
- * Generate code that will do an analysis of an entire database
+/**
+ * Wrapper to pass args to space_foreach callback.
+ */
+struct analyze_data {
+ struct Parse *parse_context;
+ /**
+ * Cursor numbers pointing to stat spaces:
+ * stat_cursor is opened on _sql_stat1 and
+ * stat_cursor + 1 - on _sql_stat4.
+ */
+ int stat_cursor;
+};
+
+static int
+sql_space_foreach_analyze(struct space *space, void *data)
+{
+ if (space->def->opts.sql == NULL || space->def->opts.is_view)
+ return 0;
+ struct analyze_data *anal_data = (struct analyze_data *) data;
+ vdbe_emit_analyze_space(anal_data->parse_context, space,
+ anal_data->stat_cursor);
+ return 0;
+}
+
+/**
+ * Generate code that will do an analysis of all spaces created
+ * via SQL facilities.
*/
static void
-sql_analyze_database(Parse *parser)
+sql_analyze_database(struct Parse *parser)
{
- struct Schema *schema = parser->db->pSchema;
sql_set_multi_write(parser, false);
int stat_cursor = parser->nTab;
- parser->nTab += 3;
+ parser->nTab += 2;
vdbe_emit_stat_space_open(parser, stat_cursor, NULL);
- int reg = parser->nMem + 1;
- int tab_cursor = parser->nTab;
- for (struct HashElem *k = sqliteHashFirst(&schema->tblHash); k != NULL;
- k = sqliteHashNext(k)) {
- struct Table *table = (struct Table *) sqliteHashData(k);
- if (! table->def->opts.is_view) {
- analyzeOneTable(parser, table, stat_cursor, reg,
- tab_cursor);
- }
- }
+ struct analyze_data anal_data = { parser, stat_cursor };
+ space_foreach(sql_space_foreach_analyze, (void *) &anal_data);
loadAnalysis(parser);
}
@@ -1108,15 +1126,18 @@ sql_analyze_database(Parse *parser)
* @param table Target table to analyze.
*/
static void
-vdbe_emit_analyze_table(struct Parse *parse, struct Table *table)
+vdbe_emit_analyze_table(struct Parse *parse, struct space *space)
{
- assert(table != NULL);
+ assert(space != NULL);
sql_set_multi_write(parse, false);
+ /*
+ * There are two system spaces for statistics: _sql_stat1
+ * and _sql_stat4.
+ */
int stat_cursor = parse->nTab;
- parse->nTab += 3;
- vdbe_emit_stat_space_open(parse, stat_cursor, table->def->name);
- analyzeOneTable(parse, table, stat_cursor, parse->nMem + 1,
- parse->nTab);
+ parse->nTab += 2;
+ vdbe_emit_stat_space_open(parse, stat_cursor, space->def->name);
+ vdbe_emit_analyze_space(parse, space, stat_cursor);
loadAnalysis(parse);
}
@@ -1142,15 +1163,21 @@ sqlite3Analyze(Parse * pParse, Token * pName)
/* Form 2: Analyze table named */
char *z = sqlite3NameFromToken(db, pName);
if (z != NULL) {
- Table *pTab = sqlite3LocateTable(pParse, 0, z);
- if (pTab != NULL) {
- if (pTab->def->opts.is_view) {
+ uint32_t space_id = box_space_id_by_name(z, strlen(z));
+ if (space_id != BOX_ID_NIL) {
+ struct space *sp = space_by_id(space_id);
+ assert(sp != NULL);
+ if (sp->def->opts.is_view) {
sqlite3ErrorMsg(pParse, "VIEW isn't "\
"allowed to be "\
"analyzed");
} else {
- vdbe_emit_analyze_table(pParse, pTab);
+ vdbe_emit_analyze_table(pParse, sp);
}
+ } else {
+ diag_set(ClientError, ER_NO_SUCH_SPACE, z);
+ pParse->rc = SQL_TARANTOOL_ERROR;
+ pParse->nErr++;
}
sqlite3DbFree(db, z);
}
diff --git a/test/sql-tap/analyze1.test.lua b/test/sql-tap/analyze1.test.lua
index dab7255e1..2d8eed950 100755
--- a/test/sql-tap/analyze1.test.lua
+++ b/test/sql-tap/analyze1.test.lua
@@ -26,7 +26,7 @@ test:do_catchsql_test(
ANALYZE no_such_table
]], {
-- <analyze-1.1>
- 1, "no such table: NO_SUCH_TABLE"
+ 1, "Space 'NO_SUCH_TABLE' does not exist"
-- </analyze-1.1>
})
--
2.15.1
More information about the Tarantool-patches
mailing list