[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