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 EDEFD2945E for ; Tue, 28 Aug 2018 20:58:39 -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 sXMTu9nDVjbZ for ; Tue, 28 Aug 2018 20:58:39 -0400 (EDT) Received: from smtp47.i.mail.ru (smtp47.i.mail.ru [94.100.177.107]) (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 5AF682944D for ; Tue, 28 Aug 2018 20:58:39 -0400 (EDT) Subject: [tarantool-patches] Re: [PATCH 2/7] sql: remove SQLite original struct Index References: <282cdd4662d2195250c1e9a828fde201d4822974.1535064700.git.korablev@tarantool.org> From: Vladislav Shpilevoy Message-ID: <0bd856e4-2178-cfa9-b680-fe1d47ce16c7@tarantool.org> Date: Tue, 28 Aug 2018 21:58:30 -0300 MIME-Version: 1.0 In-Reply-To: <282cdd4662d2195250c1e9a828fde201d4822974.1535064700.git.korablev@tarantool.org> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit 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, Nikita Pettik Thanks for the patch! See 16 comments below and a commit on the branch. On 23/08/2018 19:55, Nikita Pettik wrote: > As a part of SQL DD integration it is required to substitute SQLite > structure representing index with one from Tarantool internals. > To make this happen, lets add surrogate space to Table, which will > hold array of indexes. Those indexes are not real copies from Tarantool > core, but contain only index_def, since only def is useful during query > compilation. > > Note that in new implementation indexes are held as array and added to > that array in straight order. In SQLite indexes are arranged in list and > added to the head. Hence, the order of indexes is reversed. It results > in different query plans: if planner must make choice of two equal > indexes, it chooses simply first one. Due to this change, some tests are > fixed. > > Part of #3561 > --- > src/box/sql.c | 56 +-- > src/box/sql/analyze.c | 69 ++-- > src/box/sql/build.c | 689 ++++++++++--------------------- > src/box/sql/delete.c | 14 +- > src/box/sql/expr.c | 120 +----- > src/box/sql/insert.c | 92 ++--- > src/box/sql/parse.y | 8 - > src/box/sql/pragma.c | 188 ++++----- > src/box/sql/prepare.c | 7 +- > src/box/sql/select.c | 17 +- > src/box/sql/sqliteInt.h | 79 ++-- > src/box/sql/tarantoolInt.h | 34 +- > src/box/sql/update.c | 3 +- > src/box/sql/vdbe.c | 12 +- > src/box/sql/vdbe.h | 6 +- > src/box/sql/vdbeaux.c | 6 +- > src/box/sql/vdbemem.c | 28 +- > src/box/sql/where.c | 381 ++++++++--------- > src/box/sql/whereInt.h | 8 +- > src/box/sql/wherecode.c | 167 +++----- > test/sql-tap/analyze3.test.lua | 2 +- > test/sql-tap/analyze7.test.lua | 8 +- > test/sql-tap/analyze9.test.lua | 10 +- > test/sql-tap/analyzeF.test.lua | 2 +- > test/sql-tap/eqp.test.lua | 14 +- > test/sql-tap/gh-2996-indexed-by.test.lua | 10 +- > test/sql-tap/lua-tables.test.lua | 8 +- > 27 files changed, 807 insertions(+), 1231 deletions(-) > > diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c > index 74f5ae827..abed9d31b 100644 > --- a/src/box/sql/analyze.c > +++ b/src/box/sql/analyze.c > @@ -819,23 +817,27 @@ analyzeOneTable(Parse * pParse, /* Parser context */ > pParse->nTab = MAX(pParse->nTab, iTab); > sqlite3OpenTable(pParse, iTabCur, pTab, OP_OpenRead); > sqlite3VdbeLoadString(v, regTabname, pTab->def->name); > - > - for (pIdx = pTab->pIndex; pIdx; pIdx = pIdx->pNext) { > + /* > + * Here we need real space from Tarantool DD since > + * further it is passed to cursor opening routine. > + */ > + struct space *space = space_by_id(pTab->def->id); > + assert(space != NULL); > + for (uint32_t j = 0; j < space->index_count; ++j) { > + struct index *idx = pTab->space->index[j]; > int addrRewind; /* Address of "OP_Rewind iIdxCur" */ > int addrNextRow; /* Address of "next_row:" */ > const char *idx_name; /* Name of the index */ > > - if (pOnlyIdx && pOnlyIdx != pIdx) > - continue; > /* Primary indexes feature automatically generated > * names. Thus, for the sake of clarity, use > * instead more familiar table name. > */ > - if (sql_index_is_primary(pIdx)) > + if (idx->def->iid == 0) > idx_name = pTab->def->name; > else > - idx_name = pIdx->def->name; > - int part_count = pIdx->def->key_def->part_count; > + idx_name = idx->def->name; > + int part_count = idx->def->key_def->part_count; 1. Below you have check 'if (part_count > 0)', but it is always true, it is not? > > /* Populate the register containing the index name. */ > sqlite3VdbeLoadString(v, regIdxname, idx_name); > diff --git a/src/box/sql/build.c b/src/box/sql/build.c > index 47fa7c305..79dc46592 100644 > --- a/src/box/sql/build.c > +++ b/src/box/sql/build.c > @@ -151,55 +151,46 @@ sqlite3LocateIndex(sqlite3 * db, const char *zName, const char *zTable) > > if (pTab == NULL) > return NULL; > - for (struct Index *idx = pTab->pIndex; idx != NULL; idx = idx->pNext) { > + for (uint32_t i = 0; i < pTab->space->index_count; ++i) { > + struct index *idx = pTab->space->index[i]; > if (strcmp(zName, idx->def->name) == 0) > return idx; > } > return NULL; > } > > -/* > - * Reclaim the memory used by an index > - */ > -static void > -freeIndex(sqlite3 * db, Index * p) > -{ > - if (p->def != NULL) > - index_def_delete(p->def); > - sqlite3DbFree(db, p); > -} > - > -/* > - * For the index called zIdxName which is found in the database, > - * unlike that index from its Table then remove the index from > - * the index hash table and free all memory structures associated > - * with the index. > - */ > void > -sqlite3UnlinkAndDeleteIndex(sqlite3 * db, Index * pIndex) > +sql_space_index_delete(struct space *space, uint32_t iid) > { > - assert(pIndex != 0); > - > - struct session *user_session = current_session(); > - if (ALWAYS(pIndex)) { > - if (pIndex->pTable->pIndex == pIndex) { > - pIndex->pTable->pIndex = pIndex->pNext; > - } else { > - Index *p; > - /* Justification of ALWAYS(); The index must be on the list of > - * indices. > - */ > - p = pIndex->pTable->pIndex; > - while (ALWAYS(p) && p->pNext != pIndex) { > - p = p->pNext; > - } > - if (ALWAYS(p && p->pNext == pIndex)) { > - p->pNext = pIndex->pNext; > + assert(space != NULL); > + for (uint32_t i = 0; i < space->index_count; ++i) { > + struct index *idx = space->index[i]; 2. You have mentioned that space indexes are stored as an array, but it is not the only true. The indexes are stored in two ways: as an array and a map. A map allows to find an index by id in O(1) time. Look at space_index function. Here you do not clear space->index_map and do not reallocate it. Looks like you do not touch index_map at all in this patch. But maybe you should. See my other comments here and in next patches. > + /* > + * Allocate new chunk with size reduced by 1 slot. > + * Copy all indexes to that chunk except for one > + * to be deleted. > + */ > + if (idx->def->iid == iid) { > + free(idx->def); 3. idx->def->key_def leaks. cmp_def as well. Please, use index_def_delete. Same in other places where you delete index_def (whereLoopClearUnion, etc). > + free(idx); > + size_t idx_sz = sizeof(struct index *); > + uint32_t idx_count = --space->index_count; 4. If malloc below fails, index_count will remain decremented. > + struct index **new_idexes = > + (struct index **) malloc(idx_sz * idx_count); 5. Typo: 'idexes'. > + if (new_idexes == NULL) { > + diag_set(OutOfMemory, idx_sz * idx_count, > + "malloc", "new_indexes"); > + return; > } > + memcpy(new_idexes, space->index, i * idx_sz); > + memcpy(new_idexes + i, space->index + i + 1, > + idx_sz * (idx_count - i)); > + free(space->index); > + space->index = new_idexes; > + break; > } > - freeIndex(db, pIndex); > } > - > + struct session *user_session = current_session(); > user_session->sql_flags |= SQLITE_InternChanges; > } > > @@ -259,38 +250,39 @@ table_column_is_in_pk(Table *table, uint32_t column) > return false; > } > > -/* > +/** > * Remove the memory data structures associated with the given > - * Table. No changes are made to disk by this routine. > + * Table. > * > - * This routine just deletes the data structure. It does not unlink > - * the table data structure from the hash table. But it does destroy > - * memory structures of the indices and foreign keys associated with > - * the table. > - * > - * The db parameter is optional. It is needed if the Table object > - * contains lookaside memory. (Table objects in the schema do not use > - * lookaside memory, but some ephemeral Table objects do.) Or the > - * db parameter can be used with db->pnBytesFreed to measure the memory > - * used by the Table object. > + * @param db Database handler. > + * @param tab Table to be deleted. > */ > -static void SQLITE_NOINLINE > -deleteTable(sqlite3 * db, Table * pTable) > +static void > +table_delete(struct sqlite3 *db, struct Table *tab) > { > - Index *pIndex, *pNext; > - > + if (tab->space->def != NULL) > + goto skip_index_delete; > /* Delete all indices associated with this table. */ > - for (pIndex = pTable->pIndex; pIndex; pIndex = pNext) { > - pNext = pIndex->pNext; > - freeIndex(db, pIndex); > - } > - assert(pTable->def != NULL); > - /* Do not delete pTable->def allocated on region. */ > - if (!pTable->def->opts.is_temporary) > - space_def_delete(pTable->def); > + for (uint32_t i = 0; i < tab->space->index_count; ++i) { > + /* > + * These indexes are just wrapper for > + * index_def's, so it makes no sense to call > + * index_delete(). > + */ > + struct index *idx = tab->space->index[i]; > + free(idx->def); > + free(idx); > + } > + free(tab->space); > + free(tab->space->index); 6. Use after free (tab->space is freed here). > +skip_index_delete: > + assert(tab->def != NULL); > + /* Do not delete table->def allocated on region. */ > + if (!tab->def->opts.is_temporary) > + space_def_delete(tab->def); > else > - sql_expr_list_delete(db, pTable->def->opts.checks); > - sqlite3DbFree(db, pTable); > + sql_expr_list_delete(db, tab->def->opts.checks); > + sqlite3DbFree(db, tab); > } > > void > @@ -368,16 +360,12 @@ sqlite3CheckIdentifierName(Parse *pParse, char *zName) > return SQLITE_OK; > } > > -/* > - * Return the PRIMARY KEY index of a table > - */ > -Index * > -sqlite3PrimaryKeyIndex(Table * pTab) > +struct index * > +sql_table_primary_key(const struct Table *tab) > { > - Index *p; > - for (p = pTab->pIndex; p != NULL && !sql_index_is_primary(p); > - p = p->pNext); > - return p; > + if (tab->space->index_count == 0 || tab->space->index[0]->def->iid != 0) > + return NULL; > + return tab->space->index[0]; 7. If you had index_map, you could do it like this: if (tab->space-index_count == 0) return NULL; return tab->space->index_map[0]; No checking for index[0]->iid == 0, it looks very strange. Likewise a primary index could have id != 0. You can allocate index_map in the same memory block as index array. > } > > /** > @@ -2431,84 +2408,6 @@ sql_drop_foreign_key(struct Parse *parse_context, struct SrcList *table, > vdbe_emit_fkey_drop(parse_context, constraint_name, child_id); > } > > -/* > - * Generate code that will erase and refill index *pIdx. This is > - * used to initialize a newly created index or to recompute the > - * content of an index in response to a REINDEX command. > - */ > -static void > -sqlite3RefillIndex(Parse * pParse, Index * pIndex) 8. Reindex still has a plenty of mentions over the code, including the parser and commented tests. What are you going to do with that? I propose to remove it from all the places. > @@ -2558,16 +2457,24 @@ getNewIid(Parse * pParse, int iSpaceId, int iCursor) > +table_add_index(struct Table *tab, struct index *index) > +{ > + uint32_t idx_count = tab->space->index_count; > + size_t indexes_sz = sizeof(struct index *) * (idx_count + 1); > + struct index **idx = (struct index **) realloc(tab->space->index, > + indexes_sz); > + if (idx == NULL) { > + diag_set(OutOfMemory, indexes_sz, "malloc", "idx"); > + return; > + } > + tab->space->index = idx; > + /* Make sure that PK always comes as first member. */ > + if (index->def->iid == 0 && idx_count != 0) { > + struct index *tmp = tab->space->index[0]; > + tab->space->index[0] = index; > + index = tmp; 9. Do not care about index array. You should only care about index_map - here the pk should be on the first place. So this whole 'if' can be replaced with a single tab->space->index_map[iid] = index. > } > + tab->space->index[tab->space->index_count++] = index; > } > > /** > @@ -2751,10 +2652,10 @@ sql_create_index(struct Parse *parse, struct Token *token, > * auto-index name will be generated. > */ > if (token != NULL) { > + assert(token->z != NULL); > name = sqlite3NameFromToken(db, token); > if (name == NULL) > goto exit_create_index; > - assert(token->z != NULL); 10. Noise diff hunk. > if (sqlite3LocateIndex(db, name, table->def->name) != NULL) { > if (!if_not_exist) { > sqlite3ErrorMsg(parse, > diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c > index 7780bf749..9220d34e1 100644 > --- a/src/box/sql/insert.c > +++ b/src/box/sql/insert.c> @@ -1353,12 +1352,6 @@ xferOptimization(Parse * pParse, /* Parser context */ > sqlite3VdbeJumpHere(v, addr1); > } > > - for (pDestIdx = pDest->pIndex; pDestIdx; pDestIdx = pDestIdx->pNext) { > - for (pSrcIdx = pSrc->pIndex; ALWAYS(pSrcIdx); > - pSrcIdx = pSrcIdx->pNext) { > - if (xferCompatibleIndex(pDestIdx, pSrcIdx)) > - break; > - } 11. Why are you sure that pDestIdx and pSrcIdx are xfercompatible now? And the indentation is broken. As I see, pDestIdx and pSrcIdx above are checked for xfer in a cycle, but it is not stopped once they are found. > assert(pSrcIdx); > struct space *src_space = > space_by_id(pSrc->def->id); > diff --git a/src/box/sql/where.c b/src/box/sql/where.c > index a4a1c456f..d8a2c1a79 100644 > --- a/src/box/sql/where.c > +++ b/src/box/sql/where.c > @@ -1741,12 +1740,11 @@ whereLoopInit(WhereLoop * p) > * Clear the WhereLoop.u union. Leave WhereLoop.pLTerm intact. > */ > static void > -whereLoopClearUnion(sqlite3 * db, WhereLoop * p) > +whereLoopClearUnion(WhereLoop * p) > { > - if ((p->wsFlags & WHERE_AUTO_INDEX) != 0 && > - (p->wsFlags & WHERE_AUTO_INDEX) != 0 && p->pIndex != 0) { > - sqlite3DbFree(db, p->pIndex); > - p->pIndex = 0; > + if ((p->wsFlags & WHERE_AUTO_INDEX) != 0) { 12. I put here assert(p->index_def->key_def == NULL) and it did not fire. Then I tried assert(false) and the result was the same. So this code is not tested at all. Can you fix it? > + free(p->index_def); > + p->index_def = NULL; > } > @@ -2999,13 +2975,15 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ > /* If there was an INDEXED BY clause, then only that one index is > * considered. > */ > - if (pSrc->pIBIndex) > + if (pSrc->pIBIndex != NULL) > + break; > + if (fake_index != NULL) > break; 13. This 'break' makes no sense. You already limited loop iterations with 1 for fake_index != NULL. Either break, or limit 'for'. > + > } > - if (fake_index.def != NULL) > - { > - free(fake_index.def->opts.stat->tuple_log_est); > - index_def_delete(fake_index.def); > + if (fake_index != NULL) { > + free(fake_index->opts.stat->tuple_log_est); 14. Just allocate fake_index->opts.stat like it works in ordinary index_defs and use index_def_delete only. > + index_def_delete(fake_index); > } > return rc; > } 15. Why index_is_unordered still exists? Why can you get key_def->opts.stat->is_unordered right from SQL index_def? > @@ -4651,10 +4628,10 @@ sqlite3WhereBegin(Parse * pParse, /* The parser context */ > * It is something w/ defined space_def > * and nothing else. Skip such loops. > */ > - if (idx_def == NULL && pIx == NULL) > + if (idx_def == NULL) > continue; > - bool is_primary = (pIx != NULL && sql_index_is_primary(pIx)) || > - (idx_def != NULL && (idx_def->iid == 0)); > + bool is_primary = (idx_def != NULL && > + idx_def->iid == 0); 16. idx_def == NULL is filtered out one line above. The same about other 'idx_def !=/== NULL' below. > if (is_primary > && (wctrlFlags & WHERE_OR_SUBCLAUSE) != 0) { > /* This is one term of an OR-optimization using Please, consider my fixes on the branch and here: commit cccbcaa444453aba3373ef53febb83389d2a113d Author: Vladislav Shpilevoy Date: Mon Aug 27 17:07:53 2018 -0300 Review fixes diff --git a/src/box/key_def.c b/src/box/key_def.c index 75eba79ec..e171e88fa 100644 --- a/src/box/key_def.c +++ b/src/box/key_def.c @@ -250,6 +250,8 @@ key_part_cmp(const struct key_part *parts1, uint32_t part_count1, if (part1->coll != part2->coll) return (uintptr_t) part1->coll < (uintptr_t) part2->coll ? -1 : 1; + if (part1->sort_order != part2->sort_order) + return part1->sort_order < part2->sort_order ? -1 : 1; if (key_part_is_nullable(part1) != key_part_is_nullable(part2)) return key_part_is_nullable(part1) < key_part_is_nullable(part2) ? -1 : 1; diff --git a/src/box/sql.c b/src/box/sql.c index 61c766540..f85daf9bd 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -31,10 +31,6 @@ #include #include "field_def.h" #include "sql.h" -/* - * Both Tarantool and SQLite codebases declare Index, hence the - * workaround below. - */ #include "sql/sqliteInt.h" #include "sql/tarantoolInt.h" #include "sql/vdbeInt.h" diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c index abed9d31b..33a3e1da8 100644 --- a/src/box/sql/analyze.c +++ b/src/box/sql/analyze.c @@ -918,68 +918,67 @@ analyzeOneTable(Parse * pParse, /* Parser context */ sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng); addrNextRow = sqlite3VdbeCurrentAddr(v); - if (part_count > 0) { - int endDistinctTest = sqlite3VdbeMakeLabel(v); - int *aGotoChng; /* Array of jump instruction addresses */ - aGotoChng = - sqlite3DbMallocRawNN(db, sizeof(int) * part_count); - if (aGotoChng == 0) - continue; - + int endDistinctTest = sqlite3VdbeMakeLabel(v); + /* Array of jump instruction addresses. */ + int *aGotoChng = + sqlite3DbMallocRawNN(db, sizeof(int) * part_count); + if (aGotoChng == NULL) + continue; + /* + * next_row: + * regChng = 0 + * if( idx(0) != regPrev(0) ) goto chng_addr_0 + * regChng = 1 + * if( idx(1) != regPrev(1) ) goto chng_addr_1 + * ... + * regChng = N + * goto endDistinctTest + */ + sqlite3VdbeAddOp0(v, OP_Goto); + addrNextRow = sqlite3VdbeCurrentAddr(v); + if (part_count == 1 && idx->def->opts.is_unique) { /* - * next_row: - * regChng = 0 - * if( idx(0) != regPrev(0) ) goto chng_addr_0 - * regChng = 1 - * if( idx(1) != regPrev(1) ) goto chng_addr_1 - * ... - * regChng = N - * goto endDistinctTest + * For a single-column UNIQUE index, once + * we have found a non-NULL row, we know + * that all the rest will be distinct, so + * skip subsequent distinctness tests. */ - sqlite3VdbeAddOp0(v, OP_Goto); - addrNextRow = sqlite3VdbeCurrentAddr(v); - if (part_count == 1 && idx->def->opts.is_unique) { - /* For a single-column UNIQUE index, once we have found a non-NULL - * row, we know that all the rest will be distinct, so skip - * subsequent distinctness tests. - */ - sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, - endDistinctTest); - VdbeCoverage(v); - } - struct key_part *part = idx->def->key_def->parts; - for (i = 0; i < part_count; ++i, ++part) { - struct coll *coll = part->coll; - sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); - sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, - part->fieldno, regTemp); - aGotoChng[i] = - sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, - regPrev + i, (char *)coll, - P4_COLLSEQ); - sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); - VdbeCoverage(v); - } - sqlite3VdbeAddOp2(v, OP_Integer, part_count, regChng); - sqlite3VdbeGoto(v, endDistinctTest); + sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, + endDistinctTest); + VdbeCoverage(v); + } + struct key_part *part = idx->def->key_def->parts; + for (i = 0; i < part_count; ++i, ++part) { + struct coll *coll = part->coll; + sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, part->fieldno, + regTemp); + aGotoChng[i] = sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, + regPrev + i, + (char *)coll, + P4_COLLSEQ); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + VdbeCoverage(v); + } + sqlite3VdbeAddOp2(v, OP_Integer, part_count, regChng); + sqlite3VdbeGoto(v, endDistinctTest); - /* - * chng_addr_0: - * regPrev(0) = idx(0) - * chng_addr_1: - * regPrev(1) = idx(1) - * ... - */ - sqlite3VdbeJumpHere(v, addrNextRow - 1); - part = idx->def->key_def->parts; - for (i = 0; i < part_count; ++i, ++part) { - sqlite3VdbeJumpHere(v, aGotoChng[i]); - sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, - part->fieldno, regPrev + i); - } - sqlite3VdbeResolveLabel(v, endDistinctTest); - sqlite3DbFree(db, aGotoChng); + /* + * chng_addr_0: + * regPrev(0) = idx(0) + * chng_addr_1: + * regPrev(1) = idx(1) + * ... + */ + sqlite3VdbeJumpHere(v, addrNextRow - 1); + part = idx->def->key_def->parts; + for (i = 0; i < part_count; ++i, ++part) { + sqlite3VdbeJumpHere(v, aGotoChng[i]); + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, part->fieldno, + regPrev + i); } + sqlite3VdbeResolveLabel(v, endDistinctTest); + sqlite3DbFree(db, aGotoChng); /* * chng_addr_N: @@ -989,14 +988,14 @@ analyzeOneTable(Parse * pParse, /* Parser context */ * if !eof(csr) goto next_row; */ assert(regKey == (regStat4 + 2)); - struct index *pPk = sql_table_primary_key(pTab); - int pk_part_count = pPk->def->key_def->part_count; + struct index *pk = sql_table_primary_key(pTab); + int pk_part_count = pk->def->key_def->part_count; /* Allocate memory for array. */ pParse->nMem = MAX(pParse->nMem, regPrev + part_count + pk_part_count); int regKeyStat = regPrev + part_count; for (i = 0; i < pk_part_count; i++) { - uint32_t k = pPk->def->key_def->parts[i].fieldno; + uint32_t k = pk->def->key_def->parts[i].fieldno; assert(k < pTab->def->field_count); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKeyStat + i); diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 79dc46592..534afc154 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -273,8 +273,8 @@ table_delete(struct sqlite3 *db, struct Table *tab) free(idx->def); free(idx); } - free(tab->space); free(tab->space->index); + free(tab->space); skip_index_delete: assert(tab->def != NULL); /* Do not delete table->def allocated on region. */ @@ -1214,8 +1214,8 @@ vdbe_emit_create_index(struct Parse *parse, struct space_def *def, * @param idx_name Name of index to be created. * @param space_id Space id (or register containing it) * which index belongs to. - * @param iIndexId Id of index (or register containing it) - * to be created. + * @param iid Id of index (or register containing it) to be + * created. * @param sql_stmt String containing 'CREATE INDEX ...' statement. * NULL for UNIQUE and PK constraints. */ @@ -1229,7 +1229,7 @@ vdbe_emit_index_schema_record(struct Parse *parse, const char *idx_name, sqlite3VdbeAddOp4(v, OP_String8, 0, entry_reg, 0, sqlite3DbStrDup(parse->db, idx_name), P4_DYNAMIC); - if (parse->pNewTable) { + if (parse->pNewTable != NULL) { /* * A new table is being created, hence space_id * is a register, but index id is literal. @@ -1327,11 +1327,12 @@ parseTableSchemaRecord(Parse * pParse, int iSpaceId, char *zStmt) sqlite3VdbeAddOp2(v, OP_Integer, 0, iTop + 2); sqlite3VdbeAddOp4(v, OP_String8, 0, iTop + 3, 0, zStmt, P4_DYNAMIC); - if (!p->def->opts.is_view) + if (!p->def->opts.is_view) { for (uint32_t i = 1; i < p->space->index_count; ++i) { const char *idx_name = p->space->index[i]->def->name; vdbe_emit_index_schema_record(pParse, idx_name, iSpaceId, i, NULL); + } } sqlite3VdbeAddParseSchema2Op(v, iTop, pParse->nMem - iTop + 1); @@ -2464,7 +2465,7 @@ table_add_index(struct Table *tab, struct index *index) struct index **idx = (struct index **) realloc(tab->space->index, indexes_sz); if (idx == NULL) { - diag_set(OutOfMemory, indexes_sz, "malloc", "idx"); + diag_set(OutOfMemory, indexes_sz, "realloc", "idx"); return; } tab->space->index = idx; @@ -3010,7 +3011,7 @@ sql_drop_index(struct Parse *parse_context, struct SrcList *index_name_list, * data-dictionaries will be completely merged. */ struct Table *tab = sqlite3HashFind(&db->pSchema->tblHash, table_name); - sqlite3VdbeAddOp3(v, OP_DropIndex, index->def->iid, 0, 0); + sqlite3VdbeAddOp1(v, OP_DropIndex, index->def->iid); sqlite3VdbeAppendP4(v, tab->space, P4_SPACEPTR); exit_drop_index: diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 9220d34e1..ce704c0a2 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -1113,22 +1113,9 @@ sql_index_is_xfer_compatible(const struct index_def *dest, { assert(dest != NULL && src != NULL); assert(dest->space_id != src->space_id); - uint32_t dest_idx_part_count = dest->key_def->part_count; - uint32_t src_idx_part_count = src->key_def->part_count; - if (dest_idx_part_count != src_idx_part_count) - return false; - struct key_part *src_part = src->key_def->parts; - struct key_part *dest_part = dest->key_def->parts; - for (uint32_t i = 0; i < src_idx_part_count; - ++i, ++src_part, ++dest_part) { - if (src_part->fieldno != dest_part->fieldno) - return false; - if (src_part->sort_order != dest_part->sort_order) - return false; - if (src_part->coll != dest_part->coll) - return false; - } - return true; + return key_part_cmp(src->key_def->parts, src->key_def->part_count, + dest->key_def->parts, + dest->key_def->part_count) == 0; } /* diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 19a5e7dd9..2bc6a98f6 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -3083,7 +3083,6 @@ struct Walker { SrcList *pSrcList; /* FROM clause */ struct SrcCount *pSrcCount; /* Counting column references */ int *aiCol; /* array of column indexes */ - struct IdxCover *pIdxCover; /* Check for index coverage */ /** Space definition. */ struct space_def *space_def; } u; @@ -3682,7 +3681,6 @@ int sqlite3ExprCodeExprList(Parse *, ExprList *, int, int, u8); #define SQLITE_ECEL_OMITREF 0x08 /* Omit if ExprList.u.x.iOrderByCol */ void sqlite3ExprIfTrue(Parse *, Expr *, int, int); void sqlite3ExprIfFalse(Parse *, Expr *, int, int); -void sqlite3ExprIfFalseDup(Parse *, Expr *, int, int); #define LOCATE_VIEW 0x01 #define LOCATE_NOERR 0x02 Table *sqlite3LocateTable(Parse *, u32 flags, const char *); diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h index 6ee83a5de..3ba01198d 100644 --- a/src/box/sql/vdbe.h +++ b/src/box/sql/vdbe.h @@ -229,10 +229,10 @@ void sqlite3VdbeAppendP4(Vdbe *, void *pP4, int p4type); * Set the P4 on the most recently added opcode to the key_def for the * index given. * @param Parse context, for error reporting. - * @param idx_def Definition of index to get key_def from. + * @param key_def Definition of a key to set. */ void -sql_vdbe_set_p4_key_def(struct Parse *parse, struct index_def *idx_def); +sql_vdbe_set_p4_key_def(struct Parse *parse, struct key_def *key_def); VdbeOp *sqlite3VdbeGetOp(Vdbe *, int); int sqlite3VdbeMakeLabel(Vdbe *); diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 12c2edffe..dda030234 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -1055,16 +1055,16 @@ sqlite3VdbeAppendP4(Vdbe * p, void *pP4, int n) } void -sql_vdbe_set_p4_key_def(struct Parse *parse, struct index_def *idx_def) +sql_vdbe_set_p4_key_def(struct Parse *parse, struct key_def *key_def) { struct Vdbe *v = parse->pVdbe; assert(v != NULL); - assert(idx_def != NULL); - struct key_def *def = key_def_dup(idx_def->key_def); - if (def == NULL) + assert(key_def != NULL); + key_def = key_def_dup(key_def); + if (key_def == NULL) sqlite3OomFault(parse->db); else - sqlite3VdbeAppendP4(v, def, P4_KEYDEF); + sqlite3VdbeAppendP4(v, key_def, P4_KEYDEF); } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS diff --git a/src/box/sql/where.c b/src/box/sql/where.c index d8a2c1a79..1b9ba436c 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -617,19 +617,18 @@ isDistinctRedundant(Parse * pParse, /* Parsing context */ * contain a "col=X" term are subject to a NOT NULL constraint. */ for (uint32_t j = 0; j < pTab->space->index_count; ++j) { - struct index *idx = pTab->space->index[j]; - if (!idx->def->opts.is_unique) + struct index_def *def = pTab->space->index[j]->def; + if (!def->opts.is_unique) continue; - uint32_t col_count = idx->def->key_def->part_count; + uint32_t col_count = def->key_def->part_count; uint32_t i; for (i = 0; i < col_count; i++) { - if (0 == - sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask) 0, - WO_EQ, idx->def)) { - if (findIndexCol - (pParse, pDistinct, iBase, idx->def, i) < 0) + if (sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask) 0, + WO_EQ, def) == 0) { + if (findIndexCol(pParse, pDistinct, iBase, def, + i) < 0) break; - uint32_t x = idx->def->key_def->parts[i].fieldno; + uint32_t x = def->key_def->parts[i].fieldno; if (pTab->def->fields[x].is_nullable) break; } @@ -638,7 +637,7 @@ isDistinctRedundant(Parse * pParse, /* Parsing context */ * This index implies that the DISTINCT * qualifier is redundant. */ - if (i == idx->def->key_def->part_count) + if (i == col_count) return 1; } @@ -858,7 +857,7 @@ constructAutomaticIndex(Parse * pParse, /* The parsing context */ assert(pLevel->iIdxCur >= 0); pLevel->iIdxCur = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol + 1); - sql_vdbe_set_p4_key_def(pParse, pIdx); + sql_vdbe_set_p4_key_def(pParse, pIdx->key_def); VdbeComment((v, "for %s", pTable->def->name)); /* Fill the automatic index with content */ @@ -2827,6 +2826,7 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ memset(&fake_index, 0, sizeof(fake_index)); struct key_def *key_def = key_def_new(1); if (key_def == NULL) { +tnt_error: pWInfo->pParse->nErr++; pWInfo->pParse->rc = SQL_TARANTOOL_ERROR; return SQL_TARANTOOL_ERROR; @@ -2843,18 +2843,18 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ sizeof("fake_autoindex") - 1, TREE, &opts, key_def, NULL); key_def_delete(key_def); - if (fake_index == NULL) { - pWInfo->pParse->nErr++; - pWInfo->pParse->rc = SQL_TARANTOOL_ERROR; - return SQL_TARANTOOL_ERROR; - } + if (fake_index == NULL) + goto tnt_error; /* Special marker for non-existent index. */ fake_index->iid = UINT32_MAX; + int size = sizeof(struct index_stat) + sizeof(log_est_t) * 2; - struct index_stat *stat = - (struct index_stat *) malloc(sizeof(struct index_stat)); - stat->tuple_log_est = - (log_est_t *) malloc(sizeof(log_est_t) * 2); + struct index_stat *stat = (struct index_stat *) malloc(size); + if (stat == NULL) { + diag_set(OutOfMemory, size, "malloc", "stat"); + goto tnt_error; + } + stat->tuple_log_est = (log_est_t *) ((char *) (stat + 1)); stat->tuple_log_est[0] = sql_space_tuple_log_count(pTab); stat->tuple_log_est[1] = 0; fake_index->opts.stat = stat; @@ -2917,7 +2917,12 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ } } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ - uint32_t idx_count = fake_index == NULL ? pTab->space->index_count : 1; + /* + * If there was an INDEXED BY clause, then only that one + * index is considered. + */ + uint32_t idx_count = fake_index == NULL || pSrc->pIBIndex != NULL ? + pTab->space->index_count : 1; for (uint32_t i = 0; i < idx_count; iSortIdx++, i++) { if (i > 0) probe = pTab->space->index[i]->def; @@ -2971,20 +2976,9 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ sqlite3Stat4ProbeFree(pBuilder->pRec); pBuilder->nRecValid = 0; pBuilder->pRec = 0; - - /* If there was an INDEXED BY clause, then only that one index is - * considered. - */ - if (pSrc->pIBIndex != NULL) - break; - if (fake_index != NULL) - break; - } - if (fake_index != NULL) { - free(fake_index->opts.stat->tuple_log_est); + if (fake_index != NULL) index_def_delete(fake_index); - } return rc; } @@ -3209,7 +3203,7 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ WhereLoop *pLoop = 0; /* Current WhereLoop being processed. */ WhereTerm *pTerm; /* A single term of the WHERE clause */ Expr *pOBExpr; /* An expression from the ORDER BY clause */ - struct index_def *pIndex; + struct index_def *idx_def; sqlite3 *db = pWInfo->pParse->db; /* Database connection */ Bitmask obSat = 0; /* Mask of ORDER BY terms satisfied so far */ Bitmask obDone; /* Mask of all ORDER BY terms */ @@ -3313,14 +3307,14 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ if ((pLoop->wsFlags & WHERE_ONEROW) == 0) { if (pLoop->wsFlags & WHERE_IPK) { - pIndex = NULL; + idx_def = NULL; nColumn = 1; - } else if ((pIndex = pLoop->index_def) == NULL || - index_is_unordered(pIndex)) { + } else if ((idx_def = pLoop->index_def) == NULL || + index_is_unordered(idx_def)) { return 0; } else { - nColumn = pIndex->key_def->part_count; - isOrderDistinct = pIndex->opts.is_unique; + nColumn = idx_def->key_def->part_count; + isOrderDistinct = idx_def->opts.is_unique; } /* Loop through all columns of the index and deal with the ones @@ -3380,8 +3374,8 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ /* Get the column number in the table (iColumn) and sort order * (revIdx) for the j-th column of the index. */ - if (pIndex != NULL) { - struct key_def *def = pIndex->key_def; + if (idx_def != NULL) { + struct key_def *def = idx_def->key_def; iColumn = def->parts[j].fieldno; revIdx = def->parts[j].sort_order; } else { @@ -3393,9 +3387,9 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ * WhereLoop is not well-ordered */ if (isOrderDistinct && iColumn >= 0 && - j >= pLoop->nEq && pIndex != NULL) { + j >= pLoop->nEq && idx_def != NULL) { struct space *space = - space_by_id(pIndex->space_id); + space_by_id(idx_def->space_id); assert(space != NULL); if (space->def->fields[iColumn].is_nullable) isOrderDistinct = 0; @@ -3432,7 +3426,7 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ pOrderBy->a[i].pExpr, &is_found, &id); struct coll *idx_coll = - pIndex->key_def->parts[j].coll; + idx_def->key_def->parts[j].coll; if (is_found && coll != idx_coll) continue; @@ -4630,9 +4624,7 @@ sqlite3WhereBegin(Parse * pParse, /* The parser context */ */ if (idx_def == NULL) continue; - bool is_primary = (idx_def != NULL && - idx_def->iid == 0); - if (is_primary + if (idx_def->iid == 0 && (wctrlFlags & WHERE_OR_SUBCLAUSE) != 0) { /* This is one term of an OR-optimization using * the PRIMARY KEY. No need for a separate index @@ -4640,8 +4632,7 @@ sqlite3WhereBegin(Parse * pParse, /* The parser context */ iIndexCur = pLevel->iTabCur; op = 0; } else if (pWInfo->eOnePass != ONEPASS_OFF) { - if (idx_def != NULL && - pTabItem->pTab->space->index_count != 0) { + if (pTabItem->pTab->space->index_count != 0) { uint32_t iid = 0; struct index *pJ = pTabItem->pTab->space->index[iid]; iIndexCur = iAuxArg; @@ -4675,19 +4666,10 @@ sqlite3WhereBegin(Parse * pParse, /* The parser context */ pLevel->iIdxCur = iIndexCur; assert(iIndexCur >= 0); if (op) { - if (idx_def != NULL) { - uint32_t space_id = - idx_def->space_id; - struct space *space = - space_by_id(space_id); - vdbe_emit_open_cursor(pParse, iIndexCur, - idx_def->iid, - space); - } else { - vdbe_emit_open_cursor(pParse, iIndexCur, - idx_def->iid, - space); - } + uint32_t space_id = idx_def->space_id; + struct space *space = space_by_id(space_id); + vdbe_emit_open_cursor(pParse, iIndexCur, + idx_def->iid, space); if ((pLoop->wsFlags & WHERE_CONSTRAINT) != 0 && (pLoop-> wsFlags & (WHERE_COLUMN_RANGE | @@ -4696,8 +4678,7 @@ sqlite3WhereBegin(Parse * pParse, /* The parser context */ wctrlFlags & WHERE_ORDERBY_MIN) == 0) { sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */ } - if (idx_def != NULL) - VdbeComment((v, "%s", idx_def->name)); + VdbeComment((v, "%s", idx_def->name)); #ifdef SQLITE_ENABLE_COLUMN_USED_MASK { u64 colUsed = 0; diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index 628c6f9ad..5d8663a92 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -219,7 +219,7 @@ sqlite3WhereExplainOneScan(Parse * pParse, /* Parse context */ assert(!(flags & WHERE_AUTO_INDEX) || (flags & WHERE_IDX_ONLY)); - if (idx_def != NULL && idx_def->iid == 0) { + if (idx_def->iid == 0) { if (isSearch) { zFmt = "PRIMARY KEY"; } @@ -234,10 +234,7 @@ sqlite3WhereExplainOneScan(Parse * pParse, /* Parse context */ } if (zFmt) { sqlite3StrAccumAppend(&str, " USING ", 7); - if (idx_def != NULL) - sqlite3XPrintf(&str, zFmt, idx_def->name); - else - sqlite3XPrintf(&str, zFmt, "EPHEMERAL INDEX"); + sqlite3XPrintf(&str, zFmt, idx_def->name); explainIndexRange(&str, pLoop); } } else if ((flags & WHERE_IPK) != 0 @@ -477,7 +474,7 @@ codeEqualityTerm(Parse * pParse, /* The parsing context */ int nEq = 0; int *aiMap = 0; - if (pLoop->index_def != 0 && + if (pLoop->index_def != NULL && pLoop->index_def->key_def->parts[iEq].sort_order) { testcase(iEq == 0); testcase(bRev); @@ -1187,7 +1184,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t int limit = pRangeStart == NULL ? nEq : nEq + 1; for (int i = 0; i < limit; i++) { if (idx_def->key_def->parts[i].fieldno == - idx_pk->key_def->parts[0].fieldno) { + idx_pk->key_def->parts[0].fieldno) { /* Here: we know for sure that table has INTEGER PRIMARY KEY, single column, and Index we're trying to use for scan contains this column. */ @@ -1295,11 +1292,9 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t if (omitTable) { /* pIdx is a covering index. No need to access the main table. */ } else if (iCur != iIdxCur) { - struct index *pPk = space->index_map[0]; - int pk_part_count = pPk->def->key_def->part_count; int iKeyReg = sqlite3GetTempRange(pParse, pk_part_count); - for (j = 0; j < pk_part_count; j++) { - k = pPk->def->key_def->parts[j].fieldno; + for (j = 0; j < (int) pk_part_count; j++) { + k = idx_pk->key_def->parts[j].fieldno; sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iKeyReg + j); } @@ -1344,7 +1339,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t */ WhereClause *pOrWc; /* The OR-clause broken out into subterms */ SrcList *pOrTab; /* Shortened table list or OR-clause generation */ - struct index_def *pCov = 0; /* Potential covering index (or NULL) */ + struct index_def *cov = NULL; /* Potential covering index (or NULL) */ int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */ int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ @@ -1357,6 +1352,9 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t u16 wctrlFlags; /* Flags for sub-WHERE clause */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ Table *pTab = pTabItem->pTab; + struct key_def *pk_key_def = + sql_table_primary_key(pTab)->def->key_def; + uint32_t pk_part_count = pk_key_def->part_count; pTerm = pLoop->aLTerm[0]; assert(pTerm != 0); @@ -1403,12 +1401,10 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t * called on an uninitialized cursor. */ if ((pWInfo->wctrlFlags & WHERE_DUPLICATES_OK) == 0) { - struct index *pPk = sql_table_primary_key(pTab); - int pk_part_count = pPk->def->key_def->part_count; regRowset = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenTEphemeral, regRowset, pk_part_count); - sql_vdbe_set_p4_key_def(pParse, pPk->def); + sql_vdbe_set_p4_key_def(pParse, pk_key_def); regPk = ++pParse->nMem; } iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); @@ -1507,19 +1503,15 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t int r; int iSet = ((ii == pOrWc->nTerm - 1) ? -1 : ii); - struct index *pPk = - sql_table_primary_key(pTab); - struct key_def *def = - pPk->def->key_def; /* Read the PK into an array of temp registers. */ r = sqlite3GetTempRange(pParse, - def->part_count); + pk_part_count); for (uint32_t iPk = 0; - iPk < def->part_count; + iPk < pk_part_count; iPk++) { uint32_t fieldno = - def->parts[iPk]. + pk_key_def->parts[iPk]. fieldno; sqlite3ExprCodeGetColumnToReg (pParse, @@ -1546,20 +1538,20 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t (v, OP_Found, regRowset, 0, r, - def->part_count); + pk_part_count); VdbeCoverage(v); } if (iSet >= 0) { sqlite3VdbeAddOp3 (v, OP_MakeRecord, - r, def->part_count, regPk); + r, pk_part_count, regPk); sqlite3VdbeAddOp2 (v, OP_IdxInsert, regRowset, regPk); } /* Release the array of temp registers */ - sqlite3ReleaseTempRange(pParse, r, def->part_count); + sqlite3ReleaseTempRange(pParse, r, pk_part_count); } /* Invoke the main loop body as a subroutine */ @@ -1588,21 +1580,21 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t * If the call to sqlite3WhereBegin() above resulted in a scan that * uses an index, and this is either the first OR-connected term * processed or the index is the same as that used by all previous - * terms, set pCov to the candidate covering index. Otherwise, set - * pCov to NULL to indicate that no candidate covering index will + * terms, set cov to the candidate covering index. Otherwise, set + * cov to NULL to indicate that no candidate covering index will * be available. */ pSubLoop = pSubWInfo->a[0].pWLoop; assert((pSubLoop->wsFlags & WHERE_AUTO_INDEX) == 0); if ((pSubLoop->wsFlags & WHERE_INDEXED) != 0 - && (ii == 0 || (pCov != NULL && - pSubLoop->index_def->iid == pCov->iid)) + && (ii == 0 || (cov != NULL && + pSubLoop->index_def->iid == cov->iid)) && (pSubLoop->index_def->iid != 0)) { assert(pSubWInfo->a[0]. iIdxCur == iCovCur); - pCov = pSubLoop->index_def; + cov = pSubLoop->index_def; } else { - pCov = 0; + cov = 0; } /* Finish the loop through table entries that match term pOrTerm. */ @@ -1610,8 +1602,8 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t } } } - pLevel->u.pCovidx = pCov; - if (pCov) + pLevel->u.pCovidx = cov; + if (cov) pLevel->iIdxCur = iCovCur; if (pAndExpr) { pAndExpr->pLeft = 0;