[tarantool-patches] [PATCH 5/7] sql: remove lookups in Table hash
Nikita Pettik
korablev at tarantool.org
Fri Aug 24 01:55:51 MSK 2018
Instead of looking at Table hash lets extract space from Tarantool
internals and create Table wrapper around it.
Part of #3561
---
src/box/sql/build.c | 16 +---
src/box/sql/delete.c | 84 ++++++++------------
src/box/sql/expr.c | 2 +-
src/box/sql/fkey.c | 15 +++-
src/box/sql/insert.c | 48 ++++++-----
src/box/sql/pragma.c | 176 ++++++++++++++++++++++-------------------
src/box/sql/select.c | 41 +---------
src/box/sql/sqliteInt.h | 35 +++++---
src/box/sql/trigger.c | 10 +--
src/box/sql/update.c | 10 +--
test/sql-tap/analyze9.test.lua | 2 +-
test/sql-tap/join.test.lua | 6 +-
test/sql/delete.result | 4 +-
13 files changed, 204 insertions(+), 245 deletions(-)
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 79dc46592..840604aa3 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -217,22 +217,10 @@ sqlite3CommitInternalChanges()
current_session()->sql_flags &= ~SQLITE_InternChanges;
}
-/*
- * Return true if given column is part of primary key.
- * If field number is less than 63, corresponding bit
- * in column mask is tested. Otherwise, check whether 64-th bit
- * in mask is set or not. If it is set, then iterate through
- * key parts of primary index and check field number.
- * In case it isn't set, there are no key columns among
- * the rest of fields.
- */
bool
-table_column_is_in_pk(Table *table, uint32_t column)
+sql_space_column_is_in_pk(struct space *space, uint32_t column)
{
- struct space *space = space_by_id(table->def->id);
- assert(space != NULL);
-
- struct index *primary_idx = index_find(space, 0 /* PK */);
+ struct index *primary_idx = space->index[0];
/* Views don't have any indexes. */
if (primary_idx == NULL)
return false;
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 0f285cc8b..a457a71d1 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -36,16 +36,31 @@
#include "tarantoolInt.h"
struct Table *
-sql_list_lookup_table(struct Parse *parse, SrcList *src_list)
+sql_lookup_table(struct Parse *parse, struct SrcList_item *tbl_name)
{
- struct SrcList_item *item = src_list->a;
- assert(item != NULL && src_list->nSrc == 1);
- struct Table *table = sqlite3LocateTable(parse, 0, item->zName);
- sqlite3DeleteTable(parse->db, item->pTab);
- item->pTab = table;
- if (table != NULL)
- item->pTab->nTabRef++;
- if (sqlite3IndexedByLookup(parse, item) != 0)
+ assert(tbl_name != NULL);
+ uint32_t space_id = box_space_id_by_name(tbl_name->zName,
+ strlen(tbl_name->zName));
+ sqlite3DeleteTable(parse->db, tbl_name->pTab);
+ struct space *space = space_by_id(space_id);
+ if (space_id == BOX_ID_NIL || space == NULL) {
+ sqlite3ErrorMsg(parse, "no such table: %s", tbl_name->zName);
+ return NULL;
+ }
+ assert(space != NULL);
+ if (space->def->field_count == 0) {
+ sqlite3ErrorMsg(parse, "no format for space: %s",
+ tbl_name->zName);
+ return NULL;
+ }
+ struct Table *table = sqlite3DbMallocZero(parse->db, sizeof(*table));
+ if (table == NULL)
+ return NULL;
+ table->def = space_def_dup(space->def);
+ table->space = space;
+ table->nTabRef = 1;
+ tbl_name->pTab = table;
+ if (sqlite3IndexedByLookup(parse, tbl_name) != 0)
table = NULL;
return table;
}
@@ -130,9 +145,6 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
* with multiple tables and expect an SrcList* parameter
* instead of just a Table* parameter.
*/
- struct Table *table = NULL;
- struct space *space = NULL;
- uint32_t space_id;
/* Figure out if we have any triggers and if the table
* being deleted from is a view.
*/
@@ -140,44 +152,14 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
/* True if there are triggers or FKs or subqueries in the
* WHERE clause.
*/
- bool is_complex = false;
- const char *tab_name = tab_list->a->zName;
- struct Table tmp_tab;
- if (sqlite3LocateTable(parse, LOCATE_NOERR, tab_name) == NULL) {
- space_id = box_space_id_by_name(tab_name,
- strlen(tab_name));
- if (space_id == BOX_ID_NIL) {
- diag_set(ClientError, ER_NO_SUCH_SPACE, tab_name);
- parse->rc = SQL_TARANTOOL_ERROR;
- parse->nErr++;
- goto delete_from_cleanup;
- }
- /*
- * In this case space has been created via Lua
- * facilities, so there is no corresponding entry
- * in table hash. Thus, lets create simple
- * wrapper around space_def to support interface.
- */
- space = space_by_id(space_id);
- memset(&tmp_tab, 0, sizeof(tmp_tab));
- tmp_tab.def = space->def;
- /* Prevent from freeing memory in DeleteTable. */
- tmp_tab.space = space;
- tmp_tab.nTabRef = 2;
- tab_list->a[0].pTab = &tmp_tab;
- } else {
- table = sql_list_lookup_table(parse, tab_list);
- if (table == NULL)
- goto delete_from_cleanup;
- space_id = table->def->id;
- space = space_by_id(space_id);
- assert(space != NULL);
- trigger_list = sql_triggers_exist(table, TK_DELETE, NULL, NULL);
- is_complex = trigger_list != NULL ||
- fkey_is_required(table->def->id, NULL);
- }
- assert(space != NULL);
-
+ struct Table *table = sql_lookup_table(parse, tab_list->a);
+ if (table == NULL)
+ goto delete_from_cleanup;
+ assert(table->space != NULL);
+ trigger_list = sql_triggers_exist(table, TK_DELETE, NULL, NULL);
+ bool is_complex = trigger_list != NULL ||
+ fkey_is_required(table->def->id, NULL);
+ struct space *space = table->space;
bool is_view = space->def->opts.is_view;
/* If table is really a view, make sure it has been
@@ -230,7 +212,7 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
if (where == NULL && !is_complex) {
assert(!is_view);
- sqlite3VdbeAddOp1(v, OP_Clear, space_id);
+ sqlite3VdbeAddOp1(v, OP_Clear, space->def->id);
/* Do not start Tarantool's transaction in case of
* truncate optimization. This is workaround until
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index cb4f89e35..7b6300c75 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -278,7 +278,7 @@ comparisonAffinity(Expr * pExpr)
aff =
sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr,
aff);
- } else if (NEVER(aff == 0)) {
+ } else {
aff = AFFINITY_BLOB;
}
return aff;
diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c
index 62337792b..215ad2867 100644
--- a/src/box/sql/fkey.c
+++ b/src/box/sql/fkey.c
@@ -612,11 +612,18 @@ fkey_emit_check(struct Parse *parser, struct Table *tab, int reg_old,
struct SrcList_item *item = src->a;
struct space *child = space_by_id(fk->def->child_id);
assert(child != NULL);
- struct Table *child_tab = sqlite3HashFind(&db->pSchema->tblHash,
- child->def->name);
- item->pTab = child_tab;
+ /*
+ * Create surrogate struct Table wrapper around
+ * space_def to support legacy interface.
+ */
+ struct Table fake_tab;
+ memset(&fake_tab, 0, sizeof(fake_tab));
+ fake_tab.def = child->def;
+ fake_tab.space = child;
+ item->pTab = &fake_tab;
item->zName = sqlite3DbStrDup(db, child->def->name);
- item->pTab->nTabRef++;
+ /* Prevent from deallocationg fake_tab. */
+ item->pTab->nTabRef = 2;
item->iCursor = parser->nTab++;
if (reg_new != 0) {
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 9220d34e1..d3950254e 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -38,6 +38,7 @@
#include "box/session.h"
#include "box/schema.h"
#include "bit/bit.h"
+#include "box/box.h"
/*
* Generate code that will open pTab as cursor iCur.
@@ -150,7 +151,6 @@ vdbe_has_table_read(struct Parse *parser, const struct Table *table)
return false;
}
-
/* Forward declaration */
static int
xferOptimization(Parse * pParse, /* Parser context */
@@ -314,7 +314,7 @@ sqlite3Insert(Parse * pParse, /* Parser context */
zTab = pTabList->a[0].zName;
if (NEVER(zTab == 0))
goto insert_cleanup;
- pTab = sql_list_lookup_table(pParse, pTabList);
+ pTab = sql_lookup_table(pParse, pTabList->a);
if (pTab == NULL)
goto insert_cleanup;
@@ -1161,7 +1161,6 @@ xferOptimization(Parse * pParse, /* Parser context */
int onError) /* How to handle constraint errors */
{
ExprList *pEList; /* The result set of the SELECT */
- Table *pSrc; /* The table in the FROM clause of SELECT */
struct index *pSrcIdx, *pDestIdx;
struct SrcList_item *pItem; /* An element of pSelect->pSrc */
int i; /* Loop counter */
@@ -1234,40 +1233,40 @@ xferOptimization(Parse * pParse, /* Parser context */
* we have to check the semantics.
*/
pItem = pSelect->pSrc->a;
- pSrc = sqlite3LocateTable(pParse, 0, pItem->zName);
+ uint32_t src_id = box_space_id_by_name(pItem->zName,
+ strlen(pItem->zName));
/* FROM clause does not contain a real table. */
- if (pSrc == NULL)
+ if (src_id == BOX_ID_NIL)
return 0;
+ struct space *src = space_by_id(src_id);
+ assert(src != NULL);
/* Src and dest may not be the same table. */
- if (pSrc == pDest)
+ if (src->def->id == pDest->space->def->id)
return 0;
/* Src may not be a view. */
- if (pSrc->def->opts.is_view)
+ if (src->def->opts.is_view)
return 0;
/* Number of columns must be the same in src and dst. */
- if (pDest->def->field_count != pSrc->def->field_count)
+ if (pDest->def->field_count != src->def->field_count)
return 0;
for (i = 0; i < (int)pDest->def->field_count; i++) {
enum affinity_type dest_affinity =
pDest->def->fields[i].affinity;
enum affinity_type src_affinity =
- pSrc->def->fields[i].affinity;
+ src->def->fields[i].affinity;
/* Affinity must be the same on all columns. */
if (dest_affinity != src_affinity)
return 0;
uint32_t id;
if (sql_column_collation(pDest->def, i, &id) !=
- sql_column_collation(pSrc->def, i, &id)) {
- return 0; /* Collating sequence must be the same on all columns */
- }
- if (!pDest->def->fields[i].is_nullable
- && pSrc->def->fields[i].is_nullable) {
- return 0; /* tab2 must be NOT NULL if tab1 is */
- }
+ sql_column_collation(src->def, i, &id))
+ return 0;
+ if (!pDest->def->fields[i].is_nullable &&
+ src->def->fields[i].is_nullable)
+ return 0;
/* Default values for second and subsequent columns need to match. */
if (i > 0) {
- char *src_expr_str =
- pSrc->def->fields[i].default_value;
+ char *src_expr_str = src->def->fields[i].default_value;
char *dest_expr_str =
pDest->def->fields[i].default_value;
if ((dest_expr_str == NULL) != (src_expr_str == NULL) ||
@@ -1282,8 +1281,8 @@ xferOptimization(Parse * pParse, /* Parser context */
pDestIdx = pDest->space->index[i];
if (pDestIdx->def->opts.is_unique)
destHasUniqueIdx = 1;
- for (uint32_t j = 0; j < pSrc->space->index_count; ++j) {
- pSrcIdx = pSrc->space->index[j];
+ for (uint32_t j = 0; j < src->index_count; ++j) {
+ pSrcIdx = src->index[j];
if (sql_index_is_xfer_compatible(pDestIdx->def,
pSrcIdx->def))
break;
@@ -1293,7 +1292,7 @@ xferOptimization(Parse * pParse, /* Parser context */
return 0;
}
/* Get server checks. */
- ExprList *pCheck_src = space_checks_expr_list(pSrc->def->id);
+ ExprList *pCheck_src = space_checks_expr_list(src->def->id);
ExprList *pCheck_dest = space_checks_expr_list(pDest->def->id);
if (pCheck_dest != NULL &&
sqlite3ExprListCompare(pCheck_src, pCheck_dest, -1) != 0) {
@@ -1353,11 +1352,8 @@ xferOptimization(Parse * pParse, /* Parser context */
}
assert(pSrcIdx);
- struct space *src_space =
- space_by_id(pSrc->def->id);
- vdbe_emit_open_cursor(pParse, iSrc,
- pSrcIdx->def->iid,
- src_space);
+
+ vdbe_emit_open_cursor(pParse, iSrc, pSrcIdx->def->iid, src);
VdbeComment((v, "%s", pSrcIdx->def->name));
struct space *dest_space = space_by_id(pDest->def->id);
vdbe_emit_open_cursor(pParse, iDest,
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 6173462ff..063836989 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -245,6 +245,95 @@ sql_default_engine_set(const char *engine_name)
return 0;
}
+/**
+ * This function handles PRAGMA TABLE_INFO(<table>).
+ *
+ * Return a single row for each column of the named table.
+ * The columns of the returned data set are:
+ *
+ * - cid: Column id (numbered from left to right, starting at 0);
+ * - name: Column name;
+ * - type: Column declaration type;
+ * - notnull: True if 'NOT NULL' is part of column declaration;
+ * - dflt_value: The default value for the column, if any.
+ *
+ * @param parse Current parsing context.
+ * @param tbl_name Name of table to be examined.
+ */
+static void
+sql_pragma_table_info(struct Parse *parse, const char *tbl_name)
+{
+ if (tbl_name == NULL)
+ return;
+ uint32_t space_id = box_space_id_by_name(tbl_name, strlen(tbl_name));
+ if (space_id == BOX_ID_NIL)
+ return;
+ struct space *space = space_by_id(space_id);
+ assert(space != NULL);
+ struct space_def *def = space->def;
+ struct index *pk = space->index[0];
+ parse->nMem = 6;
+ if (def->opts.is_view) {
+ const char *sql = def->opts.sql;
+ sql_view_assign_cursors(parse, sql);
+ }
+ struct Vdbe *v = sqlite3GetVdbe(parse);
+ for (uint32_t i = 0, k; i < def->field_count; ++i) {
+ if (!sql_space_column_is_in_pk(space, i)) {
+ k = 0;
+ } else if (pk == NULL) {
+ k = 1;
+ } else {
+ struct key_def *kdef = pk->def->key_def;
+ k = key_def_find(kdef, i) - kdef->parts + 1;
+ }
+ bool is_nullable = def->fields[i].is_nullable;
+ char *expr_str = def->fields[i].default_value;
+ const char *name = def->fields[i].name;
+ enum field_type type = def->fields[i].type;
+ sqlite3VdbeMultiLoad(v, 1, "issisi", i, name,
+ field_type_strs[type], !is_nullable,
+ expr_str, k);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
+ }
+}
+
+/**
+ * This function handles PRAGMA stats.
+ * It displays estimate (log) number of tuples in space and
+ * average size of tuple in each index.
+ *
+ * @param space Space to be examined.
+ * @param data Parsing context passed as callback argument.
+ */
+static int
+sql_pragma_table_stats(struct space *space, void *data)
+{
+ if (space->def->opts.sql == NULL || space->def->opts.is_view)
+ return 0;
+ struct Parse *parse = (struct Parse *) data;
+ struct index *pk = space_index(space, 0);
+ if (pk == NULL)
+ return 0;
+ struct Vdbe *v = sqlite3GetVdbe(parse);
+ LogEst tuple_count_est = sqlite3LogEst(pk->vtab->size(pk));
+ size_t avg_tuple_size_pk = sql_index_tuple_size(space, pk);
+ parse->nMem = 4;
+ sqlite3VdbeMultiLoad(v, 1, "ssii", space->def->name, 0,
+ avg_tuple_size_pk, tuple_count_est);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
+ for (uint32_t i = 0; i < space->index_count; ++i) {
+ struct index *idx = space->index[i];
+ assert(idx != NULL);
+ size_t avg_tuple_size_idx = sql_index_tuple_size(space, idx);
+ sqlite3VdbeMultiLoad(v, 2, "sii", idx->def->name,
+ avg_tuple_size_idx,
+ index_field_tuple_est(idx->def, 0));
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
+ }
+ return 0;
+}
+
/**
* This function handles PRAGMA INDEX_INFO and PRAGMA INDEX_XINFO
* statements.
@@ -431,93 +520,18 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */
#endif /* SQLITE_OMIT_FLAG_PRAGMAS */
#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
- /* * PRAGMA table_info(<table>) *
- *
- * Return a single row for each column of the named table. The
- * columns of * the returned data set are: *
- *
- * cid: Column id (numbered from left to right, starting at
- * 0) * name: Column name * type: Column
- * declaration type. * notnull: True if 'NOT NULL' is part
- * of column declaration * dflt_value: The default value for
- * the column, if any.
- */
case PragTyp_TABLE_INFO:
- if (zRight == NULL)
- break;
- struct Table *table =
- sqlite3LocateTable(pParse, LOCATE_NOERR, zRight);
- if (table == NULL)
- break;
- struct space *space = space_cache_find(table->def->id);
- struct space_def *def = space->def;
- struct index *pk = sql_table_primary_key(table);
- pParse->nMem = 6;
- if (def->opts.is_view) {
- const char *sql = table->def->opts.sql;
- sql_view_assign_cursors(pParse, sql);
- }
- for (uint32_t i = 0, k; i < def->field_count; ++i) {
- if (!table_column_is_in_pk(table, i)) {
- k = 0;
- } else if (pk == NULL) {
- k = 1;
- } else {
- struct key_def *kdef = pk->def->key_def;
- k = key_def_find(kdef, i) - kdef->parts + 1;
- }
- bool is_nullable = def->fields[i].is_nullable;
- char *expr_str = def->fields[i].default_value;
- const char *name = def->fields[i].name;
- enum field_type type = def->fields[i].type;
- sqlite3VdbeMultiLoad(v, 1, "issisi", i, name,
- field_type_strs[type],
- !is_nullable, expr_str, k);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
- }
+ sql_pragma_table_info(pParse, zRight);
break;
-
- case PragTyp_STATS:{
- HashElem *i;
- pParse->nMem = 4;
- for (i = sqliteHashFirst(&db->pSchema->tblHash); i;
- i = sqliteHashNext(i)) {
- Table *pTab = sqliteHashData(i);
- struct space *space = space_by_id(pTab->def->id);
- assert(space != NULL);
- struct index *pk = space_index(space, 0);
- size_t avg_tuple_size_pk =
- sql_index_tuple_size(space, pk);
- sqlite3VdbeMultiLoad(v, 1, "ssii",
- pTab->def->name,
- 0,
- avg_tuple_size_pk,
- sql_space_tuple_log_count(pTab));
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
- for (uint32_t i = 0; i < pTab->space->index_count; ++i) {
- struct index *idx = pTab->space->index[i];
- assert(idx != NULL);
- size_t avg_tuple_size_idx =
- sql_index_tuple_size(space, idx);
- sqlite3VdbeMultiLoad(v, 2, "sii",
- idx->def->name,
- avg_tuple_size_idx,
- index_field_tuple_est(idx->def, 0));
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1,
- 4);
- }
- }
- break;
- }
-
- case PragTyp_INDEX_INFO:{
+ case PragTyp_STATS:
+ space_foreach(sql_pragma_table_stats, (void *) pParse);
+ break;
+ case PragTyp_INDEX_INFO:
sql_pragma_index_info(pParse, pPragma, zTable, zRight);
break;
- }
- case PragTyp_INDEX_LIST:{
+ case PragTyp_INDEX_LIST:
sql_pragma_index_list(pParse, zRight);
break;
- }
case PragTyp_COLLATION_LIST:{
int i = 0;
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index dd6a8f1b0..a20d0bb3f 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -4812,44 +4812,9 @@ selectExpander(Walker * pWalker, Select * p)
* FROM clause.
*/
assert(pFrom->pTab == NULL);
- const char *t_name = pFrom->zName;
- pFrom->pTab = pTab =
- sqlite3LocateTable(pParse, LOCATE_NOERR, t_name);
- if (pTab == NULL) {
- int space_id =
- box_space_id_by_name(t_name,
- strlen(t_name));
- struct space *space = space_by_id(space_id);
- if (space == NULL) {
- sqlite3ErrorMsg(pParse,
- "no such table: %s",
- t_name);
- return WRC_Abort;
- }
- if (space->def->field_count <= 0) {
- sqlite3ErrorMsg(pParse, "no format for"\
- " space: %s", t_name);
- return WRC_Abort;
- }
- struct Table *tab =
- sqlite3DbMallocZero(db, sizeof(*tab));
- if (tab == NULL)
- return WRC_Abort;
- tab->nTabRef = 1;
- tab->def = space_def_dup(space->def);
- tab->space = space;
- pFrom->pTab = pTab = tab;
- } else {
- if (pTab->nTabRef >= 0xffff) {
- sqlite3ErrorMsg(pParse, "too many "\
- "references to "\
- "\"%s\": max 65535",
- t_name);
- pFrom->pTab = NULL;
- return WRC_Abort;
- }
- pTab->nTabRef++;
- }
+ pTab = sql_lookup_table(pParse, pFrom);
+ if (pTab == NULL)
+ return WRC_Abort;
if (cannotBeFunction(pParse, pFrom))
return WRC_Abort;
if (pTab->def->opts.is_view) {
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 3ae8db1bc..08893c473 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -3333,6 +3333,11 @@ void sqlite3ExprListSetSpan(Parse *, ExprList *, ExprSpan *);
u32 sqlite3ExprListFlags(const ExprList *);
int sqlite3Init(sqlite3 *);
+void sqlite3Pragma(Parse *, Token *, Token *, Token *, int);
+void sqlite3ResetAllSchemasOfConnection(sqlite3 *);
+void sqlite3CommitInternalChanges();
+void sqlite3DeleteColumnNames(sqlite3 *, Table *);
+
/**
* This is the callback routine for the code that initializes the
* database. See sqlite3Init() below for additional information.
@@ -3351,11 +3356,17 @@ int
sql_init_callback(struct init_data *init, const char *name,
uint32_t space_id, uint32_t index_id, const char *sql);
-void sqlite3Pragma(Parse *, Token *, Token *, Token *, int);
-void sqlite3ResetAllSchemasOfConnection(sqlite3 *);
-void sqlite3CommitInternalChanges();
-void sqlite3DeleteColumnNames(sqlite3 *, Table *);
-bool table_column_is_in_pk(Table *, uint32_t);
+/**
+ * Return true if given column is part of primary key.
+ * If field number is less than 63, corresponding bit
+ * in column mask is tested. Otherwise, check whether 64-th bit
+ * in mask is set or not. If it is set, then iterate through
+ * key parts of primary index and check field number.
+ * In case it isn't set, there are no key columns among
+ * the rest of fields.
+ */
+bool
+sql_space_column_is_in_pk(struct space *space, uint32_t);
/**
* Given an expression list (which is really the list of expressions
@@ -3558,10 +3569,10 @@ Select *sqlite3SelectNew(Parse *, ExprList *, SrcList *, Expr *, ExprList *,
* While a SrcList can in general represent multiple tables and
* subqueries (as in the FROM clause of a SELECT statement) in
* this case it contains the name of a single table, as one might
- * find in an INSERT, DELETE, or UPDATE statement. Look up that
- * table in the symbol table and return a pointer. Set an error
- * message and return NULL if the table name is not found or if
- * any other error occurs.
+ * find in an INSERT, DELETE, or UPDATE statement. Look up that
+ * space in the cache and create Table wrapper around it.
+ * Set an error message and return NULL if the table name is not
+ * found or if space doesn't have format.
*
* The following fields are initialized appropriate in src_list:
*
@@ -3570,11 +3581,11 @@ Select *sqlite3SelectNew(Parse *, ExprList *, SrcList *, Expr *, ExprList *,
* if there is one.
*
* @param parse Parsing context.
- * @param src_list List containing single table element.
- * @retval Table object if found, NULL oterwise.
+ * @param tbl_name Table element.
+ * @retval Table object if found, NULL otherwise.
*/
struct Table *
-sql_list_lookup_table(struct Parse *parse, struct SrcList *src_list);
+sql_lookup_table(struct Parse *parse, struct SrcList_item *tbl_name);
void sqlite3OpenTable(Parse *, int iCur, Table *, int);
/**
diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c
index bd730c401..b6b727fdd 100644
--- a/src/box/sql/trigger.c
+++ b/src/box/sql/trigger.c
@@ -204,18 +204,14 @@ sql_trigger_finish(struct Parse *parse, struct TriggerStep *step_list,
if (v == 0)
goto triggerfinish_cleanup;
- struct Table *sys_trigger =
- sqlite3HashFind(&parse->db->pSchema->tblHash,
- TARANTOOL_SYS_TRIGGER_NAME);
- if (NEVER(sys_trigger == NULL))
- goto triggerfinish_cleanup;
-
sql_str = sqlite3MPrintf(db, "CREATE TRIGGER %s", token->z);
if (db->mallocFailed)
goto triggerfinish_cleanup;
int cursor = parse->nTab++;
- sqlite3OpenTable(parse, cursor, sys_trigger, OP_OpenWrite);
+ struct space *_trigger = space_by_id(BOX_TRIGGER_ID);
+ assert(_trigger != NULL);
+ vdbe_emit_open_cursor(parse, cursor, 0, _trigger);
/*
* makerecord(cursor(iRecord),
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 63d48705e..e3876f293 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -121,7 +121,7 @@ sqlite3Update(Parse * pParse, /* The parser context */
/* Locate the table which we want to update.
*/
- pTab = sql_list_lookup_table(pParse, pTabList);
+ pTab = sql_lookup_table(pParse, pTabList->a);
if (pTab == NULL)
goto update_cleanup;
@@ -171,9 +171,9 @@ sqlite3Update(Parse * pParse, /* The parser context */
for (j = 0; j < (int)def->field_count; j++) {
if (strcmp(def->fields[j].name,
pChanges->a[i].zName) == 0) {
- if (pPk && table_column_is_in_pk(pTab, j)) {
+ if (pPk &&
+ sql_space_column_is_in_pk(pTab->space, j))
is_pk_modified = true;
- }
if (aXRef[j] != -1) {
sqlite3ErrorMsg(pParse,
"set id list: duplicate"
@@ -329,8 +329,8 @@ sqlite3Update(Parse * pParse, /* The parser context */
pTab, on_error);
for (i = 0; i < (int)def->field_count; i++) {
if (oldmask == 0xffffffff
- || (i < 32 && (oldmask & MASKBIT32(i)) != 0)
- || table_column_is_in_pk(pTab, i)) {
+ || (i < 32 && (oldmask & MASKBIT32(i)) != 0) ||
+ sql_space_column_is_in_pk(pTab->space, i)) {
testcase(oldmask != 0xffffffff && i == 31);
sqlite3ExprCodeGetColumnOfTable(v, def,
pk_cursor, i,
diff --git a/test/sql-tap/analyze9.test.lua b/test/sql-tap/analyze9.test.lua
index 2b37e3ad5..05ed50192 100755
--- a/test/sql-tap/analyze9.test.lua
+++ b/test/sql-tap/analyze9.test.lua
@@ -1021,7 +1021,7 @@ test:do_execsql_test(
INSERT INTO x1 VALUES(3, 4);
INSERT INTO x1 VALUES(5, 6);
ANALYZE;
- INSERT INTO "_sql_stat4" VALUES('x1', 'abc', 0, 0, 0, '');
+ INSERT INTO "_sql_stat4" VALUES('x1', 'abc', '', '', '', '');
]])
test:do_execsql_test(
diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index 04b7674ed..ac05a98b2 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -1080,9 +1080,9 @@ jointest("join-12.9", 1000, {1, 'at most 64 tables in a join'})
-- if X(703, "X!cmd", [=[["expr","[lsearch [db eval {PRAGMA compile_options}] MEMDEBUG]<0"]]=])
-- then
jointest("join-12.10", 65534, {1, 'at most 64 tables in a join'})
-jointest("join-12.11", 65535, {1, 'too many references to "T14": max 65535'})
-jointest("join-12.12", 65536, {1, 'too many references to "T14": max 65535'})
-jointest("join-12.13", 65537, {1, 'too many references to "T14": max 65535'})
+jointest("join-12.11", 65535, {1, 'at most 64 tables in a join'})
+jointest("join-12.12", 65536, {1, 'at most 64 tables in a join'})
+jointest("join-12.13", 65537, {1, 'at most 64 tables in a join'})
-- end
--end
diff --git a/test/sql/delete.result b/test/sql/delete.result
index 52f9969c1..993e9e04d 100644
--- a/test/sql/delete.result
+++ b/test/sql/delete.result
@@ -44,7 +44,7 @@ box.sql.execute("DROP TABLE t1;");
--
box.sql.execute("DELETE FROM t1;")
---
-- error: Space 'T1' does not exist
+- error: 'no such table: T1'
...
box.sql.execute("CREATE TABLE t2 (s1 INT PRIMARY KEY);")
---
@@ -54,7 +54,7 @@ box.sql.execute("CREATE TRIGGER t2 BEFORE INSERT ON t2 BEGIN DELETE FROM t1; END
...
box.sql.execute("INSERT INTO t2 VALUES (0);")
---
-- error: Space 'T1' does not exist
+- error: 'no such table: T1'
...
box.sql.execute("DROP TABLE t2;")
---
--
2.15.1
More information about the Tarantool-patches
mailing list