From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 7C9202A3F2 for ; Thu, 23 Aug 2018 18:56:16 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id DgqcRiNCPwtg for ; Thu, 23 Aug 2018 18:56:16 -0400 (EDT) Received: from smtp48.i.mail.ru (smtp48.i.mail.ru [94.100.177.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id DE03A2A004 for ; Thu, 23 Aug 2018 18:56:15 -0400 (EDT) From: Nikita Pettik Subject: [tarantool-patches] [PATCH 5/7] sql: remove lookups in Table hash Date: Fri, 24 Aug 2018 01:55:51 +0300 Message-Id: <9de5ab38d451d8a024df8912e8d3ae086d5f6ab4.1535064700.git.korablev@tarantool.org> In-Reply-To: References: In-Reply-To: References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: v.shpilevoy@tarantool.org, Nikita Pettik 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(). + * + * 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(
) * - * - * 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