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 244B626290 for ; Thu, 21 Jun 2018 08:57:09 -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 QoM8UsCJjK87 for ; Thu, 21 Jun 2018 08:57:09 -0400 (EDT) Received: from smtp34.i.mail.ru (smtp34.i.mail.ru [94.100.177.94]) (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 A73CF26140 for ; Thu, 21 Jun 2018 08:57:07 -0400 (EDT) From: Ivan Koptelov Subject: [tarantool-patches] Re: [PATCH v4] sql: add index_def to struct Index References: <9A0A687D-2E0B-4AB9-B223-1A1287817824@tarantool.org> Message-ID: <8900ae2a-59e8-d69a-7f5d-95436b23214a@tarantool.org> Date: Thu, 21 Jun 2018 15:57:05 +0300 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset="utf-8"; format="flowed" Content-Transfer-Encoding: 8bit Content-Language: en-GB 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: Kirill Shcherbatov Thank you for the review. Sorry for that problem with smashed mail. I fixed my mail client, now everything should be ok. See my patch at the end of the mail. > Thank you for the patch. Glad to see indexes so much simplified. > Would you kindly use post program next time? The message was smashed and this made me cry a bit ;) > Please, fix following 16 comments (2 memory problems and 14 minor codestyle fixes): > >>> Branch:https://github.com/tarantool/tarantool/tree/sb/gh-3369-use-index-def-in-select-and-where >>> Issue:https://github.com/tarantool/tarantool/issues/3369 >>> >>> src/box/sql.c | 54 +++--- >>> src/box/sql/analyze.c | 40 ++-- >>> src/box/sql/build.c | 488 +++++++++++++++++++++++------------------------- >>> src/box/sql/delete.c | 17 +- >>> src/box/sql/expr.c | 60 +++--- >>> src/box/sql/fkey.c | 47 ++--- >>> src/box/sql/insert.c | 148 ++++++--------- >>> src/box/sql/pragma.c | 32 ++-- >>> src/box/sql/select.c | 2 +- >>> src/box/sql/sqliteInt.h | 63 +------ >>> src/box/sql/trigger.c | 2 - >>> src/box/sql/update.c | 10 +- >>> src/box/sql/vdbeaux.c | 2 +- >>> src/box/sql/vdbemem.c | 4 +- >>> src/box/sql/where.c | 168 ++++++++--------- >>> src/box/sql/wherecode.c | 54 +++--- >>> src/box/sql/whereexpr.c | 15 -- >>> 17 files changed, 532 insertions(+), 674 deletions(-) >>> >>> diff --git a/src/box/sql.c b/src/box/sql.c >>> index 7379cb418..213f8e453 100644 >>> --- a/src/box/sql.c >>> +++ b/src/box/sql.c >>> @@ -1442,8 +1442,8 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf) >>> >>> /* If table's PK is single column which is INTEGER, then >>> * treat it as strict type, not affinity. */ >>> - if (pk_idx && pk_idx->nColumn == 1) { >>> - int pk = pk_idx->aiColumn[0]; >>> + if (pk_idx != NULL && pk_idx->def->key_def->part_count == 1) { >>> + int pk = pk_idx->def->key_def->parts[0].fieldno; >>> if (def->fields[pk].type == FIELD_TYPE_INTEGER) >>> pk_forced_int = pk; >>> } >>> @@ -1552,20 +1552,19 @@ tarantoolSqlite3MakeTableOpts(Table *pTable, const char *zSql, char *buf) >>> */ >>> int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf) >>> { >>> - struct space_def *def = pIndex->pTable->def; >>> - assert(def != NULL); >>> + struct field_def *fields = pIndex->pTable->def->fields; >>> + struct key_def *key_def = pIndex->def->key_def; >>> const struct Enc *enc = get_enc(buf); >>> - struct SqliteIndex *primary_index; >>> - char *base = buf, *p; >>> - int pk_forced_int = -1; >>> - >>> - primary_index = sqlite3PrimaryKeyIndex(pIndex->pTable); >>> + char *base = buf; >>> + uint32_t pk_forced_int = UINT32_MAX; >>> + struct SqliteIndex *primary_index = >>> + sqlite3PrimaryKeyIndex(pIndex->pTable); >>> >>> /* If table's PK is single column which is INTEGER, then >>> * treat it as strict type, not affinity. */ >>> - if (primary_index->nColumn == 1) { >>> - int pk = primary_index->aiColumn[0]; >>> - if (def->fields[pk].type == FIELD_TYPE_INTEGER) >>> + if (primary_index->def->key_def->part_count == 1) { >>> + int pk = primary_index->def->key_def->parts[0].fieldno; >>> + if (fields[pk].type == FIELD_TYPE_INTEGER) >>> pk_forced_int = pk; >>> } >>> >>> @@ -1575,46 +1574,45 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf) >>> * primary key columns. Query planner depends on this particular >>> * data layout. >>> */ >>> - int i, n = pIndex->nColumn; >>> - >>> - p = enc->encode_array(base, n); >>> - for (i = 0; i < n; i++) { >>> - int col = pIndex->aiColumn[i]; >>> - assert(def->fields[col].is_nullable == >>> - action_is_nullable(def->fields[col].nullable_action)); >>> + struct key_part *part = key_def->parts; >>> + char *p = enc->encode_array(base, key_def->part_count); >>> + for (uint32_t i = 0; i < key_def->part_count; ++i, ++part) { >>> + uint32_t col = part->fieldno; >>> + assert(fields[col].is_nullable == >>> + action_is_nullable(fields[col].nullable_action)); >>> const char *t; >>> if (pk_forced_int == col) { >>> t = "integer"; >>> } else { >>> - enum affinity_type affinity = def->fields[col].affinity; >>> - t = convertSqliteAffinity(affinity, >>> - def->fields[col].is_nullable); >>> + t = convertSqliteAffinity(fields[col].affinity, >>> + fields[col].is_nullable); >>> } >>> /* do not decode default collation */ >>> - uint32_t cid = pIndex->coll_id_array[i]; >>> + uint32_t cid = part->coll_id; >>> p = enc->encode_map(p, cid == COLL_NONE ? 5 : 6); >>> p = enc->encode_str(p, "type", sizeof("type")-1); >>> p = enc->encode_str(p, t, strlen(t)); >>> p = enc->encode_str(p, "field", sizeof("field")-1); >>> p = enc->encode_uint(p, col); >>> if (cid != COLL_NONE) { >>> - p = enc->encode_str(p, "collation", sizeof("collation")-1); >>> + p = enc->encode_str(p, "collation", >>> + sizeof("collation") - 1); >>> p = enc->encode_uint(p, cid); >>> } >>> p = enc->encode_str(p, "is_nullable", 11); >>> - p = enc->encode_bool(p, def->fields[col].is_nullable); >>> + p = enc->encode_bool(p, fields[col].is_nullable); >>> p = enc->encode_str(p, "nullable_action", 15); >>> const char *action_str = >>> - on_conflict_action_strs[def->fields[col].nullable_action]; >>> + on_conflict_action_strs[fields[col].nullable_action]; >>> p = enc->encode_str(p, action_str, strlen(action_str)); >>> >>> p = enc->encode_str(p, "sort_order", 10); >>> - enum sort_order sort_order = pIndex->sort_order[i]; >>> + enum sort_order sort_order = part->sort_order; >>> assert(sort_order < sort_order_MAX); >>> const char *sort_order_str = sort_order_strs[sort_order]; >>> p = enc->encode_str(p, sort_order_str, strlen(sort_order_str)); >>> } >>> - return (int)(p - base); >>> + return p - base; >>> } >>> >>> /* >>> diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c >>> index afc824a1a..31de7ab05 100644 >>> --- a/src/box/sql/analyze.c >>> +++ b/src/box/sql/analyze.c >>> @@ -849,7 +849,6 @@ analyzeOneTable(Parse * pParse, /* Parser context */ >>> int addrRewind; /* Address of "OP_Rewind iIdxCur" */ >>> int addrNextRow; /* Address of "next_row:" */ >>> const char *zIdxName; /* Name of the index */ >>> - int nColTest; /* Number of columns to test for changes */ >>> >>> if (pOnlyIdx && pOnlyIdx != pIdx) >>> continue; >>> @@ -860,9 +859,9 @@ analyzeOneTable(Parse * pParse, /* Parser context */ >>> if (IsPrimaryKeyIndex(pIdx)) { >>> zIdxName = pTab->def->name; >>> } else { >>> - zIdxName = pIdx->zName; >>> + zIdxName = pIdx->def->name; >>> } >>> - nColTest = index_column_count(pIdx); >>> + int nColTest = pIdx->def->key_def->part_count; >>> >>> /* Populate the register containing the index name. */ >>> sqlite3VdbeLoadString(v, regIdxname, zIdxName); >>> @@ -917,7 +916,7 @@ analyzeOneTable(Parse * pParse, /* Parser context */ >>> sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, >>> space_ptr_reg); >>> sql_vdbe_set_p4_key_def(pParse, pIdx); >>> - VdbeComment((v, "%s", pIdx->zName)); >>> + VdbeComment((v, "%s", pIdx->def->name)); >>> >>> /* Invoke the stat_init() function. The arguments are: >>> * >>> @@ -969,7 +968,7 @@ analyzeOneTable(Parse * pParse, /* Parser context */ >>> */ >>> sqlite3VdbeAddOp0(v, OP_Goto); >>> addrNextRow = sqlite3VdbeCurrentAddr(v); >>> - if (nColTest == 1 && index_is_unique(pIdx)) { >>> + if (nColTest == 1 && pIdx->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. >>> @@ -978,13 +977,12 @@ analyzeOneTable(Parse * pParse, /* Parser context */ >>> endDistinctTest); >>> VdbeCoverage(v); >>> } >>> - for (i = 0; i < nColTest; i++) { >>> - uint32_t id; >>> - struct coll *coll = >>> - sql_index_collation(pIdx, i, &id); >>> + struct key_part *part = pIdx->def->key_def->parts; >>> + for (i = 0; i < nColTest; ++i, ++part) { >>> + struct coll *coll = part->coll; >>> sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); >>> sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, >>> - pIdx->aiColumn[i], regTemp); >>> + part->fieldno, regTemp); >>> aGotoChng[i] = >>> sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, >>> regPrev + i, (char *)coll, >>> @@ -1006,7 +1004,8 @@ analyzeOneTable(Parse * pParse, /* Parser context */ >>> for (i = 0; i < nColTest; i++) { >>> sqlite3VdbeJumpHere(v, aGotoChng[i]); >>> sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, >>> - pIdx->aiColumn[i], >>> + pIdx->def->key_def-> >>> + parts[i].fieldno, >>> regPrev + i); >>> } >>> sqlite3VdbeResolveLabel(v, endDistinctTest); >>> @@ -1022,15 +1021,14 @@ analyzeOneTable(Parse * pParse, /* Parser context */ >>> */ >>> assert(regKey == (regStat4 + 2)); >>> Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); >>> - int j, k, regKeyStat; >>> - int nPkColumn = (int)index_column_count(pPk); >>> - regKeyStat = sqlite3GetTempRange(pParse, nPkColumn); >>> - for (j = 0; j < nPkColumn; j++) { >>> - k = pPk->aiColumn[j]; >>> - assert(k >= 0 && k < (int)pTab->def->field_count); >>> - sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKeyStat + j); >>> - VdbeComment((v, "%s", >>> - pTab->def->fields[pPk->aiColumn[j]].name)); >>> + int nPkColumn = (int) pPk->def->key_def->part_count; >>> + int regKeyStat = sqlite3GetTempRange(pParse, nPkColumn); >>> + for (int j = 0; j < nPkColumn; ++j) { >>> + int k = pPk->def->key_def->parts[j].fieldno; >>> + assert(k >= 0 && k < (int) pTab->def->field_count); >>> + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, >>> + regKeyStat + j); >>> + VdbeComment((v, "%s", pTab->def->fields[k].name)); >>> } >>> sqlite3VdbeAddOp3(v, OP_MakeRecord, regKeyStat, >>> nPkColumn, regKey); >>> @@ -1150,7 +1148,7 @@ analyzeTable(Parse * pParse, Table * pTab, Index * pOnlyIdx) >>> iStatCur = pParse->nTab; >>> pParse->nTab += 3; >>> if (pOnlyIdx) { >>> - openStatTable(pParse, iStatCur, pOnlyIdx->zName, "idx"); >>> + openStatTable(pParse, iStatCur, pOnlyIdx->def->name, "idx"); >>> } else { >>> openStatTable(pParse, iStatCur, pTab->def->name, "tbl"); >>> } >>> diff --git a/src/box/sql/build.c b/src/box/sql/build.c >>> index 62d687b17..f18727c61 100644 >>> --- a/src/box/sql/build.c >>> +++ b/src/box/sql/build.c >>> @@ -253,6 +253,8 @@ freeIndex(sqlite3 * db, Index * p) >>> { >>> sql_expr_delete(db, p->pPartIdxWhere, false); >>> sql_expr_list_delete(db, p->aColExpr); >>> + if (p->def != NULL) >>> + index_def_delete(p->def); >>> sqlite3DbFree(db, p->zColAff); >>> sqlite3DbFree(db, p); >>> } >>> @@ -271,7 +273,8 @@ sqlite3UnlinkAndDeleteIndex(sqlite3 * db, Index * pIndex) >>> >>> struct session *user_session = current_session(); >>> >>> - pIndex = sqlite3HashInsert(&pIndex->pTable->idxHash, pIndex->zName, 0); >>> + pIndex = sqlite3HashInsert(&pIndex->pTable->idxHash, >>> + pIndex->def->name, 0); >>> if (ALWAYS(pIndex)) { >>> if (pIndex->pTable->pIndex == pIndex) { >>> pIndex->pTable->pIndex = pIndex->pNext; >>> @@ -388,7 +391,7 @@ deleteTable(sqlite3 * db, Table * pTable) >>> pNext = pIndex->pNext; >>> assert(pIndex->pSchema == pTable->pSchema); >>> if ((db == 0 || db->pnBytesFreed == 0)) { >>> - char *zName = pIndex->zName; >>> + char *zName = pIndex->def->name; >>> TESTONLY(Index * >>> pOld =) sqlite3HashInsert(&pTable->idxHash, >>> zName, 0); >>> @@ -1058,7 +1061,7 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken) >>> Table *p = pParse->pNewTable; >>> if (p == NULL) >>> return; >>> - int i = p->def->field_count - 1; >>> + uint32_t i = p->def->field_count - 1; >>> sqlite3 *db = pParse->db; >>> char *zColl = sqlite3NameFromToken(db, pToken); >>> if (!zColl) >>> @@ -1066,22 +1069,20 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken) >>> uint32_t *id = &p->def->fields[i].coll_id; >>> p->aCol[i].coll = sql_get_coll_seq(pParse, zColl, id); >>> if (p->aCol[i].coll != NULL) { >>> - Index *pIdx; >>> /* If the column is declared as " PRIMARY KEY COLLATE ", >>> * then an index may have been created on this column before the >>> * collation type was added. Correct this if it is the case. >>> */ >>> - for (pIdx = p->pIndex; pIdx; pIdx = pIdx->pNext) { >>> - assert(pIdx->nColumn == 1); >>> - if (pIdx->aiColumn[0] == i) { >>> - id = &pIdx->coll_id_array[0]; >>> - pIdx->coll_array[0] = >>> + for (struct Index *pIdx = p->pIndex; pIdx; pIdx = pIdx->pNext) { >>> + assert(pIdx->def->key_def->part_count == 1); >>> + if (pIdx->def->key_def->parts[0].fieldno == i) { >>> + pIdx->def->key_def->parts[0].coll_id = *id; >>> + pIdx->def->key_def->parts[0].coll = >>> sql_column_collation(p->def, i, id); >>> } >>> } >>> - } else { >>> - sqlite3DbFree(db, zColl); >>> } >>> + sqlite3DbFree(db, zColl); >>> } >>> >>> struct coll * >>> @@ -1111,66 +1112,6 @@ sql_column_collation(struct space_def *def, uint32_t column, uint32_t *coll_id) >>> return space->format->fields[column].coll; >>> } >>> >>> -struct key_def* >>> -sql_index_key_def(struct Index *idx) >>> -{ >>> - uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->tnum); >>> - uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum); >>> - struct space *space = space_by_id(space_id); >>> - assert(space != NULL); >>> - struct index *index = space_index(space, index_id); >>> - assert(index != NULL && index->def != NULL); >>> - return index->def->key_def; >>> -} >>> - >>> -struct coll * >>> -sql_index_collation(Index *idx, uint32_t column, uint32_t *coll_id) >>> -{ >>> - assert(idx != NULL); >>> - uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->pTable->tnum); >>> - struct space *space = space_by_id(space_id); >>> - >>> - assert(column < idx->nColumn); >>> - /* >>> - * If space is still under construction, or it is >>> - * an ephemeral space, then fetch collation from >>> - * SQL internal structure. >>> - */ >>> - if (space == NULL) { >>> - assert(column < idx->nColumn); >>> - *coll_id = idx->coll_id_array[column]; >>> - return idx->coll_array[column]; >>> - } >>> - >>> - struct key_def *key_def = sql_index_key_def(idx); >>> - assert(key_def != NULL && key_def->part_count >= column); >>> - *coll_id = key_def->parts[column].coll_id; >>> - return key_def->parts[column].coll; >>> -} >>> - >>> -enum sort_order >>> -sql_index_column_sort_order(Index *idx, uint32_t column) >>> -{ >>> - assert(idx != NULL); >>> - uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->pTable->tnum); >>> - struct space *space = space_by_id(space_id); >>> - >>> - assert(column < idx->nColumn); >>> - /* >>> - * If space is still under construction, or it is >>> - * an ephemeral space, then fetch collation from >>> - * SQL internal structure. >>> - */ >>> - if (space == NULL) { >>> - assert(column < idx->nColumn); >>> - return idx->sort_order[column]; >>> - } >>> - >>> - struct key_def *key_def = sql_index_key_def(idx); >>> - assert(key_def != NULL && key_def->part_count >= column); >>> - return key_def->parts[column].sort_order; >>> -} >>> - >>> /** >>> * Return true if space which corresponds to >>> * given table has view option. >>> @@ -1383,14 +1324,16 @@ createTableStmt(sqlite3 * db, Table * p) >>> return zStmt; >>> } >>> >>> -/* Return true if value x is found any of the first nCol entries of aiCol[] >>> - */ >>> static int >>> -hasColumn(const i16 * aiCol, int nCol, int x) >>> +hasColumn(const struct key_part *key_parts, int nCol, uint32_t fieldno) >>> { >>> - while (nCol-- > 0) >>> - if (x == *(aiCol++)) >>> + int i = 0; >>> + while (i < nCol) { >>> + if (fieldno == key_parts->fieldno) >>> return 1; >>> + key_parts++; >>> + i++; >>> + } >>> return 0; >>> } >>> >>> @@ -1410,13 +1353,12 @@ static void >>> convertToWithoutRowidTable(Parse * pParse, Table * pTab) >>> { >>> Index *pPk; >>> - int i, j; >>> sqlite3 *db = pParse->db; >>> >>> /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables) >>> */ >>> if (!db->init.imposterTable) { >>> - for (i = 0; i < (int)pTab->def->field_count; i++) { >>> + for (uint32_t i = 0; i < pTab->def->field_count; i++) { >>> if (pTab->aCol[i].is_primkey) { >>> pTab->def->fields[i].nullable_action >>> = ON_CONFLICT_ACTION_ABORT; >>> @@ -1454,14 +1396,28 @@ convertToWithoutRowidTable(Parse * pParse, Table * pTab) >>> * "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later >>> * code assumes the PRIMARY KEY contains no repeated columns. >>> */ >>> - for (i = j = 1; i < pPk->nColumn; i++) { >>> - if (hasColumn(pPk->aiColumn, j, pPk->aiColumn[i])) { >>> - pPk->nColumn--; >>> - } else { >>> - pPk->aiColumn[j++] = pPk->aiColumn[i]; >>> + >>> + struct key_part *parts = pPk->def->key_def->parts; >>> + uint32_t part_count = pPk->def->key_def->part_count; >>> + uint32_t new_part_count = part_count; >>> + >>> + for (uint32_t i = 1; i < part_count; i++) { >>> + if (hasColumn(parts, i, parts[i].fieldno)){ >>> + new_part_count--; >>> + bool is_found = false; >>> + for (uint32_t j = i + 1; j < part_count; j++){ >>> + if (!(hasColumn(parts, j, >>> + parts[j].fieldno))) { >>> + parts[i] = parts[j]; >>> + is_found = true; >>> + break; >>> + } >>> + } >>> + if (!(is_found)) >>> + break; >>> } >>> } >>> - pPk->nColumn = j; >>> + pPk->def->key_def->part_count = new_part_count; >>> } >>> assert(pPk != 0); >>> } >>> @@ -1543,7 +1499,7 @@ createIndex(Parse * pParse, Index * pIndex, int iSpaceId, int iIndexId, >>> } >>> sqlite3VdbeAddOp4(v, >>> OP_String8, 0, iFirstCol + 2, 0, >>> - sqlite3DbStrDup(pParse->db, pIndex->zName), >>> + sqlite3DbStrDup(pParse->db, pIndex->def->name), >>> P4_DYNAMIC); >>> sqlite3VdbeAddOp4(v, OP_String8, 0, iFirstCol + 3, 0, "tree", >>> P4_STATIC); >>> @@ -1580,7 +1536,7 @@ makeIndexSchemaRecord(Parse * pParse, >>> >>> sqlite3VdbeAddOp4(v, >>> OP_String8, 0, iFirstCol, 0, >>> - sqlite3DbStrDup(pParse->db, pIndex->zName), >>> + sqlite3DbStrDup(pParse->db, pIndex->def->name), >>> P4_DYNAMIC); >>> >>> if (pParse->pNewTable) { >>> @@ -2652,14 +2608,15 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage) >>> } else { >>> tnum = pIndex->tnum; >>> } >>> - struct key_def *def = key_def_dup(sql_index_key_def(pIndex)); >>> + struct key_def *def = key_def_dup(pIndex->def->key_def); >>> if (def == NULL) { >>> sqlite3OomFault(db); >>> return; >>> } >>> /* Open the sorter cursor if we are to use one. */ >>> iSorter = pParse->nTab++; >>> - sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nColumn, >>> + sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, >>> + pIndex->def->key_def->part_count, >>> (char *)def, P4_KEYDEF); > 1. Maybe a little better like this? > - pIndex->def->key_def->part_count, > - (char *)def, P4_KEYDEF); > + pIndex->def->key_def->part_count, (char *)def, > + P4_KEYDEF); Ok, fixed. >>> >>> /* Open the table. Loop through all rows of the table, inserting index >>> @@ -2692,7 +2649,7 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage) >>> sqlite3VdbeGoto(v, j2); >>> addr2 = sqlite3VdbeCurrentAddr(v); >>> sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, >>> - regRecord, pIndex->nColumn); >>> + regRecord, pIndex->def->key_def->part_count); > 2. Out of margin > - regRecord, pIndex->def->key_def->part_count); > + regRecord, > + pIndex->def->key_def->part_count); Fixed. >>> VdbeCoverage(v); >>> sqlite3UniqueConstraint(pParse, ON_CONFLICT_ACTION_ABORT, >>> pIndex); >>> @@ -2730,24 +2687,13 @@ sqlite3AllocateIndexObject(sqlite3 * db, /* Database connection */ >>> int nByte; /* Bytes of space for Index object + arrays */ >>> >>> nByte = ROUND8(sizeof(Index)) + /* Index structure */ >>> - ROUND8(sizeof(struct coll *) * nCol) + /* Index.coll_array */ >>> - ROUND8(sizeof(uint32_t) * nCol) + /* Index.coll_id_array*/ >>> - ROUND8(sizeof(LogEst) * (nCol + 1) + /* Index.aiRowLogEst */ >>> - sizeof(i16) * nCol + /* Index.aiColumn */ >>> - sizeof(enum sort_order) * nCol); /* Index.sort_order */ >>> + ROUND8(sizeof(LogEst) * (nCol + 1)); /* Index.aiRowLogEst */ >>> p = sqlite3DbMallocZero(db, nByte + nExtra); >>> if (p) { >>> char *pExtra = ((char *)p) + ROUND8(sizeof(Index)); >>> - p->coll_array = (struct coll **)pExtra; >>> - pExtra += ROUND8(sizeof(struct coll **) * nCol); >>> - p->coll_id_array = (uint32_t *) pExtra; >>> - pExtra += ROUND8(sizeof(uint32_t) * nCol); >>> p->aiRowLogEst = (LogEst *) pExtra; >>> pExtra += sizeof(LogEst) * (nCol + 1); >>> - p->aiColumn = (i16 *) pExtra; >>> pExtra += sizeof(i16) * nCol; >>> - p->sort_order = (enum sort_order *) pExtra; >>> - p->nColumn = nCol; >>> *ppExtra = ((char *)p) + nByte; >>> } >>> return p; >>> @@ -2836,18 +2782,133 @@ addIndexToTable(Index * pIndex, Table * pTab) >>> } >>> } >>> >>> -bool >>> -index_is_unique(Index *idx) >>> +static inline void >>> +append_string_part(struct region *r, const char *str, >>> + size_t *total_sql_size, Parse *parse) >>> { >>> - assert(idx != NULL); >>> - uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->tnum); >>> - uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum); >>> - struct space *space = space_by_id(space_id); >>> - assert(space != NULL); >>> - struct index *tnt_index = space_index(space, index_id); >>> - assert(tnt_index != NULL); >>> + char * str_part = region_alloc(r, strlen(str)); >>> + if (str_part == NULL){ >>> + diag_set(OutOfMemory, strlen(str), >>> + "region_alloc", "str_part"); >>> + parse->rc = SQL_TARANTOOL_ERROR; >>> + parse->nErr++; >>> + } >>> + memcpy(str_part, str, strlen(str)); >>> + *total_sql_size += strlen(str); >>> +} >>> + >>> +void static > 3. GCC doesn't accept such specifiers order in default build. > Please change this to "static void". > You also better look to the Travis times to times. Ok, sorry, fixed. >>> +set_index_def(Parse *parse, Index *index, Table *table, uint32_t iid, >>> + const char *name, uint32_t name_len, int on_error, >>> + struct ExprList *expr_list, u8 idx_type) >>> +{ >>> + struct space_def *space_def = table->def; >>> + struct index_opts opts; >>> + index_opts_create(&opts); >>> + opts.is_unique = on_error != ON_CONFLICT_ACTION_NONE; >>> + >>> + struct key_def *key_def = key_def_new(expr_list->nExpr); >>> + if (key_def == NULL) { >>> + parse->rc = SQL_TARANTOOL_ERROR; >>> + parse->nErr++; >>> + return; >>> + } >>> + >>> + /* >>> + * Build initial parts of SQL statement. >>> + */ >>> + >>> + struct region *r = &fiber()->gc; > 4. Please, rebase to the master. There would be parser region that should be used here, I believe. > Ok, removed with  parser region >>> + size_t total_sql_size = 0; >>> + >>> + if (idx_type == SQLITE_IDXTYPE_APPDEF) { >>> + append_string_part(r, "CREATE INDEX ", &total_sql_size, >>> + parse); >>> + append_string_part(r, name, &total_sql_size, parse); >>> + append_string_part(r, " ON ", &total_sql_size, parse); >>> + append_string_part(r, space_def->name, &total_sql_size, >>> + parse); >>> + append_string_part(r, " (", &total_sql_size, parse); >>> + } >>> + >>> + for (int i = 0; i < expr_list->nExpr; i++) { >>> + Expr *expr = expr_list->a[i].pExpr; >>> + sql_resolve_self_reference(parse, table, NC_IdxExpr, expr, 0); >>> + if (parse->nErr > 0) >>> + return; > 5. If I not mistaken, key_def is leaking here, with other returns and at the end of the function. You are right. Now fixed. >>> + >>> + Expr *column_expr = sqlite3ExprSkipCollate(expr); >>> + if (column_expr->op != TK_COLUMN) { >>> + sqlite3ErrorMsg(parse, >>> + "functional indexes aren't supported " >>> + "in the current version"); >>> + return; >>> + } >>> + >>> + uint32_t fieldno = column_expr->iColumn; >>> + uint32_t coll_id; >>> + struct coll *coll; >>> + if (expr->op == TK_COLLATE) { >>> + coll = sql_get_coll_seq(parse, expr->u.zToken, >>> + &coll_id); >>> + >>> + if (idx_type == SQLITE_IDXTYPE_APPDEF) { >>> + append_string_part(r, name, >>> + &total_sql_size, parse); >>> + append_string_part(r, " COLLATE ", >>> + &total_sql_size, parse); >>> + const char *coll_name = expr->u.zToken; >>> + append_string_part(r, coll_name, >>> + &total_sql_size, parse); >>> + append_string_part(r, ", ", >>> + &total_sql_size, parse); >>> + } >>> + } else { >>> + coll = sql_column_collation(space_def, fieldno, >>> + &coll_id); >>> + if (idx_type == SQLITE_IDXTYPE_APPDEF) { >>> + append_string_part(r, name, >>> + &total_sql_size, parse); >>> + append_string_part(r, ", ", >>> + &total_sql_size, parse); >>> + } >>> + } >>> + >>> + /* >>> + * Tarantool: DESC indexes are not supported so far. >>> + * See gh-3016. >>> + */ >>> + key_def_set_part(key_def, i, fieldno, >>> + space_def->fields[fieldno].type, >>> + space_def->fields[fieldno].nullable_action, >>> + coll, coll_id, SORT_ORDER_ASC); >>> + } >>> >>> - return tnt_index->def->opts.is_unique; >>> + if (parse->nErr > 0) { >>> + index->def = NULL; >>> + return; >>> + } >>> + >>> + if (idx_type == SQLITE_IDXTYPE_APPDEF) { >>> + memcpy(region_alloc(r, 1), "\0", 1); >>> + total_sql_size += 1; >>> + opts.sql = region_join(r, total_sql_size); >>> + >>> + /* >>> + * fix last ", " with ")\0" to finish the statement. >>> + */ >>> + opts.sql[total_sql_size - 3] = ')'; >>> + opts.sql[total_sql_size - 2] = '\0'; >>> + } >>> + >>> + struct key_def *pk_key_def; >>> + if (idx_type == SQLITE_IDXTYPE_APPDEF) >>> + pk_key_def = table->pIndex->def->key_def; >>> + else >>> + pk_key_def = NULL; >>> + >>> + index->def = index_def_new(space_def->id, iid, name, name_len, >>> + TREE, &opts, key_def, pk_key_def); >>> } >>> >>> void >>> @@ -2856,16 +2917,14 @@ sql_create_index(struct Parse *parse, struct Token *token, >>> int on_error, struct Token *start, struct Expr *where, >>> enum sort_order sort_order, bool if_not_exist, u8 idx_type) >>> { >>> - Table *pTab = 0; /* Table to be indexed */ >>> - Index *pIndex = 0; /* The index to be created */ >>> - char *zName = 0; /* Name of the index */ >>> - int nName; /* Number of characters in zName */ >>> - int i, j; >>> + Table *pTab = NULL; /* Table to be indexed */ >>> + Index *pIndex = NULL; /* The index to be created */ >>> + char *name = NULL; /* Name of the index */ >>> + int name_len; /* Number of characters in zName */ >>> DbFixer sFix; /* For assigning database names to pTable */ >>> sqlite3 *db = parse->db; >>> - struct ExprList_item *col_listItem; /* For looping over col_list */ >>> int nExtra = 0; /* Space allocated for zExtra[] */ >>> - char *zExtra = 0; /* Extra space after the Index object */ >>> + char *zExtra = NULL; /* Extra space after the Index object */ >>> struct session *user_session = current_session(); >>> >>> if (db->mallocFailed || parse->nErr > 0) { >>> @@ -2939,24 +2998,24 @@ sql_create_index(struct Parse *parse, struct Token *token, >>> * our own name. >>> */ >>> if (token) { >>> - zName = sqlite3NameFromToken(db, token); >>> - if (zName == 0) >>> + name = sqlite3NameFromToken(db, token); >>> + if (name == NULL) >>> goto exit_create_index; >>> assert(token->z != 0); >>> if (!db->init.busy) { >>> - if (sqlite3HashFind(&db->pSchema->tblHash, zName) != >>> + if (sqlite3HashFind(&db->pSchema->tblHash, name) != >>> NULL) { >>> sqlite3ErrorMsg(parse, >>> "there is already a table named %s", >>> - zName); >>> + name); >>> goto exit_create_index; >>> } >>> } >>> - if (sqlite3HashFind(&pTab->idxHash, zName) != NULL) { >>> + if (sqlite3HashFind(&pTab->idxHash, name) != NULL) { >>> if (!if_not_exist) { >>> sqlite3ErrorMsg(parse, >>> "index %s.%s already exists", >>> - pTab->def->name, zName); >>> + pTab->def->name, name); >>> } else { >>> assert(!db->init.busy); >>> } >>> @@ -2968,10 +3027,9 @@ sql_create_index(struct Parse *parse, struct Token *token, >>> for (pLoop = pTab->pIndex, n = 1; pLoop; >>> pLoop = pLoop->pNext, n++) { >>> } >>> - zName = >>> - sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->def->name, >>> - n); >>> - if (zName == 0) { >>> + name = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", >>> + pTab->def->name, n); >>> + if (name == NULL) { >>> goto exit_create_index; >>> } >>> } >>> @@ -2997,31 +3055,27 @@ sql_create_index(struct Parse *parse, struct Token *token, >>> sqlite3ExprListCheckLength(parse, col_list, "index"); >>> } >>> >>> - /* Figure out how many bytes of space are required to store explicitly >>> - * specified collation sequence names. >>> - */ >>> - for (i = 0; i < col_list->nExpr; i++) { >>> - Expr *pExpr = col_list->a[i].pExpr; >>> - assert(pExpr != 0); >>> - if (pExpr->op == TK_COLLATE) { >>> - nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); >>> - } >>> - } >>> - >>> /* >>> * Allocate the index structure. >>> */ >>> - nName = sqlite3Strlen30(zName); >>> + name_len = sqlite3Strlen30(name); >>> + >>> + if (name_len > BOX_NAME_MAX) { >>> + sqlite3ErrorMsg(parse, >>> + "%s.%s exceeds indexes' names length limit", >>> + pTab->def->name, name); >>> + goto exit_create_index; >>> + } >>> + >>> + if (sqlite3CheckIdentifierName(parse, name) != SQLITE_OK) >>> + goto exit_create_index; >>> + >>> pIndex = sqlite3AllocateIndexObject(db, col_list->nExpr, >>> - nName + nExtra + 1, &zExtra); >>> + name_len + nExtra + 1, &zExtra); >>> if (db->mallocFailed) { >>> goto exit_create_index; >>> } >>> assert(EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst)); >>> - assert(EIGHT_BYTE_ALIGNMENT(pIndex->coll_array)); >>> - pIndex->zName = zExtra; >>> - zExtra += nName + 1; >>> - memcpy(pIndex->zName, zName, nName + 1); >>> pIndex->pTable = pTab; >>> pIndex->onError = (u8) on_error; >>> /* >>> @@ -3036,7 +3090,6 @@ sql_create_index(struct Parse *parse, struct Token *token, >>> pIndex->idxType = idx_type; >>> } >>> pIndex->pSchema = db->pSchema; >>> - pIndex->nColumn = col_list->nExpr; >>> /* Tarantool have access to each column by any index */ >>> if (where) { >>> sql_resolve_self_reference(parse, pTab, NC_PartIdx, where, >>> @@ -3045,60 +3098,27 @@ sql_create_index(struct Parse *parse, struct Token *token, >>> where = NULL; >>> } >>> >>> - /* Analyze the list of expressions that form the terms of the index and >>> - * report any errors. In the common case where the expression is exactly >>> - * a table column, store that column in aiColumn[]. For general expressions, >>> - * populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[]. >>> - * >>> + /* >>> * TODO: Issue a warning if two or more columns of the index are identical. >>> * TODO: Issue a warning if the table primary key is used as part of the >>> * index key. >>> */ >>> - for (i = 0, col_listItem = col_list->a; i < col_list->nExpr; >>> - i++, col_listItem++) { >>> - Expr *pCExpr; /* The i-th index expression */ >>> - sql_resolve_self_reference(parse, pTab, NC_IdxExpr, >>> - col_listItem->pExpr, NULL); >>> - if (parse->nErr > 0) >>> - goto exit_create_index; >>> - pCExpr = sqlite3ExprSkipCollate(col_listItem->pExpr); >>> - if (pCExpr->op != TK_COLUMN) { >>> - sqlite3ErrorMsg(parse, >>> - "functional indexes aren't supported " >>> - "in the current version"); >>> - goto exit_create_index; >>> - } else { >>> - j = pCExpr->iColumn; >>> - assert(j <= 0x7fff); >>> - if (j < 0) { >>> - j = pTab->iPKey; >>> - } >>> - pIndex->aiColumn[i] = (i16) j; >>> - } >>> - struct coll *coll; >>> - uint32_t id; >>> - if (col_listItem->pExpr->op == TK_COLLATE) { >>> - const char *coll_name = col_listItem->pExpr->u.zToken; >>> - coll = sql_get_coll_seq(parse, coll_name, &id); >>> >>> - if (coll == NULL && >>> - sqlite3StrICmp(coll_name, "binary") != 0) { >>> - goto exit_create_index; >>> - } >>> - } else if (j >= 0) { >>> - coll = sql_column_collation(pTab->def, j, &id); >>> - } else { >>> - id = COLL_NONE; >>> - coll = NULL; >>> - } >>> - pIndex->coll_array[i] = coll; >>> - pIndex->coll_id_array[i] = id; >>> + uint32_t max_iid = 0; >>> + for (Index *index = pTab->pIndex; index; index = index->pNext) { >>> + max_iid = max_iid > index->def->iid ? >>> + max_iid : >>> + index->def->iid + 1; >>> + } >>> >>> - /* Tarantool: DESC indexes are not supported so far. >>> - * See gh-3016. >>> - */ >>> - pIndex->sort_order[i] = SORT_ORDER_ASC; >>> + set_index_def(parse, pIndex, pTab, max_iid, name, name_len, on_error, >>> + col_list, idx_type); >>> + >>> + if (pIndex->def == NULL || >>> + !index_def_is_valid(pIndex->def, pTab->def->name)) { >>> + goto exit_create_index; >>> } >>> + >>> if (pTab == parse->pNewTable) { >>> /* This routine has been called to create an automatic index as a >>> * result of a PRIMARY KEY or UNIQUE clause on a column definition, or >>> @@ -3123,25 +3143,27 @@ sql_create_index(struct Parse *parse, struct Token *token, >>> */ >>> Index *pIdx; >>> for (pIdx = pTab->pIndex; pIdx; pIdx = pIdx->pNext) { >>> - int k; >>> + uint32_t k; >>> assert(IsUniqueIndex(pIdx)); >>> assert(pIdx->idxType != SQLITE_IDXTYPE_APPDEF); >>> assert(IsUniqueIndex(pIndex)); >>> >>> - if (pIdx->nColumn != pIndex->nColumn) >>> + if (pIdx->def->key_def->part_count != >>> + pIndex->def->key_def->part_count) { >>> continue; >>> - for (k = 0; k < pIdx->nColumn; k++) { >>> - assert(pIdx->aiColumn[k] >= 0); >>> - if (pIdx->aiColumn[k] != pIndex->aiColumn[k]) >>> + } >>> + for (k = 0; k < pIdx->def->key_def->part_count; k++) { >>> + if (pIdx->def->key_def->parts[k].fieldno != >>> + pIndex->def->key_def->parts[k].fieldno) { >>> break; >>> + } >>> struct coll *coll1, *coll2; >>> - uint32_t id; >>> - coll1 = sql_index_collation(pIdx, k, &id); >>> - coll2 = sql_index_collation(pIndex, k, &id); >>> + coll1 = pIdx->def->key_def->parts[k].coll; >>> + coll2 = pIndex->def->key_def->parts[k].coll; >>> if (coll1 != coll2) >>> break; >>> } >>> - if (k == pIdx->nColumn) { >>> + if (k == pIdx->def->key_def->part_count) { >>> if (pIdx->onError != pIndex->onError) { >>> /* This constraint creates the same index as a previous >>> * constraint specified somewhere in the CREATE TABLE statement. >>> @@ -3175,7 +3197,7 @@ sql_create_index(struct Parse *parse, struct Token *token, >>> assert(parse->nErr == 0); >>> if (db->init.busy) { >>> Index *p; >>> - p = sqlite3HashInsert(&pTab->idxHash, pIndex->zName, pIndex); >>> + p = sqlite3HashInsert(&pTab->idxHash, pIndex->def->name, pIndex); >>> if (p) { >>> assert(p == pIndex); /* Malloc must have failed */ >>> sqlite3OomFault(db); >>> @@ -3273,44 +3295,7 @@ sql_create_index(struct Parse *parse, struct Token *token, >>> sql_expr_delete(db, where, false); >>> sql_expr_list_delete(db, col_list); >>> sqlite3SrcListDelete(db, tbl_name); >>> - sqlite3DbFree(db, zName); >>> -} >>> - >>> -/** >>> - * Return number of columns in given index. >>> - * If space is ephemeral, use internal >>> - * SQL structure to fetch the value. >>> - */ >>> -uint32_t >>> -index_column_count(const Index *idx) >>> -{ >>> - assert(idx != NULL); >>> - uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->tnum); >>> - struct space *space = space_by_id(space_id); >>> - /* It is impossible to find an ephemeral space by id. */ >>> - if (space == NULL) >>> - return idx->nColumn; >>> - >>> - uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum); >>> - struct index *index = space_index(space, index_id); >>> - assert(index != NULL); >>> - return index->def->key_def->part_count; >>> -} >>> - >>> -/** Return true if given index is unique and not nullable. */ >>> -bool >>> -index_is_unique_not_null(const Index *idx) >>> -{ >>> - assert(idx != NULL); >>> - uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->tnum); >>> - struct space *space = space_by_id(space_id); >>> - assert(space != NULL); >>> - >>> - uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum); >>> - struct index *index = space_index(space, index_id); >>> - assert(index != NULL); >>> - return (index->def->opts.is_unique && >>> - !index->def->key_def->is_nullable); >>> + sqlite3DbFree(db, name); >>> } >>> >>> void >>> @@ -3938,18 +3923,19 @@ sqlite3UniqueConstraint(Parse * pParse, /* Parsing context */ >>> ) >>> { >>> char *zErr; >>> - int j; >>> + uint32_t j; >>> StrAccum errMsg; >>> Table *pTab = pIdx->pTable; >>> >>> sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); >>> if (pIdx->aColExpr) { >>> - sqlite3XPrintf(&errMsg, "index '%q'", pIdx->zName); >>> + sqlite3XPrintf(&errMsg, "index '%q'", pIdx->def->name); >>> } else { >>> - for (j = 0; j < pIdx->nColumn; j++) { >>> + struct key_part *part = pIdx->def->key_def->parts; >>> + for (j = 0; j < pIdx->def->key_def->part_count; j++, part++) { >>> char *zCol; >>> - assert(pIdx->aiColumn[j] >= 0); >>> - zCol = pTab->def->fields[pIdx->aiColumn[j]].name; >>> + uint32_t fieldno = part->fieldno; >>> + zCol = pTab->def->fields[fieldno].name; >>> if (j) >>> sqlite3StrAccumAppend(&errMsg, ", ", 2); >>> sqlite3XPrintf(&errMsg, "%s.%s", pTab->def->name, zCol); >>> @@ -3972,11 +3958,11 @@ static bool >>> collationMatch(struct coll *coll, struct Index *index) >>> { >>> assert(coll != NULL); >>> - for (int i = 0; i < index->nColumn; i++) { >>> - uint32_t id; >>> - struct coll *idx_coll = sql_index_collation(index, i, &id); >>> - assert(idx_coll != 0 || index->aiColumn[i] < 0); >>> - if (index->aiColumn[i] >= 0 && coll == idx_coll) >>> + struct key_part *part = index->def->key_def->parts; >>> + for (uint32_t i = 0; i < index->def->key_def->part_count; i++, part++) { >>> + struct coll *idx_coll = part->coll; >>> + assert(idx_coll != NULL); >>> + if (coll == idx_coll) >>> return true; >>> } >>> return false; >>> diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c >>> index ddad54b3e..0314382f7 100644 >>> --- a/src/box/sql/delete.c >>> +++ b/src/box/sql/delete.c >>> @@ -209,7 +209,7 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list, >>> } else { >>> pk = sqlite3PrimaryKeyIndex(table); >>> assert(pk != NULL); >>> - pk_len = index_column_count(pk); >>> + pk_len = pk->def->key_def->part_count; >>> parse->nMem += pk_len; >>> sqlite3VdbeAddOp2(v, OP_OpenTEphemeral, eph_cursor, >>> pk_len); >>> @@ -251,12 +251,11 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list, >>> >>> /* Extract the primary key for the current row */ >>> if (!is_view) { >>> - for (int i = 0; i < pk_len; i++) { >>> - assert(pk->aiColumn[i] >= 0); >>> + struct key_part *part = pk->def->key_def->parts; >>> + for (int i = 0; i < pk_len; i++, part++) { >>> sqlite3ExprCodeGetColumnOfTable(v, table->def, >>> tab_cursor, >>> - pk-> >>> - aiColumn[i], >>> + part->fieldno, >>> reg_pk + i); >>> } >>> } else { >>> @@ -326,7 +325,7 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list, >>> sqlite3VdbeAddOp3(v, OP_OpenWrite, tab_cursor, >>> table->tnum, space_ptr_reg); >>> sql_vdbe_set_p4_key_def(parse, pk); >>> - VdbeComment((v, "%s", pk->zName)); >>> + VdbeComment((v, "%s", pk->def->name)); >>> >>> if (one_pass == ONEPASS_MULTI) >>> sqlite3VdbeJumpHere(v, iAddrOnce); >>> @@ -536,14 +535,14 @@ sql_generate_index_key(struct Parse *parse, struct Index *index, int cursor, >>> *part_idx_label = 0; >>> } >>> } >>> - int col_cnt = index_column_count(index); >>> + int col_cnt = index->def->key_def->part_count; >>> int reg_base = sqlite3GetTempRange(parse, col_cnt); >>> if (prev != NULL && (reg_base != reg_prev || >>> prev->pPartIdxWhere != NULL)) >>> prev = NULL; >>> for (int j = 0; j < col_cnt; j++) { >>> - if (prev != NULL && prev->aiColumn[j] == index->aiColumn[j] >>> - && prev->aiColumn[j] != XN_EXPR) { >>> + if (prev->def->key_def->parts[j].fieldno == >>> + index->def->key_def->parts[j].fieldno && prev == NULL) { >>> /* >>> * This column was already computed by the >>> * previous index. >>> diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c >>> index 8866f6fed..a756535f0 100644 >>> --- a/src/box/sql/expr.c >>> +++ b/src/box/sql/expr.c >>> @@ -2422,20 +2422,24 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */ >>> pIdx = pIdx->pNext) { >>> Bitmask colUsed; /* Columns of the index used */ >>> Bitmask mCol; /* Mask for the current column */ >>> - if (pIdx->nColumn < nExpr) >>> + uint32_t part_count = pIdx->def->key_def-> >>> + part_count; >>> + struct key_part *parts = pIdx->def->key_def-> >>> + parts; >>> + if ((int)part_count < nExpr) >>> continue; >>> /* Maximum nColumn is BMS-2, not BMS-1, so that we can compute >>> * BITMASK(nExpr) without overflowing >>> */ >>> - testcase(pIdx->nColumn == BMS - 2); >>> - testcase(pIdx->nColumn == BMS - 1); >>> - if (pIdx->nColumn >= BMS - 1) >>> + testcase(part_count == BMS - 2); >>> + testcase(>part_count == BMS - 1); >>> + if (part_count >= BMS - 1) >>> continue; >>> if (mustBeUnique) { >>> - if (pIdx->nColumn > nExpr >>> - || (pIdx->nColumn > nExpr >>> - && !index_is_unique(pIdx))) { >>> - continue; /* This index is not unique over the IN RHS columns */ >>> + if ((int)part_count > nExpr >>> + || !pIdx->def->opts.is_unique) { >>> + /* This index is not unique over the IN RHS columns */ >>> + continue; >>> } >>> } >>> >>> @@ -2449,12 +2453,13 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */ >>> int j; >>> >>> for (j = 0; j < nExpr; j++) { >>> - if (pIdx->aiColumn[j] != >>> - pRhs->iColumn) { >>> + if ((int) parts[j].fieldno >>> + != pRhs->iColumn) { >>> continue; >>> } >>> - struct coll *idx_coll; >>> - idx_coll = sql_index_collation(pIdx, j, &id); >>> + >>> + struct coll *idx_coll = >>> + parts[j].coll; >>> if (pReq != NULL && >>> pReq != idx_coll) { >>> continue; >>> @@ -2483,17 +2488,16 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */ >>> 0, 0, 0, >>> sqlite3MPrintf(db, >>> "USING INDEX %s FOR IN-OPERATOR", >>> - pIdx->zName), >>> + pIdx->def->name), >>> P4_DYNAMIC); >>> emit_open_cursor(pParse, iTab, >>> pIdx->tnum); >>> sql_vdbe_set_p4_key_def(pParse, pIdx); >>> - VdbeComment((v, "%s", pIdx->zName)); >>> + VdbeComment((v, "%s", pIdx->def->name)); >>> assert(IN_INDEX_INDEX_DESC == >>> IN_INDEX_INDEX_ASC + 1); >>> eType = IN_INDEX_INDEX_ASC + >>> - sql_index_column_sort_order(pIdx, >>> - 0); >>> + parts[0].sort_order; >>> >>> if (prRhsHasNull) { >>> #ifdef SQLITE_ENABLE_COLUMN_USED_MASK >>> @@ -2515,7 +2519,7 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */ >>> /* Tarantool: Check for null is performed on first key of the index. */ >>> sqlite3SetHasNullFlag(v, >>> iTab, >>> - pIdx->aiColumn[0], >>> + parts[0].fieldno, >>> *prRhsHasNull); >>> } >>> } >>> @@ -3146,12 +3150,12 @@ sqlite3ExprCodeIN(Parse * pParse, /* Parsing and code generating context */ >>> struct Index *pk = sqlite3PrimaryKeyIndex(tab); >>> assert(pk); >>> >>> + uint32_t fieldno = pk->def->key_def->parts[0].fieldno; >>> enum affinity_type affinity = >>> - tab->def->fields[pk->aiColumn[0]].affinity; >>> - if (pk->nColumn == 1 >>> + tab->def->fields[fieldno].affinity; >>> + if (pk->def->key_def->part_count == 1 >>> && affinity == AFFINITY_INTEGER >>> - && pk->aiColumn[0] < nVector) { >>> - int reg_pk = rLhs + pk->aiColumn[0]; >>> + && (int) fieldno < nVector) { int reg_pk = rLhs + (int)fieldno; >>> sqlite3VdbeAddOp2(v, OP_MustBeInt, reg_pk, destIfFalse); >>> } >>> } >>> @@ -3483,17 +3487,9 @@ sqlite3ExprCodeLoadIndexColumn(Parse * pParse, /* The parsing context */ >>> int regOut /* Store the index column value in this register */ >>> ) >>> { >>> - i16 iTabCol = pIdx->aiColumn[iIdxCol]; >>> - if (iTabCol == XN_EXPR) { >>> - assert(pIdx->aColExpr); >>> - assert(pIdx->aColExpr->nExpr > iIdxCol); >>> - pParse->iSelfTab = iTabCur; >>> - sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, >>> - regOut); >>> - } else { >>> - sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable->def, >>> - iTabCur, iTabCol, regOut); >>> - } >>> + i16 iTabCol = pIdx->def->key_def->parts[iIdxCol].fieldno; >>> + sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable->def, >>> + iTabCur, iTabCol, regOut); >>> } >>> >>> void >>> diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c >>> index 70ebef89f..79320eced 100644 >>> --- a/src/box/sql/fkey.c >>> +++ b/src/box/sql/fkey.c >>> @@ -256,8 +256,8 @@ sqlite3FkLocateIndex(Parse * pParse, /* Parse context to store any error in */ >>> } >>> >>> for (pIdx = pParent->pIndex; pIdx; pIdx = pIdx->pNext) { >>> - int nIdxCol = index_column_count(pIdx); >>> - if (nIdxCol == nCol && index_is_unique(pIdx) >>> + int nIdxCol = pIdx->def->key_def->part_count; >>> + if (nIdxCol == nCol && pIdx->def->opts.is_unique >>> && pIdx->pPartIdxWhere == 0) { >>> /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number >>> * of columns. If each indexed column corresponds to a foreign key >>> @@ -286,8 +286,10 @@ sqlite3FkLocateIndex(Parse * pParse, /* Parse context to store any error in */ >>> * the default collation sequences for each column. >>> */ >>> int i, j; >>> - for (i = 0; i < nCol; i++) { >>> - i16 iCol = pIdx->aiColumn[i]; /* Index of column in parent tbl */ >>> + struct key_part *part = >>> + pIdx->def->key_def->parts; >>> + for (i = 0; i < nCol; i++, part++) { >>> + i16 iCol = (int) part->fieldno; /* Index of column in parent tbl */ >>> char *zIdxCol; /* Name of indexed column */ >>> >>> if (iCol < 0) >>> @@ -302,9 +304,7 @@ sqlite3FkLocateIndex(Parse * pParse, /* Parse context to store any error in */ >>> def_coll = sql_column_collation(pParent->def, >>> iCol, >>> &id); >>> - struct coll *coll = >>> - sql_index_collation(pIdx, i, >>> - &id); >>> + struct coll *coll = part->coll; >>> if (def_coll != coll) >>> break; >>> >>> @@ -464,13 +464,15 @@ fkLookupParent(Parse * pParse, /* Parse context */ >>> for (i = 0; i < nCol; i++) { >>> int iChild = aiCol[i] + 1 + regData; >>> int iParent = >>> - pIdx->aiColumn[i] + 1 + regData; >>> - assert(pIdx->aiColumn[i] >= 0); >>> + (int) pIdx->def->key_def->parts[i].fieldno >>> + + 1 + regData; >>> assert(aiCol[i] != pTab->iPKey); >>> - if (pIdx->aiColumn[i] == pTab->iPKey) { >>> + if ((int)pIdx->def->key_def-> >>> + parts[i].fieldno == pTab->iPKey) { >>> /* The parent key is a composite key that includes the IPK column */ >>> iParent = regData; >>> } >>> + >>> sqlite3VdbeAddOp3(v, OP_Ne, iChild, >>> iJump, iParent); >>> VdbeCoverage(v); >>> @@ -622,7 +624,7 @@ fkScanChildren(Parse * pParse, /* Parse context */ >>> Vdbe *v = sqlite3GetVdbe(pParse); >>> >>> assert(pIdx == 0 || pIdx->pTable == pTab); >>> - assert(pIdx == 0 || (int)index_column_count(pIdx) == pFKey->nCol); >>> + assert(pIdx == 0 || (int) pIdx->def->key_def->part_count == pFKey->nCol); >>> assert(pIdx != 0); >>> >>> if (nIncr < 0) { >>> @@ -646,7 +648,7 @@ fkScanChildren(Parse * pParse, /* Parse context */ >>> i16 iCol; /* Index of column in child table */ >>> const char *zCol; /* Name of column in child table */ >>> >>> - iCol = pIdx ? pIdx->aiColumn[i] : -1; >>> + iCol = pIdx ? pIdx->def->key_def->parts[i].fieldno : -1; > - iCol = pIdx ? pIdx->def->key_def->parts[i].fieldno : -1; > + iCol = pIdx != NULL ? > + (i16)pIdx->def->key_def->parts[i].fieldno : -1; > Fixed. >>> pLeft = exprTableRegister(pParse, pTab, regData, iCol); >>> iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; >>> assert(iCol >= 0); >>> @@ -671,10 +673,9 @@ fkScanChildren(Parse * pParse, /* Parse context */ >>> Expr *pEq, *pAll = 0; >>> Index *pPk = sqlite3PrimaryKeyIndex(pTab); >>> assert(pIdx != 0); >>> - int col_count = index_column_count(pPk); >>> + int col_count = pPk->def->key_def->part_count; >>> for (i = 0; i < col_count; i++) { >>> - i16 iCol = pIdx->aiColumn[i]; >>> - assert(iCol >= 0); >>> + i16 iCol = (int) pIdx->def->key_def->parts[i].fieldno; >>> pLeft = exprTableRegister(pParse, pTab, regData, iCol); >>> pRight = >>> exprTableColumn(db, pTab->def, >>> @@ -992,7 +993,6 @@ sqlite3FkCheck(Parse * pParse, /* Parse context */ >>> if (aiCol[i] == pTab->iPKey) { >>> aiCol[i] = -1; >>> } >>> - assert(pIdx == 0 || pIdx->aiColumn[i] >= 0); >>> } >>> >>> pParse->nTab++; >>> @@ -1126,10 +1126,10 @@ sqlite3FkOldmask(Parse * pParse, /* Parse context */ >>> Index *pIdx = 0; >>> sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0); >>> if (pIdx) { >>> - int nIdxCol = index_column_count(pIdx); >>> + int nIdxCol = pIdx->def->key_def->part_count; >>> for (i = 0; i < nIdxCol; i++) { >>> - assert(pIdx->aiColumn[i] >= 0); >>> - mask |= COLUMN_MASK(pIdx->aiColumn[i]); >>> + mask |= COLUMN_MASK(pIdx->def-> >>> + key_def->parts[i].fieldno); >>> } >>> } >>> } >>> @@ -1264,11 +1264,12 @@ fkActionTrigger(Parse * pParse, /* Parse context */ >>> || (pTab->iPKey >= 0 >>> && pTab->iPKey < >>> (int)pTab->def->field_count)); >>> - assert(pIdx == 0 || pIdx->aiColumn[i] >= 0); >>> + >>> + uint32_t fieldno = pIdx != NULL ? >>> + pIdx->def->key_def->parts[i].fieldno >>> + : pTab->iPKey; > 6. GCC looks like a little more pedantic. > - : pTab->iPKey; > > + : (uint32_t)pTab->iPKey; > 7. Please put ":" at the prev. line. Fixed. >>> sqlite3TokenInit(&tToCol, >>> - pTab->def->fields[pIdx ? pIdx-> >>> - aiColumn[i] : pTab->iPKey]. >>> - name); >>> + pTab->def->fields[fieldno].name); >>> sqlite3TokenInit(&tFromCol, >>> pFKey->pFrom->def->fields[ >>> iFromCol].name); >>> diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c >>> index 59c61c703..fc9f85165 100644 >>> --- a/src/box/sql/insert.c >>> +++ b/src/box/sql/insert.c >>> @@ -89,7 +89,7 @@ sqlite3IndexAffinityStr(sqlite3 * db, Index * pIdx) >>> * up. >>> */ >>> int n; >>> - int nColumn = index_column_count(pIdx); >>> + int nColumn = pIdx->def->key_def->part_count; >>> pIdx->zColAff = >>> (char *)sqlite3DbMallocRaw(0, nColumn + 1); >>> if (!pIdx->zColAff) { >>> @@ -97,22 +97,8 @@ sqlite3IndexAffinityStr(sqlite3 * db, Index * pIdx) >>> return 0; >>> } >>> for (n = 0; n < nColumn; n++) { >>> - i16 x = pIdx->aiColumn[n]; >>> - if (x >= 0) { >>> - char affinity = pIdx->pTable-> >>> - def->fields[x].affinity; >>> - pIdx->zColAff[n] = affinity; >>> - } else { >>> - char aff; >>> - assert(x == XN_EXPR); >>> - assert(pIdx->aColExpr != 0); >>> - aff = >>> - sqlite3ExprAffinity(pIdx->aColExpr->a[n]. >>> - pExpr); >>> - if (aff == 0) >>> - aff = AFFINITY_BLOB; >>> - pIdx->zColAff[n] = aff; >>> - } >>> + i16 x = pIdx->def->key_def->parts[n].fieldno; >>> + pIdx->zColAff[n] = pIdx->pTable->def->fields[x].affinity; >>> } >>> pIdx->zColAff[n] = 0; >>> } >>> @@ -645,7 +631,7 @@ sqlite3Insert(Parse * pParse, /* Parser context */ >>> pIdx = pIdx->pNext, i++) { >>> assert(pIdx); >>> aRegIdx[i] = ++pParse->nMem; >>> - pParse->nMem += index_column_count(pIdx); >>> + pParse->nMem += pIdx->def->key_def->part_count; >>> } >>> } >>> >>> @@ -1088,7 +1074,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ >>> nCol = pTab->def->field_count; >>> >>> pPk = sqlite3PrimaryKeyIndex(pTab); >>> - nPkField = index_column_count(pPk); >>> + nPkField = pPk->def->key_def->part_count; >>> >>> /* Record that this module has started */ >>> VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)", >>> @@ -1252,38 +1238,27 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ >>> * the insert or update. Store that record in the aRegIdx[ix] register >>> */ >>> regIdx = aRegIdx[ix] + 1; >>> - int nIdxCol = (int)index_column_count(pIdx); >>> + int nIdxCol = pIdx->def->key_def->part_count; >>> for (i = 0; i < nIdxCol; i++) { >>> - int iField = pIdx->aiColumn[i]; >>> + int iField = (int) pIdx->def->key_def->parts[i].fieldno; >>> int x; >>> - if (iField == XN_EXPR) { >>> - pParse->ckBase = regNewData + 1; >>> - sqlite3ExprCodeCopy(pParse, >>> - pIdx->aColExpr->a[i].pExpr, >>> - regIdx + i); >>> - pParse->ckBase = 0; >>> - VdbeComment((v, "%s column %d", pIdx->zName, >>> - i)); >>> - } else { >>> - /* OP_SCopy copies value in separate register, >>> - * which later will be used by OP_NoConflict. >>> - * But OP_NoConflict is necessary only in cases >>> - * when bytecode is needed for proper UNIQUE >>> - * constraint handling. >>> - */ >>> - if (uniqueByteCodeNeeded) { >>> - if (iField == pTab->iPKey) >>> - x = regNewData; >>> - else >>> - x = iField + regNewData + 1; >>> - >>> - assert(iField >= 0); >>> - sqlite3VdbeAddOp2(v, OP_SCopy, >>> - x, regIdx + i); >>> - VdbeComment((v, "%s", >>> - pTab->def->fields[ >>> - iField].name)); >>> - } >>> + /* OP_SCopy copies value in separate register, >>> + * which later will be used by OP_NoConflict. >>> + * But OP_NoConflict is necessary only in cases >>> + * when bytecode is needed for proper UNIQUE >>> + * constraint handling. >>> + */ >>> + if (uniqueByteCodeNeeded) { >>> + if (iField == pTab->iPKey) >>> + x = regNewData; >>> + else >>> + x = iField + regNewData + 1; >>> + >>> + assert(iField >= 0); >>> + sqlite3VdbeAddOp2(v, OP_SCopy, >>> + x, regIdx + i); >>> + VdbeComment((v, "%s", >>> + pTab->def->fields[iField].name)); >>> } >>> } >>> >>> @@ -1293,8 +1268,12 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ >>> /* If PK is marked as INTEGER, use it as strict type, >>> * not as affinity. Emit code for type checking */ >>> if (nIdxCol == 1) { >>> - reg_pk = regNewData + 1 + pIdx->aiColumn[0]; >>> - if (pTab->zColAff[pIdx->aiColumn[0]] == >>> + reg_pk = regNewData + 1 + >>> + pIdx->def->key_def->parts[0].fieldno; >>> + >>> + int fieldno = (int)pIdx->def->key_def-> >>> + parts[0].fieldno; >>> + if (pTab->zColAff[fieldno] == >>> AFFINITY_INTEGER) { >>> int skip_if_null = sqlite3VdbeMakeLabel(v); >>> if ((pTab->tabFlags & TF_Autoincrement) != 0) { >>> @@ -1311,8 +1290,8 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ >>> } >>> >>> sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData + 1, >>> - pTab->def->field_count, aRegIdx[ix]); >>> - VdbeComment((v, "for %s", pIdx->zName)); >>> + pTab->def->field_count, aRegIdx[ix]); >>> + VdbeComment((v, "for %s", pIdx->def->name)); >>> } >>> >>> /* In an UPDATE operation, if this index is the PRIMARY KEY >>> @@ -1400,7 +1379,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ >>> if (uniqueByteCodeNeeded) { >>> sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, >>> addrUniqueOk, regIdx, >>> - index_column_count(pIdx)); >>> + pIdx->def->key_def->part_count); >>> } >>> VdbeCoverage(v); >>> >>> @@ -1410,19 +1389,17 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ >>> nPkField); >>> if (isUpdate || on_error == ON_CONFLICT_ACTION_REPLACE) { >>> int x; >>> - int nPkCol = index_column_count(pPk); >>> + int nPkCol = pPk->def->key_def->part_count; >>> /* Extract the PRIMARY KEY from the end of the index entry and >>> * store it in registers regR..regR+nPk-1 >>> */ >>> if (pIdx != pPk) { >>> for (i = 0; i < nPkCol; i++) { >>> - assert(pPk->aiColumn[i] >= 0); >>> - x = pPk->aiColumn[i]; >>> + x = pPk->def->key_def->parts[i].fieldno; >>> sqlite3VdbeAddOp3(v, OP_Column, >>> iThisCur, x, regR + i); >>> VdbeComment((v, "%s.%s", pTab->def->name, >>> - pTab->def->fields[ >>> - pPk->aiColumn[i]].name)); >>> + pTab->def->fields[x].name)); >>> } >>> } >>> if (isUpdate && uniqueByteCodeNeeded) { >>> @@ -1440,10 +1417,11 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ >>> regIdx : regR); >>> >>> for (i = 0; i < nPkCol; i++) { >>> - uint32_t id; >>> - char *p4 = (char *)sql_index_collation(pPk, i, &id); >>> - x = pPk->aiColumn[i]; >>> - assert(x >= 0); >>> + char *p4 = (char *) pPk->def->key_def->parts[i].coll; >>> + x = pPk->def->key_def->parts[i].fieldno; >>> + if (pPk->tnum==0) { >>> + x = -1; >>> + } > 8. Redundant {} > - if (pPk->tnum==0) { > + if (pPk->tnum == 0) > x = -1; > - } Fixed. >>> if (i == (nPkCol - 1)) { >>> addrJump = addrUniqueOk; >>> op = OP_Eq; >>> @@ -1620,8 +1598,8 @@ sqlite3OpenTableAndIndices(Parse * pParse, /* Parsing context */ >>> IsPrimaryKeyIndex(pIdx) || /* Condition 2 */ >>> sqlite3FkReferences(pTab) || /* Condition 3 */ >>> /* Condition 4 */ >>> - (index_is_unique(pIdx) && pIdx->onError != >>> - ON_CONFLICT_ACTION_DEFAULT && >>> + (pIdx->def->opts.is_unique && >>> + pIdx->onError != ON_CONFLICT_ACTION_DEFAULT && >>> /* Condition 4.1 */ >>> pIdx->onError != ON_CONFLICT_ACTION_ABORT) || >>> /* Condition 4.2 */ >>> @@ -1639,7 +1617,7 @@ sqlite3OpenTableAndIndices(Parse * pParse, /* Parsing context */ >>> space_ptr_reg); >>> sql_vdbe_set_p4_key_def(pParse, pIdx); >>> sqlite3VdbeChangeP5(v, p5); >>> - VdbeComment((v, "%s", pIdx->zName)); >>> + VdbeComment((v, "%s", pIdx->def->name)); >>> } >>> } >>> } >>> @@ -1676,35 +1654,23 @@ xferCompatibleIndex(Index * pDest, Index * pSrc) >>> uint32_t i; >>> assert(pDest && pSrc); >>> assert(pDest->pTable != pSrc->pTable); >>> - uint32_t nDestCol = index_column_count(pDest); >>> - uint32_t nSrcCol = index_column_count(pSrc); >>> + uint32_t nDestCol = pDest->def->key_def->part_count; >>> + uint32_t nSrcCol = pSrc->def->key_def->part_count; >>> if (nDestCol != nSrcCol) { >>> return 0; /* Different number of columns */ >>> } >>> if (pDest->onError != pSrc->onError) { >>> return 0; /* Different conflict resolution strategies */ >>> } >>> - for (i = 0; i < nSrcCol; i++) { >>> - if (pSrc->aiColumn[i] != pDest->aiColumn[i]) { >>> + struct key_part *src_part = pSrc->def->key_def->parts; >>> + struct key_part *dest_part = pDest->def->key_def->parts; >>> + for (i = 0; i < nSrcCol; i++, src_part++, dest_part++) { >>> + if (src_part->fieldno != dest_part->fieldno) >>> return 0; /* Different columns indexed */ >>> - } >>> - if (pSrc->aiColumn[i] == XN_EXPR) { >>> - assert(pSrc->aColExpr != 0 && pDest->aColExpr != 0); >>> - if (sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr, >>> - pDest->aColExpr->a[i].pExpr, >>> - -1) != 0) { >>> - return 0; /* Different expressions in the index */ >>> - } >>> - } >>> - if (sql_index_column_sort_order(pSrc, i) != >>> - sql_index_column_sort_order(pDest, i)) { >>> + if (src_part->sort_order != dest_part->sort_order) >>> return 0; /* Different sort orders */ >>> - } >>> - uint32_t id; >>> - if (sql_index_collation(pSrc, i, &id) != >>> - sql_index_collation(pDest, i, &id)) { >>> + if (src_part->coll != dest_part->coll) >>> return 0; /* Different collating sequences */ >>> - } >>> } >>> if (sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1)) { >>> return 0; /* Different WHERE clauses */ >>> @@ -1876,16 +1842,14 @@ xferOptimization(Parse * pParse, /* Parser context */ >>> } >>> } >>> for (pDestIdx = pDest->pIndex; pDestIdx; pDestIdx = pDestIdx->pNext) { >>> - if (index_is_unique(pDestIdx)) { >>> + if (pDestIdx->def->opts.is_unique) >>> destHasUniqueIdx = 1; >>> - } >>> for (pSrcIdx = pSrc->pIndex; pSrcIdx; pSrcIdx = pSrcIdx->pNext) { >>> if (xferCompatibleIndex(pDestIdx, pSrcIdx)) >>> break; >>> } >>> - if (pSrcIdx == 0) { >>> + if (pSrcIdx == 0) >>> return 0; /* pDestIdx has no corresponding index in pSrc */ >>> - } > 9. Please, like this: > - if (pSrcIdx == 0) > - return 0; /* pDestIdx has no corresponding index in pSrc */ > + /* pDestIdx has no corresponding index in pSrc. */ > + if (pSrcIdx == NULL) > + return 0; Fixed. >>> } >>> /* Get server checks. */ >>> ExprList *pCheck_src = space_checks_expr_list( >>> @@ -1960,11 +1924,11 @@ xferOptimization(Parse * pParse, /* Parser context */ >>> assert(pSrcIdx); >>> emit_open_cursor(pParse, iSrc, pSrcIdx->tnum); >>> sql_vdbe_set_p4_key_def(pParse, pSrcIdx); >>> - VdbeComment((v, "%s", pSrcIdx->zName)); >>> + VdbeComment((v, "%s", pSrcIdx->def->name)); >>> emit_open_cursor(pParse, iDest, pDestIdx->tnum); >>> sql_vdbe_set_p4_key_def(pParse, pDestIdx); >>> sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); >>> - VdbeComment((v, "%s", pDestIdx->zName)); >>> + VdbeComment((v, "%s", pDestIdx->def->name)); >>> addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); >>> VdbeCoverage(v); >>> sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData); >>> diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c >>> index 9dab5a7fd..45896811b 100644 >>> --- a/src/box/sql/pragma.c >>> +++ b/src/box/sql/pragma.c >>> @@ -370,8 +370,11 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ >>> for (k = 1; >>> k <= >>> (int)pTab->def->field_count >>> - && pPk->aiColumn[k - 1] != >>> - i; k++) { >>> + && (int) pPk->def-> >>> + key_def-> >>> + parts[k - 1]. >>> + fieldno != i; >>> + k++) { >>> } >>> } >>> bool nullable = >>> @@ -430,7 +433,7 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ >>> size_t avg_tuple_size_idx = >>> sql_index_tuple_size(space, idx); >>> sqlite3VdbeMultiLoad(v, 2, "sii", >>> - pIdx->zName, >>> + pIdx->def->name, >>> avg_tuple_size_idx, >>> index_field_tuple_est(pIdx, 0)); >>> sqlite3VdbeAddOp2(v, OP_ResultRow, 1, >>> @@ -459,11 +462,13 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ >>> */ >>> pParse->nMem = 3; >>> } >>> - mx = index_column_count(pIdx); >>> + mx = pIdx->def->key_def->part_count; >>> assert(pParse->nMem <= >>> pPragma->nPragCName); >>> - for (i = 0; i < mx; i++) { >>> - i16 cnum = pIdx->aiColumn[i]; >>> + struct key_part *part = >>> + pIdx->def->key_def->parts; >>> + for (i = 0; i < mx; i++, part++) { >>> + i16 cnum = (int) part->fieldno; >>> assert(pIdx->pTable); >>> sqlite3VdbeMultiLoad(v, 1, >>> "iis", i, >>> @@ -477,19 +482,18 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ >>> name); >>> if (pPragma->iArg) { >>> const char *c_n; >>> - uint32_t id; >>> + uint32_t id = >>> + part->coll_id; >>> struct coll *coll = >>> - sql_index_collation(pIdx, i, &id); >>> + part->coll; >>> if (coll != NULL) >>> c_n = coll_by_id(id)->name; >>> else >>> c_n = "BINARY"; >>> - enum sort_order sort_order; >>> - sort_order = sql_index_column_sort_order(pIdx, >>> - i); >>> sqlite3VdbeMultiLoad(v, >>> 4, >>> "isi", >>> + part-> >>> sort_order, >>> c_n, >>> i < >>> @@ -519,10 +523,8 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ >>> { "c", "u", "pk" }; >>> sqlite3VdbeMultiLoad(v, 1, >>> "isisi", i, >>> - pIdx-> >>> - zName, >>> - index_is_unique >>> - (pIdx), >>> + pIdx->def->name, >>> + pIdx->def->opts.is_unique, >>> azOrigin >>> [pIdx-> >>> idxType], >>> diff --git a/src/box/sql/select.c b/src/box/sql/select.c >>> index 2aa35a114..2646a99c3 100644 >>> --- a/src/box/sql/select.c >>> +++ b/src/box/sql/select.c >>> @@ -4291,7 +4291,7 @@ sqlite3IndexedByLookup(Parse * pParse, struct SrcList_item *pFrom) >>> char *zIndexedBy = pFrom->u1.zIndexedBy; >>> Index *pIdx; >>> for (pIdx = pTab->pIndex; >>> - pIdx && strcmp(pIdx->zName, zIndexedBy); >>> + pIdx && strcmp(pIdx->def->name, zIndexedBy); >>> pIdx = pIdx->pNext) ; >>> if (!pIdx) { >>> sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, >>> diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h >>> index 01351a183..36b46ed4f 100644 >>> --- a/src/box/sql/sqliteInt.h >>> +++ b/src/box/sql/sqliteInt.h >>> @@ -2071,21 +2071,6 @@ struct UnpackedRecord { >>> * Each SQL index is represented in memory by an >>> * instance of the following structure. >>> * >>> - * The columns of the table that are to be indexed are described >>> - * by the aiColumn[] field of this structure. For example, suppose >>> - * we have the following table and index: >>> - * >>> - * CREATE TABLE Ex1(c1 int, c2 int, c3 text); >>> - * CREATE INDEX Ex2 ON Ex1(c3,c1); >>> - * >>> - * In the Table structure describing Ex1, nCol==3 because there are >>> - * three columns in the table. In the Index structure describing >>> - * Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed. >>> - * The value of aiColumn is {2, 0}. aiColumn[0]==2 because the >>> - * first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. >>> - * The second column to be indexed (c1) has an index of 0 in >>> - * Ex1.aCol[], hence Ex2.aiColumn[1]==0. >>> - * >>> * The Index.onError field determines whether or not the indexed columns >>> * must be unique and what to do if they are not. When Index.onError= >>> * ON_CONFLICT_ACTION_NONE, it means this is not a unique index. >>> @@ -2102,27 +2087,19 @@ struct UnpackedRecord { >>> * program is executed). See convertToWithoutRowidTable() for details. >>> */ >>> struct Index { >>> - char *zName; /* Name of this index */ >>> - i16 *aiColumn; /* Which columns are used by this index. 1st is 0 */ >>> LogEst *aiRowLogEst; /* From ANALYZE: Est. rows selected by each column */ >>> Table *pTable; /* The SQL table being indexed */ >>> char *zColAff; /* String defining the affinity of each column */ >>> Index *pNext; /* The next index associated with the same table */ >>> Schema *pSchema; /* Schema containing this index */ >>> - /** Sorting order for each column. */ >>> - enum sort_order *sort_order; >>> - /** Array of collation sequences for index. */ >>> - struct coll **coll_array; >>> - /** Array of collation identifiers. */ >>> - uint32_t *coll_id_array; >>> Expr *pPartIdxWhere; /* WHERE clause for partial indices */ >>> ExprList *aColExpr; /* Column expressions */ >>> int tnum; /* DB Page containing root of this index */ >>> - u16 nColumn; /* Number of columns stored in the index */ >>> u8 onError; /* ON_CONFLICT_ACTION_ABORT, _IGNORE, _REPLACE, >>> * or _NONE >>> */ >>> unsigned idxType:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ > 10. Will you keep an informative tarantool-style comment here? Ok, added comment. >>> + struct index_def *def; >>> }; >>> >>> /** >>> @@ -2161,11 +2138,6 @@ index_field_tuple_est(struct Index *idx, uint32_t field); >>> #define IsUniqueIndex(X) (((X)->idxType == SQLITE_IDXTYPE_UNIQUE) || \ >>> ((X)->idxType == SQLITE_IDXTYPE_PRIMARYKEY)) >>> >>> -/* The Index.aiColumn[] values are normally positive integer. But >>> - * there are some negative values that have special meaning: >>> - */ >>> -#define XN_EXPR (-2) /* Indexed column is an expression */ >>> - >>> #ifdef DEFAULT_TUPLE_COUNT >>> #undef DEFAULT_TUPLE_COUNT >>> #endif >>> @@ -3526,37 +3498,10 @@ void sqlite3AddCollateType(Parse *, Token *); >>> */ >>> struct coll * >>> sql_column_collation(struct space_def *def, uint32_t column, uint32_t *coll_id); >>> -/** >>> - * Return name of given column collation from index. >>> - * >>> - * @param idx Index which is used to fetch column. >>> - * @param column Number of column. >>> - * @param[out] coll_id Collation identifier. >>> - * @retval Pointer to collation. >>> - */ >>> -struct coll * >>> -sql_index_collation(Index *idx, uint32_t column, uint32_t *id); >>> + >>> bool >>> space_is_view(Table *); >>> >>> -/** >>> - * Return key_def of provided struct Index. >>> - * @param idx Pointer to `struct Index` object. >>> - * @retval Pointer to `struct key_def`. >>> - */ >>> -struct key_def* >>> -sql_index_key_def(struct Index *idx); >>> - >>> -/** >>> - * Return sort order of given column from index. >>> - * >>> - * @param idx Index which is used to fetch column. >>> - * @param column Number of column. >>> - * @retval Sort order of requested column. >>> - */ >>> -enum sort_order >>> -sql_index_column_sort_order(Index *idx, uint32_t column); >>> - >>> void sqlite3EndTable(Parse *, Token *, Token *, Select *); >>> int >>> emit_open_cursor(Parse *, int, int); >>> @@ -3607,8 +3552,6 @@ void sqlite3SrcListAssignCursors(Parse *, SrcList *); >>> void sqlite3IdListDelete(sqlite3 *, IdList *); >>> void sqlite3SrcListDelete(sqlite3 *, SrcList *); >>> Index *sqlite3AllocateIndexObject(sqlite3 *, i16, int, char **); >>> -bool >>> -index_is_unique(Index *); >>> >>> /** >>> * Create a new index for an SQL table. name is the name of the >>> @@ -4293,8 +4236,6 @@ int sqlite3InvokeBusyHandler(BusyHandler *); >>> int >>> sql_analysis_load(struct sqlite3 *db); >>> >>> -uint32_t >>> -index_column_count(const Index *); >>> bool >>> index_is_unique_not_null(const Index *); >>> void sqlite3RegisterLikeFunctions(sqlite3 *, int); >>> diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c >>> index e1126b2d2..ea3521133 100644 >>> --- a/src/box/sql/trigger.c >>> +++ b/src/box/sql/trigger.c >>> @@ -872,8 +872,6 @@ codeRowTrigger(Parse * pParse, /* Current parse context */ >>> pSubParse->pToplevel = pTop; >>> pSubParse->eTriggerOp = pTrigger->op; >>> pSubParse->nQueryLoop = pParse->nQueryLoop; >>> - struct region *region = &fiber()->gc; >>> - pSubParse->region_initial_size = region_used(region); >>> >>> v = sqlite3GetVdbe(pSubParse); >>> if (v) { >>> diff --git a/src/box/sql/update.c b/src/box/sql/update.c >>> index 590aad28b..6545b3b06 100644 >>> --- a/src/box/sql/update.c >>> +++ b/src/box/sql/update.c >>> @@ -237,14 +237,14 @@ sqlite3Update(Parse * pParse, /* The parser context */ >>> */ >>> for (j = 0, pIdx = pTab->pIndex; pIdx; pIdx = pIdx->pNext, j++) { >>> int reg; >>> - int nIdxCol = index_column_count(pIdx); >>> + int nIdxCol = pIdx->def->key_def->part_count; >>> if (chngPk || hasFK || pIdx->pPartIdxWhere || pIdx == pPk) { >>> reg = ++pParse->nMem; >>> pParse->nMem += nIdxCol; >>> } else { >>> reg = 0; >>> for (i = 0; i < nIdxCol; i++) { >>> - i16 iIdxCol = pIdx->aiColumn[i]; >>> + i16 iIdxCol = pIdx->def->key_def->parts[i].fieldno; >>> if (iIdxCol < 0 || aXRef[iIdxCol] >= 0) { >>> reg = ++pParse->nMem; >>> pParse->nMem += nIdxCol; >>> @@ -306,7 +306,7 @@ sqlite3Update(Parse * pParse, /* The parser context */ >>> nPk = nKey; >>> } else { >>> assert(pPk != 0); >>> - nPk = index_column_count(pPk); >>> + nPk = pPk->def->key_def->part_count; >>> } >>> iPk = pParse->nMem + 1; >>> pParse->nMem += nPk; >>> @@ -333,9 +333,9 @@ sqlite3Update(Parse * pParse, /* The parser context */ >>> } >>> } else { >>> for (i = 0; i < nPk; i++) { >>> - assert(pPk->aiColumn[i] >= 0); >>> sqlite3ExprCodeGetColumnOfTable(v, pTab->def, iDataCur, >>> - pPk->aiColumn[i], >>> + pPk->def->key_def-> >>> + parts[i].fieldno, >>> iPk + i); >>> } >>> } >>> diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c >>> index 679bd0bc1..520b309d9 100644 >>> --- a/src/box/sql/vdbeaux.c >>> +++ b/src/box/sql/vdbeaux.c >>> @@ -1165,7 +1165,7 @@ sql_vdbe_set_p4_key_def(struct Parse *parse, struct Index *idx) >>> struct Vdbe *v = parse->pVdbe; >>> assert(v != NULL); >>> assert(idx != NULL); >>> - struct key_def *def = key_def_dup(sql_index_key_def(idx)); >>> + struct key_def *def = key_def_dup(idx->def->key_def); >>> if (def == NULL) >>> sqlite3OomFault(parse->db); >>> else >>> diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c >>> index f408b7701..51b5d516e 100644 >>> --- a/src/box/sql/vdbemem.c >>> +++ b/src/box/sql/vdbemem.c >>> @@ -1087,7 +1087,7 @@ valueNew(sqlite3 * db, struct ValueNewStat4Ctx *p) >>> Index *pIdx = p->pIdx; /* Index being probed */ >>> int nByte; /* Bytes of space to allocate */ >>> int i; /* Counter variable */ >>> - int nCol = index_column_count(pIdx); >>> + int nCol = pIdx->def->key_def->part_count; >>> >>> nByte = sizeof(Mem) * nCol + >>> ROUND8(sizeof(UnpackedRecord)); >>> @@ -1095,7 +1095,7 @@ valueNew(sqlite3 * db, struct ValueNewStat4Ctx *p) >>> (UnpackedRecord *) sqlite3DbMallocZero(db, nByte); >>> if (pRec == NULL) >>> return NULL; >>> - pRec->key_def = key_def_dup(sql_index_key_def(pIdx)); >>> + pRec->key_def = key_def_dup(pIdx->def->key_def); >>> if (pRec->key_def == NULL) { >>> sqlite3DbFree(db, pRec); >>> sqlite3OomFault(db); >>> diff --git a/src/box/sql/where.c b/src/box/sql/where.c >>> index e79164781..9f5de50f9 100644 >>> --- a/src/box/sql/where.c >>> +++ b/src/box/sql/where.c >>> @@ -265,11 +265,6 @@ whereScanNext(WhereScan * pScan) >>> for (pTerm = pWC->a + k; k < pWC->nTerm; k++, pTerm++) { >>> if (pTerm->leftCursor == iCur >>> && pTerm->u.leftColumn == iColumn >>> - && (iColumn != XN_EXPR >>> - || sqlite3ExprCompare(pTerm->pExpr-> >>> - pLeft, >>> - pScan->pIdxExpr, >>> - iCur) == 0) >>> && (pScan->iEquiv <= 1 >>> || !ExprHasProperty(pTerm->pExpr, >>> EP_FromJoin)) >>> @@ -376,19 +371,21 @@ whereScanInit(WhereScan * pScan, /* The WhereScan object being initialized */ >>> pScan->is_column_seen = false; >>> if (pIdx) { >>> int j = iColumn; >>> - iColumn = pIdx->aiColumn[j]; >>> - if (iColumn == XN_EXPR) { >>> - pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; >>> - } else if (iColumn >= 0) { >>> + iColumn = pIdx->def->key_def->parts[j].fieldno; >>> + /* >>> + * pIdx->tnum == 0 means that pIdx is a fake integer >>> + * primary key index >>> + */ > 11. Out of comment-type margin > - * pIdx->tnum == 0 means that pIdx is a fake integer > - * primary key index > + * pIdx->tnum == 0 means that pIdx is a fake > + * integer primary key index. Fixed. >>> + if (pIdx->tnum == 0) >>> + iColumn = -1; >>> + >>> + if (iColumn >= 0) { >>> char affinity = >>> pIdx->pTable->def->fields[iColumn].affinity; >>> pScan->idxaff = affinity; >>> - uint32_t id; >>> - pScan->coll = sql_index_collation(pIdx, j, &id); >>> + pScan->coll = pIdx->def->key_def->parts[j].coll; >>> pScan->is_column_seen = true; >>> } >>> - } else if (iColumn == XN_EXPR) { >>> - return 0; >>> } >>> pScan->opMask = opMask; >>> pScan->k = 0; >>> @@ -464,18 +461,17 @@ findIndexCol(Parse * pParse, /* Parse context */ >>> Index * pIdx, /* Index to match column of */ >>> int iCol) /* Column of index to match */ >>> { >>> + struct key_part *part_to_match = &pIdx->def->key_def->parts[iCol]; >>> for (int i = 0; i < pList->nExpr; i++) { >>> Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr); >>> - if (p->op == TK_COLUMN && >>> - p->iColumn == pIdx->aiColumn[iCol] && >>> - p->iTable == iBase) { >>> + if (p->op == TK_COLUMN && p->iTable == iBase && >>> + p->iColumn == (int) part_to_match->fieldno) { >>> bool is_found; >>> uint32_t id; >>> struct coll *coll = sql_expr_coll(pParse, >>> pList->a[i].pExpr, >>> &is_found, &id); >>> - if (is_found && >>> - coll == sql_index_collation(pIdx, iCol, &id)) { >>> + if (is_found && coll == part_to_match->coll) { >>> return i; >>> } > 12. Extra braces: > - if (is_found && coll == part_to_match->coll) { > + if (is_found && coll == part_to_match->coll) > return i; > - } Fixed. >>> } >>> @@ -484,27 +480,6 @@ findIndexCol(Parse * pParse, /* Parse context */ >>> return -1; >>> } >>> >>> -/* >>> - * Return TRUE if the iCol-th column of index pIdx is NOT NULL >>> - */ >>> -static int >>> -indexColumnNotNull(Index * pIdx, int iCol) >>> -{ >>> - int j; >>> - assert(pIdx != 0); >>> - assert(iCol >= 0 && iCol < (int)index_column_count(pIdx)); >>> - j = pIdx->aiColumn[iCol]; >>> - if (j >= 0) { >>> - return !pIdx->pTable->def->fields[j].is_nullable; >>> - } else if (j == (-1)) { >>> - return 1; >>> - } else { >>> - assert(j == (-2)); >>> - return 0; /* Assume an indexed expression can always yield a NULL */ >>> - >>> - } >>> -} >>> - >>> /* >>> * Return true if the DISTINCT expression-list passed as the third argument >>> * is redundant. >>> @@ -556,9 +531,9 @@ isDistinctRedundant(Parse * pParse, /* Parsing context */ >>> * contain a "col=X" term are subject to a NOT NULL constraint. >>> */ >>> for (pIdx = pTab->pIndex; pIdx; pIdx = pIdx->pNext) { >>> - if (!index_is_unique(pIdx)) >>> + if (!pIdx->def->opts.is_unique) >>> continue; >>> - int col_count = index_column_count(pIdx); >>> + int col_count = pIdx->def->key_def->part_count; >>> for (i = 0; i < col_count; i++) { >>> if (0 == >>> sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask) 0, >>> @@ -566,11 +541,12 @@ isDistinctRedundant(Parse * pParse, /* Parsing context */ >>> if (findIndexCol >>> (pParse, pDistinct, iBase, pIdx, i) < 0) >>> break; >>> - if (indexColumnNotNull(pIdx, i) == 0) >>> + uint32_t j = pIdx->def->key_def->parts[i].fieldno; >>> + if (!pIdx->pTable->def->fields[j].is_nullable == 0) > 13. !.. == 0 is looking confusing for me.. Please, fix it. Fixed. >>> break; >>> } >>> } >>> - if (i == (int)index_column_count(pIdx)) { >>> + if (i == (int) pIdx->def->key_def->part_count) { >>> /* This index implies that the DISTINCT qualifier is redundant. */ >>> return 1; >>> } >>> @@ -1107,7 +1083,7 @@ whereRangeAdjust(WhereTerm * pTerm, LogEst nNew) >>> char >>> sqlite3IndexColumnAffinity(sqlite3 * db, Index * pIdx, int iCol) >>> { >>> - assert(iCol >= 0 && iCol < (int)index_column_count(pIdx)); >>> + assert(iCol >= 0 && iCol < (int) pIdx->def->key_def->part_count); >>> if (!pIdx->zColAff) { >>> if (sqlite3IndexAffinityStr(db, pIdx) == 0) >>> return AFFINITY_BLOB; >>> @@ -1169,13 +1145,12 @@ whereRangeSkipScanEst(Parse * pParse, /* Parsing & code generating context */ >>> int nUpper = index->def->opts.stat->sample_count + 1; >>> int rc = SQLITE_OK; >>> u8 aff = sqlite3IndexColumnAffinity(db, p, nEq); >>> - uint32_t id; >>> >>> sqlite3_value *p1 = 0; /* Value extracted from pLower */ >>> sqlite3_value *p2 = 0; /* Value extracted from pUpper */ >>> sqlite3_value *pVal = 0; /* Value extracted from record */ >>> >>> - struct coll *pColl = sql_index_collation(p, nEq, &id); >>> + struct coll *pColl = p->def->key_def->parts[nEq].coll; >>> if (pLower) { >>> rc = sqlite3Stat4ValueFromExpr(pParse, pLower->pExpr->pRight, >>> aff, &p1); >>> @@ -1371,7 +1346,7 @@ whereRangeScanEst(Parse * pParse, /* Parsing & code generating context */ >>> || (pLower->eOperator & (WO_GT | WO_GE)) != 0); >>> assert(pUpper == 0 >>> || (pUpper->eOperator & (WO_LT | WO_LE)) != 0); >>> - if (sql_index_column_sort_order(p, nEq) != >>> + if (p->def->key_def->parts[nEq].sort_order != >>> SORT_ORDER_ASC) { >>> /* The roles of pLower and pUpper are swapped for a DESC index */ >>> SWAP(pLower, pUpper); >>> @@ -1521,7 +1496,7 @@ whereEqualScanEst(Parse * pParse, /* Parsing & code generating context */ >>> int bOk; >>> >>> assert(nEq >= 1); >>> - assert(nEq <= (int)index_column_count(p)); >>> + assert(nEq <= (int) p->def->key_def->part_count); >>> assert(pBuilder->nRecValid < nEq); >>> >>> /* If values are not available for all fields of the index to the left >>> @@ -1542,7 +1517,7 @@ whereEqualScanEst(Parse * pParse, /* Parsing & code generating context */ >>> >>> whereKeyStats(pParse, p, pRec, 0, a); >>> WHERETRACE(0x10, ("equality scan regions %s(%d): %d\n", >>> - p->zName, nEq - 1, (int)a[1])); >>> + p->def->name, nEq - 1, (int)a[1])); >>> *pnRow = a[1]; >>> >>> return rc; >>> @@ -1674,7 +1649,7 @@ whereLoopPrint(WhereLoop * p, WhereClause * pWC) >>> pItem->zAlias ? pItem->zAlias : pTab->def->name); >>> #endif >>> const char *zName; >>> - if (p->pIndex && (zName = p->pIndex->zName) != 0) { >>> + if (p->pIndex && (zName = p->pIndex->def->name) != 0) { >>> if (strncmp(zName, "sqlite_autoindex_", 17) == 0) { >>> int i = sqlite3Strlen30(zName) - 1; >>> while (zName[i] != '_') >>> @@ -2236,7 +2211,7 @@ whereRangeVectorLen(Parse * pParse, /* Parsing context */ >>> int nCmp = sqlite3ExprVectorSize(pTerm->pExpr->pLeft); >>> int i; >>> >>> - nCmp = MIN(nCmp, (int)(index_column_count(pIdx) - nEq)); >>> + nCmp = MIN(nCmp, (int)(pIdx->def->key_def->part_count - nEq)); >>> for (i = 1; i < nCmp; i++) { >>> /* Test if comparison i of pTerm is compatible with column (i+nEq) >>> * of the index. If not, exit the loop. >>> @@ -2257,11 +2232,10 @@ whereRangeVectorLen(Parse * pParse, /* Parsing context */ >>> * order of the index column is the same as the sort order of the >>> * leftmost index column. >>> */ >>> - if (pLhs->op != TK_COLUMN >>> - || pLhs->iTable != iCur >>> - || pLhs->iColumn != pIdx->aiColumn[i + nEq] >>> - || sql_index_column_sort_order(pIdx, i + nEq) != >>> - sql_index_column_sort_order(pIdx, nEq)) { >>> + if (pLhs->op != TK_COLUMN || pLhs->iTable != iCur >>> + || pLhs->iColumn != (int)pIdx->def->key_def->parts[i + nEq].fieldno >>> + || pIdx->def->key_def->parts[i + nEq].sort_order != >>> + pIdx->def->key_def->parts[nEq].sort_order) { >>> break; >>> } > 14. Extra braces: > - pIdx->def->key_def->parts[nEq].sort_order) { > + pIdx->def->key_def->parts[nEq].sort_order) > break; > - } Fixed. >>> >>> @@ -2275,7 +2249,7 @@ whereRangeVectorLen(Parse * pParse, /* Parsing context */ >>> pColl = sql_binary_compare_coll_seq(pParse, pLhs, pRhs, &id); >>> if (pColl == 0) >>> break; >>> - if (sql_index_collation(pIdx, i + nEq, &id) != pColl) >>> + if (pIdx->def->key_def->parts[(i + nEq)].coll != pColl) >>> break; >>> } >>> return i; >>> @@ -2318,13 +2292,13 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder, /* The WhereLoop factory */ >>> LogEst rSize; /* Number of rows in the table */ >>> LogEst rLogSize; /* Logarithm of table size */ >>> WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ >>> - uint32_t nProbeCol = index_column_count(pProbe); >>> + uint32_t nProbeCol = pProbe->def->key_def->part_count; >>> >>> pNew = pBuilder->pNew; >>> if (db->mallocFailed) >>> return SQLITE_NOMEM_BKPT; >>> WHERETRACE(0x800, ("BEGIN addBtreeIdx(%s), nEq=%d\n", >>> - pProbe->zName, pNew->nEq)); >>> + pProbe->def->name, pNew->nEq)); >>> >>> assert((pNew->wsFlags & WHERE_TOP_LIMIT) == 0); >>> if (pNew->wsFlags & WHERE_BTM_LIMIT) { >>> @@ -2374,8 +2348,9 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder, /* The WhereLoop factory */ >>> LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */ >>> int nIn = 0; >>> int nRecValid = pBuilder->nRecValid; >>> + uint32_t j = pProbe->def->key_def->parts[saved_nEq].fieldno; >>> if ((eOp == WO_ISNULL || (pTerm->wtFlags & TERM_VNULL) != 0) >>> - && indexColumnNotNull(pProbe, saved_nEq) >>> + && !pProbe->pTable->def->fields[j].is_nullable >>> ) { >>> continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */ >>> } >>> @@ -2445,14 +2420,16 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder, /* The WhereLoop factory */ >>> */ >>> } >>> } else if (eOp & WO_EQ) { >>> - int iCol = pProbe->aiColumn[saved_nEq]; >>> + int iCol = pProbe->def->key_def->parts[saved_nEq].fieldno; >>> pNew->wsFlags |= WHERE_COLUMN_EQ; >>> assert(saved_nEq == pNew->nEq); >>> - if ((iCol > 0 && nInMul == 0 >>> - && saved_nEq == nProbeCol - 1) >>> - ) { >>> - if (iCol >= 0 && >>> - !index_is_unique_not_null(pProbe)) { >>> + if ((iCol > 0 && nInMul == 0 && >>> + saved_nEq == nProbeCol - 1)) { >>> + bool index_is_unique_not_null = >>> + pProbe->def->key_def->is_nullable && >>> + pProbe->def->opts.is_unique; >>> + if (pProbe->tnum != 0 && >>> + !index_is_unique_not_null) { >>> pNew->wsFlags |= WHERE_UNQ_WANTED; >>> } else { >>> pNew->wsFlags |= WHERE_ONEROW; >>> @@ -2514,8 +2491,7 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder, /* The WhereLoop factory */ >>> assert(eOp & (WO_ISNULL | WO_EQ | WO_IN)); >>> >>> assert(pNew->nOut == saved_nOut); >>> - if (pTerm->truthProb <= 0 >>> - && pProbe->aiColumn[saved_nEq] >= 0) { >>> + if (pTerm->truthProb <= 0 && pProbe->tnum != 0 ) { >>> assert((eOp & WO_IN) || nIn == 0); >>> testcase(eOp & WO_IN); >>> pNew->nOut += pTerm->truthProb; >>> @@ -2671,7 +2647,7 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder, /* The WhereLoop factory */ >>> } >>> >>> WHERETRACE(0x800, ("END addBtreeIdx(%s), nEq=%d, rc=%d\n", >>> - pProbe->zName, saved_nEq, rc)); >>> + pProbe->def->name, saved_nEq, rc)); >>> return rc; >>> } >>> >>> @@ -2715,7 +2691,7 @@ indexMightHelpWithOrderBy(WhereLoopBuilder * pBuilder, >>> ExprList *pOB; >>> ExprList *aColExpr; >>> int ii, jj; >>> - int nIdxCol = index_column_count(pIndex); >>> + int nIdxCol = pIndex->def->key_def->part_count; >>> if (index_is_unordered(pIndex)) >>> return 0; >>> if ((pOB = pBuilder->pWInfo->pOrderBy) == 0) >>> @@ -2726,13 +2702,12 @@ indexMightHelpWithOrderBy(WhereLoopBuilder * pBuilder, >>> if (pExpr->iColumn < 0) >>> return 1; >>> for (jj = 0; jj < nIdxCol; jj++) { >>> - if (pExpr->iColumn == pIndex->aiColumn[jj]) >>> + if (pExpr->iColumn == (int) >>> + pIndex->def->key_def->parts[jj].fieldno) >>> return 1; >>> } >>> } else if ((aColExpr = pIndex->aColExpr) != 0) { >>> for (jj = 0; jj < nIdxCol; jj++) { >>> - if (pIndex->aiColumn[jj] != XN_EXPR) >>> - continue; >>> if (sqlite3ExprCompare >>> (pExpr, aColExpr->a[jj].pExpr, >>> iCursor) == 0) { >>> @@ -2815,7 +2790,6 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ >>> Index *pProbe; /* An index we are evaluating */ >>> Index sPk; /* A fake index object for the primary key */ >>> LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ >>> - i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */ >>> SrcList *pTabList; /* The FROM clause */ >>> struct SrcList_item *pSrc; /* The FROM clause btree term to add */ >>> WhereLoop *pNew; /* Template WhereLoop object */ >>> @@ -2846,11 +2820,27 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ >>> */ >>> Index *pFirst; /* First of real indices on the table */ >>> memset(&sPk, 0, sizeof(Index)); >>> - sPk.nColumn = 1; >>> - sPk.aiColumn = &aiColumnPk; >>> sPk.aiRowLogEst = aiRowEstPk; >>> sPk.onError = ON_CONFLICT_ACTION_REPLACE; >>> sPk.pTable = pTab; >>> + >>> + struct key_def *key_def = key_def_new(1); >>> + if (key_def == NULL) >>> + return SQLITE_ERROR; >>> + >>> + key_def_set_part(key_def, 0, 0, pTab->def->fields[0].type, >>> + ON_CONFLICT_ACTION_ABORT, >>> + NULL, COLL_NONE, SORT_ORDER_ASC); >>> + >>> + struct index_opts index_opts = index_opts_default; >>> + >>> + sPk.def = index_def_new(pTab->def->id, 0, "primary", >>> + sizeof("primary") - 1, TREE, &index_opts, >>> + key_def, NULL); >>> + >>> + if (sPk.def == NULL) >>> + return SQLITE_ERROR; > 15. key_def is leaking here, same as in other errors bellow and at the end of the function. Fixed. >>> + >>> aiRowEstPk[0] = sql_space_tuple_log_count(pTab); >>> aiRowEstPk[1] = 0; >>> pFirst = pSrc->pTab->pIndex; >>> @@ -3325,8 +3315,8 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ >>> index_is_unordered(pIndex)) { >>> return 0; >>> } else { >>> - nColumn = index_column_count(pIndex); >>> - isOrderDistinct = index_is_unique(pIndex); >>> + nColumn = pIndex->def->key_def->part_count; >>> + isOrderDistinct = pIndex->def->opts.is_unique; >>> } >>> >>> /* Loop through all columns of the index and deal with the ones >>> @@ -3387,9 +3377,10 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ >>> * (revIdx) for the j-th column of the index. >>> */ >>> if (pIndex) { >>> - iColumn = pIndex->aiColumn[j]; >>> - revIdx = sql_index_column_sort_order(pIndex, >>> - j); >>> + iColumn = pIndex->def->key_def-> >>> + parts[j].fieldno; >>> + revIdx = pIndex->def->key_def-> >>> + parts[j].sort_order; >>> if (iColumn == pIndex->pTable->iPKey) >>> iColumn = -1; >>> } else { >>> @@ -3442,8 +3433,7 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */ >>> pOrderBy->a[i].pExpr, >>> &is_found, &id); >>> struct coll *idx_coll = >>> - sql_index_collation(pIndex, >>> - j, &id); >>> + pIndex->def->key_def->parts[j].coll; >>> if (is_found && >>> coll != idx_coll) >>> continue; >>> @@ -4105,13 +4095,13 @@ whereShortCut(WhereLoopBuilder * pBuilder) >>> } else { >>> for (pIdx = pTab->pIndex; pIdx; pIdx = pIdx->pNext) { >>> int opMask; >>> - int nIdxCol = index_column_count(pIdx); >>> + int nIdxCol = pIdx->def->key_def->part_count; >>> assert(pLoop->aLTermSpace == pLoop->aLTerm); >>> - if (!index_is_unique(pIdx) >>> + if (!pIdx->def->opts.is_unique >>> || pIdx->pPartIdxWhere != 0 >>> - || nIdxCol > ArraySize(pLoop->aLTermSpace) >>> - ) >>> + || nIdxCol > ArraySize(pLoop->aLTermSpace)) { >>> continue; >>> + } >>> opMask = WO_EQ; >>> for (j = 0; j < nIdxCol; j++) { >>> pTerm = >>> @@ -4650,7 +4640,7 @@ sqlite3WhereBegin(Parse * pParse, /* The parser context */ >>> wctrlFlags & WHERE_ORDERBY_MIN) == 0) { >>> sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */ >>> } >>> - VdbeComment((v, "%s", pIx->zName)); >>> + VdbeComment((v, "%s", pIx->def->name)); >>> #ifdef SQLITE_ENABLE_COLUMN_USED_MASK >>> { >>> u64 colUsed = 0; >>> @@ -4781,7 +4771,7 @@ sqlite3WhereEnd(WhereInfo * pWInfo) >>> if (pLevel->addrSkip) { >>> sqlite3VdbeGoto(v, pLevel->addrSkip); >>> VdbeComment((v, "next skip-scan on %s", >>> - pLoop->pIndex->zName)); >>> + pLoop->pIndex->def->name)); >>> sqlite3VdbeJumpHere(v, pLevel->addrSkip); >>> sqlite3VdbeJumpHere(v, pLevel->addrSkip - 2); >>> } >>> diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c >>> index 09b267194..22bb76013 100644 >>> --- a/src/box/sql/wherecode.c >>> +++ b/src/box/sql/wherecode.c >>> @@ -47,9 +47,7 @@ >>> static const char * >>> explainIndexColumnName(Index * pIdx, int i) >>> { >>> - i = pIdx->aiColumn[i]; >>> - if (i == XN_EXPR) >>> - return ""; >>> + i = pIdx->def->key_def->parts[i].fieldno; >>> return pIdx->pTable->def->fields[i].name; >>> } >>> >>> @@ -222,7 +220,7 @@ sqlite3WhereExplainOneScan(Parse * pParse, /* Parse context */ >>> } >>> if (zFmt) { >>> sqlite3StrAccumAppend(&str, " USING ", 7); >>> - sqlite3XPrintf(&str, zFmt, pIdx->zName); >>> + sqlite3XPrintf(&str, zFmt, pIdx->def->name); >>> explainIndexRange(&str, pLoop); >>> } >>> } else if ((flags & WHERE_IPK) != 0 >>> @@ -463,7 +461,7 @@ codeEqualityTerm(Parse * pParse, /* The parsing context */ >>> int *aiMap = 0; >>> >>> if (pLoop->pIndex != 0 && >>> - sql_index_column_sort_order(pLoop->pIndex, iEq)) { >>> + pLoop->pIndex->def->key_def->parts[iEq].sort_order) { >>> testcase(iEq == 0); >>> testcase(bRev); >>> bRev = !bRev; >>> @@ -708,7 +706,7 @@ codeAllEqualityTerms(Parse * pParse, /* Parsing context */ >>> sqlite3VdbeAddOp1(v, (bRev ? OP_Last : OP_Rewind), iIdxCur); >>> VdbeCoverageIf(v, bRev == 0); >>> VdbeCoverageIf(v, bRev != 0); >>> - VdbeComment((v, "begin skip-scan on %s", pIdx->zName)); >>> + VdbeComment((v, "begin skip-scan on %s", pIdx->def->name)); >>> j = sqlite3VdbeAddOp0(v, OP_Goto); >>> pLevel->addrSkip = >>> sqlite3VdbeAddOp4Int(v, (bRev ? OP_SeekLT : OP_SeekGT), >>> @@ -718,8 +716,8 @@ codeAllEqualityTerms(Parse * pParse, /* Parsing context */ >>> sqlite3VdbeJumpHere(v, j); >>> for (j = 0; j < nSkip; j++) { >>> sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, >>> - pIdx->aiColumn[j], regBase + j); >>> - testcase(pIdx->aiColumn[j] == XN_EXPR); >>> + pIdx->def->key_def->parts[j].fieldno, >>> + regBase + j); >>> VdbeComment((v, "%s", explainIndexColumnName(pIdx, j))); >>> } >>> } >>> @@ -1245,10 +1243,10 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t >>> assert(pWInfo->pOrderBy == 0 >>> || pWInfo->pOrderBy->nExpr == 1 >>> || (pWInfo->wctrlFlags & WHERE_ORDERBY_MIN) == 0); >>> - int nIdxCol = index_column_count(pIdx); >>> + int nIdxCol = pIdx->def->key_def->part_count; >>> if ((pWInfo->wctrlFlags & WHERE_ORDERBY_MIN) != 0 >>> && pWInfo->nOBSat > 0 && (nIdxCol > nEq)) { >>> - j = pIdx->aiColumn[nEq]; >>> + j = pIdx->def->key_def->parts[nEq].fieldno; >>> /* Allow seek for column with `NOT NULL` == false attribute. >>> * If a column may contain NULL-s, the comparator installed >>> * by Tarantool is prepared to seek using a NULL value. >>> @@ -1259,8 +1257,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t >>> * FYI: entries in an index are ordered as follows: >>> * NULL, ... NULL, min_value, ... >>> */ >>> - if ((j >= 0 && pIdx->pTable->def->fields[j].is_nullable) >>> - || j == XN_EXPR) { >>> + if (pIdx->pTable->def->fields[j].is_nullable) { >>> assert(pLoop->nSkip == 0); >>> bSeekPastNull = 1; >>> nExtraReg = 1; >>> @@ -1299,17 +1296,15 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t >>> assert((bRev & ~1) == 0); >>> pLevel->iLikeRepCntr <<= 1; >>> pLevel->iLikeRepCntr |= >>> - bRev ^ (sql_index_column_sort_order(pIdx, nEq) == >>> + bRev ^ (pIdx->def->key_def-> >>> + parts[nEq].sort_order == >>> SORT_ORDER_DESC); >>> } >>> #endif >>> if (pRangeStart == 0) { >>> - j = pIdx->aiColumn[nEq]; >>> - if ((j >= 0 && >>> - pIdx->pTable->def->fields[j].is_nullable)|| >>> - j == XN_EXPR) { >>> + j = pIdx->def->key_def->parts[nEq].fieldno; >>> + if (pIdx->pTable->def->fields[j].is_nullable) >>> bSeekPastNull = 1; >>> - } >>> } >>> } >>> assert(pRangeEnd == 0 >>> @@ -1320,7 +1315,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t >>> * start and end terms (pRangeStart and pRangeEnd). >>> */ >>> if ((nEq < nIdxCol && >>> - bRev == (sql_index_column_sort_order(pIdx, nEq) == >>> + bRev == (pIdx->def->key_def->parts[nEq].sort_order == >>> SORT_ORDER_ASC)) || >>> (bRev && nIdxCol == nEq)) { >>> SWAP(pRangeEnd, pRangeStart); >>> @@ -1386,9 +1381,10 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t >>> } >>> struct Index *pk = sqlite3PrimaryKeyIndex(pIdx->pTable); >>> assert(pk); >>> - int nPkCol = index_column_count(pk); >>> + int nPkCol = pk->def->key_def->part_count; >>> + uint32_t zero_fieldno = pk->def->key_def->parts[0].fieldno; >>> char affinity = >>> - pIdx->pTable->def->fields[pk->aiColumn[0]].affinity; >>> + pIdx->pTable->def->fields[zero_fieldno].affinity; >>> if (nPkCol == 1 && affinity == AFFINITY_INTEGER) { >>> /* Right now INTEGER PRIMARY KEY is the only option to >>> * get Tarantool's INTEGER column type. Need special handling >>> @@ -1397,7 +1393,8 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t >>> */ >>> int limit = pRangeStart == NULL ? nEq : nEq + 1; >>> for (int i = 0; i < limit; i++) { >>> - if (pIdx->aiColumn[i] == pk->aiColumn[0]) { >>> + if (pIdx->def->key_def->parts[i].fieldno == >>> + zero_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. */ >>> @@ -1506,10 +1503,10 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t >>> /* pIdx is a covering index. No need to access the main table. */ >>> } else if (iCur != iIdxCur) { >>> Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); >>> - int nPkCol = index_column_count(pPk); >>> + int nPkCol = pPk->def->key_def->part_count; >>> int iKeyReg = sqlite3GetTempRange(pParse, nPkCol); >>> for (j = 0; j < nPkCol; j++) { >>> - k = pPk->aiColumn[j]; >>> + k = pPk->def->key_def->parts[j].fieldno; >>> sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, >>> iKeyReg + j); >>> } >>> @@ -1614,7 +1611,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t >>> */ >>> if ((pWInfo->wctrlFlags & WHERE_DUPLICATES_OK) == 0) { >>> Index *pPk = sqlite3PrimaryKeyIndex(pTab); >>> - int nPkCol = index_column_count(pPk); >>> + int nPkCol = pPk->def->key_def->part_count; >>> regRowset = pParse->nTab++; >>> sqlite3VdbeAddOp2(v, OP_OpenTEphemeral, >>> regRowset, nPkCol); >>> @@ -1718,13 +1715,16 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t >>> int iSet = >>> ((ii == pOrWc->nTerm - 1) ? -1 : ii); >>> Index *pPk = sqlite3PrimaryKeyIndex (pTab); >>> - int nPk = index_column_count(pPk); >>> + int nPk = pPk->def->key_def->part_count; >>> int iPk; >>> >>> /* Read the PK into an array of temp registers. */ >>> r = sqlite3GetTempRange(pParse, nPk); >>> for (iPk = 0; iPk < nPk; iPk++) { >>> - int iCol = pPk->aiColumn[iPk]; >>> + int iCol = pPk->def-> >>> + key_def-> >>> + parts[iPk]. >>> + fieldno; >>> sqlite3ExprCodeGetColumnToReg >>> (pParse, pTab->def, >>> iCol, iCur, >>> diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c >>> index aa6d4524d..40e4e2577 100644 >>> --- a/src/box/sql/whereexpr.c >>> +++ b/src/box/sql/whereexpr.c >>> @@ -903,7 +903,6 @@ exprMightBeIndexed(SrcList * pFrom, /* The FROM clause */ >>> int *piColumn /* Write the referenced table column number here */ >>> ) >>> { >>> - Index *pIdx; >>> int i; >>> int iCur; >>> >>> @@ -930,20 +929,6 @@ exprMightBeIndexed(SrcList * pFrom, /* The FROM clause */ >>> for (i = 0; mPrereq > 1; i++, mPrereq >>= 1) { >>> } >>> iCur = pFrom->a[i].iCursor; >>> - for (pIdx = pFrom->a[i].pTab->pIndex; pIdx; pIdx = pIdx->pNext) { >>> - if (pIdx->aColExpr == 0) >>> - continue; >>> - for (i = 0; i < pIdx->nColumn; i++) { >>> - if (pIdx->aiColumn[i] != XN_EXPR) >>> - continue; >>> - if (sqlite3ExprCompare >>> - (pExpr, pIdx->aColExpr->a[i].pExpr, iCur) == 0) { >>> - *piCur = iCur; >>> - *piColumn = XN_EXPR; >>> - return 1; >>> - } >>> - } >>> - } > 16. You don't need iCur anymore; please delete it and SrcList * pFrom argument that would come useless. > Please don't dorget to beautify function head to match our codestyle as you are going to touch it. Not actual after rebase onto master. >>> return 0; >>> } >>> >>> -- Here is the patch: -- sql: add index_def to Index Now every sqlite struct Index is created with tnt struct index_def inside. This allows us to use tnt index_def in work with sqlite indexes in the same manner as with tnt index and is a step to remove sqlite Index with tnt index. Fields coll_array, coll_id_array, aiColumn, sort_order and zName are removed from Index. All usages of this fields changed to usage of corresponding index_def fields. index_is_unique(), sql_index_collation() and index_column_count() are removed with calls of index_def corresponding fields. Closes: #3369 --- Branch: https://github.com/tarantool/tarantool/tree/sb/gh-3369-use-index-def-in-select-and-where Issue: https://github.com/tarantool/tarantool/issues/3369  src/box/sql.c           |  54 +++---  src/box/sql/analyze.c   |  40 ++--  src/box/sql/build.c     | 488 ++++++++++++++++++++++++------------------------  src/box/sql/delete.c    |  10 +-  src/box/sql/expr.c      |  48 ++---  src/box/sql/fkey.c      |  48 ++---  src/box/sql/insert.c    |  76 ++++----  src/box/sql/pragma.c    |  28 +--  src/box/sql/select.c    |   2 +-  src/box/sql/sqliteInt.h |  74 ++------  src/box/sql/trigger.c   |   2 -  src/box/sql/update.c    |  10 +-  src/box/sql/vdbeaux.c   |   2 +-  src/box/sql/vdbemem.c   |   4 +-  src/box/sql/where.c     | 151 +++++++--------  src/box/sql/wherecode.c |  51 ++---  16 files changed, 517 insertions(+), 571 deletions(-) diff --git a/src/box/sql.c b/src/box/sql.c index 82f3d6d52..a24812c65 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -1452,8 +1452,8 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)      /* If table's PK is single column which is INTEGER, then       * treat it as strict type, not affinity.  */ -    if (pk_idx && pk_idx->nColumn == 1) { -        int pk = pk_idx->aiColumn[0]; +    if (pk_idx != NULL && pk_idx->def->key_def->part_count == 1) { +        int pk = pk_idx->def->key_def->parts[0].fieldno;          if (def->fields[pk].type == FIELD_TYPE_INTEGER)              pk_forced_int = pk;      } @@ -1564,20 +1564,19 @@ tarantoolSqlite3MakeTableOpts(Table *pTable, const char *zSql, char *buf)   */  int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf)  { -    struct space_def *def = pIndex->pTable->def; -    assert(def != NULL); +    struct field_def *fields = pIndex->pTable->def->fields; +    struct key_def *key_def = pIndex->def->key_def;      const struct Enc *enc = get_enc(buf); -    struct SqliteIndex *primary_index; -    char *base = buf, *p; -    int pk_forced_int = -1; - -    primary_index = sqlite3PrimaryKeyIndex(pIndex->pTable); +    char *base = buf; +    uint32_t pk_forced_int = UINT32_MAX; +    struct SqliteIndex *primary_index = +        sqlite3PrimaryKeyIndex(pIndex->pTable);      /* If table's PK is single column which is INTEGER, then       * treat it as strict type, not affinity.  */ -    if (primary_index->nColumn == 1) { -        int pk = primary_index->aiColumn[0]; -        if (def->fields[pk].type == FIELD_TYPE_INTEGER) +    if (primary_index->def->key_def->part_count == 1) { +        int pk = primary_index->def->key_def->parts[0].fieldno; +        if (fields[pk].type == FIELD_TYPE_INTEGER)              pk_forced_int = pk;      } @@ -1587,46 +1586,45 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf)       * primary key columns. Query planner depends on this particular       * data layout.       */ -    int i, n = pIndex->nColumn; - -    p = enc->encode_array(base, n); -    for (i = 0; i < n; i++) { -        int col = pIndex->aiColumn[i]; -        assert(def->fields[col].is_nullable == - action_is_nullable(def->fields[col].nullable_action)); +    struct key_part *part = key_def->parts; +    char *p = enc->encode_array(base, key_def->part_count); +    for (uint32_t i = 0; i < key_def->part_count; ++i, ++part) { +        uint32_t col = part->fieldno; +        assert(fields[col].is_nullable == +               action_is_nullable(fields[col].nullable_action));          const char *t;          if (pk_forced_int == col) {              t = "integer";          } else { -            enum affinity_type affinity = def->fields[col].affinity; -            t = convertSqliteAffinity(affinity, -                          def->fields[col].is_nullable); +            t = convertSqliteAffinity(fields[col].affinity, +                          fields[col].is_nullable);          }          /* do not decode default collation */ -        uint32_t cid = pIndex->coll_id_array[i]; +        uint32_t cid = part->coll_id;          p = enc->encode_map(p, cid == COLL_NONE ? 5 : 6);          p = enc->encode_str(p, "type", sizeof("type")-1);          p = enc->encode_str(p, t, strlen(t));          p = enc->encode_str(p, "field", sizeof("field")-1);          p = enc->encode_uint(p, col);          if (cid != COLL_NONE) { -            p = enc->encode_str(p, "collation", sizeof("collation")-1); +            p = enc->encode_str(p, "collation", +                        sizeof("collation") - 1);              p = enc->encode_uint(p, cid);          }          p = enc->encode_str(p, "is_nullable", 11); -        p = enc->encode_bool(p, def->fields[col].is_nullable); +        p = enc->encode_bool(p, fields[col].is_nullable);          p = enc->encode_str(p, "nullable_action", 15);          const char *action_str = - on_conflict_action_strs[def->fields[col].nullable_action]; +            on_conflict_action_strs[fields[col].nullable_action];          p = enc->encode_str(p, action_str, strlen(action_str));          p = enc->encode_str(p, "sort_order", 10); -        enum sort_order sort_order = pIndex->sort_order[i]; +        enum sort_order sort_order = part->sort_order;          assert(sort_order < sort_order_MAX);          const char *sort_order_str = sort_order_strs[sort_order];          p = enc->encode_str(p, sort_order_str, strlen(sort_order_str));      } -    return (int)(p - base); +    return p - base;  }  /* diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c index 5f73f026e..ca699ecd9 100644 --- a/src/box/sql/analyze.c +++ b/src/box/sql/analyze.c @@ -849,7 +849,6 @@ analyzeOneTable(Parse * pParse,    /* Parser context */          int addrRewind;    /* Address of "OP_Rewind iIdxCur" */          int addrNextRow;    /* Address of "next_row:" */          const char *zIdxName;    /* Name of the index */ -        int nColTest;    /* Number of columns to test for changes */          if (pOnlyIdx && pOnlyIdx != pIdx)              continue; @@ -860,9 +859,9 @@ analyzeOneTable(Parse * pParse,    /* Parser context */          if (IsPrimaryKeyIndex(pIdx)) {              zIdxName = pTab->def->name;          } else { -            zIdxName = pIdx->zName; +            zIdxName = pIdx->def->name;          } -        nColTest = index_column_count(pIdx); +        int nColTest = pIdx->def->key_def->part_count;          /* Populate the register containing the index name. */          sqlite3VdbeLoadString(v, regIdxname, zIdxName); @@ -917,7 +916,7 @@ analyzeOneTable(Parse * pParse,    /* Parser context */          sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum,                    space_ptr_reg);          sql_vdbe_set_p4_key_def(pParse, pIdx); -        VdbeComment((v, "%s", pIdx->zName)); +        VdbeComment((v, "%s", pIdx->def->name));          /* Invoke the stat_init() function. The arguments are:           * @@ -969,7 +968,7 @@ analyzeOneTable(Parse * pParse,    /* Parser context */               */              sqlite3VdbeAddOp0(v, OP_Goto);              addrNextRow = sqlite3VdbeCurrentAddr(v); -            if (nColTest == 1 && index_is_unique(pIdx)) { +            if (nColTest == 1 && pIdx->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. @@ -978,13 +977,12 @@ analyzeOneTable(Parse * pParse,    /* Parser context */                            endDistinctTest);                  VdbeCoverage(v);              } -            for (i = 0; i < nColTest; i++) { -                uint32_t id; -                struct coll *coll = -                    sql_index_collation(pIdx, i, &id); +            struct key_part *part = pIdx->def->key_def->parts; +            for (i = 0; i < nColTest; ++i, ++part) { +                struct coll *coll = part->coll;                  sqlite3VdbeAddOp2(v, OP_Integer, i, regChng);                  sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, -                          pIdx->aiColumn[i], regTemp); +                          part->fieldno, regTemp);                  aGotoChng[i] =                      sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0,                                regPrev + i, (char *)coll, @@ -1006,7 +1004,8 @@ analyzeOneTable(Parse * pParse,    /* Parser context */              for (i = 0; i < nColTest; i++) {                  sqlite3VdbeJumpHere(v, aGotoChng[i]);                  sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, -                          pIdx->aiColumn[i], +                          pIdx->def->key_def-> +                              parts[i].fieldno,                            regPrev + i);              }              sqlite3VdbeResolveLabel(v, endDistinctTest); @@ -1022,15 +1021,14 @@ analyzeOneTable(Parse * pParse,    /* Parser context */           */          assert(regKey == (regStat4 + 2));          Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); -        int j, k, regKeyStat; -        int nPkColumn = (int)index_column_count(pPk); -        regKeyStat = sqlite3GetTempRange(pParse, nPkColumn); -        for (j = 0; j < nPkColumn; j++) { -            k = pPk->aiColumn[j]; -            assert(k >= 0 && k < (int)pTab->def->field_count); -            sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKeyStat + j); -            VdbeComment((v, "%s", - pTab->def->fields[pPk->aiColumn[j]].name)); +        int nPkColumn = (int) pPk->def->key_def->part_count; +        int regKeyStat = sqlite3GetTempRange(pParse, nPkColumn); +        for (int j = 0; j < nPkColumn; ++j) { +            int k = pPk->def->key_def->parts[j].fieldno; +            assert(k >= 0 && k < (int) pTab->def->field_count); +            sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, +                      regKeyStat + j); +            VdbeComment((v, "%s", pTab->def->fields[k].name));          }          sqlite3VdbeAddOp3(v, OP_MakeRecord, regKeyStat,                    nPkColumn, regKey); @@ -1146,7 +1144,7 @@ analyzeTable(Parse * pParse, Table * pTab, Index * pOnlyIdx)      iStatCur = pParse->nTab;      pParse->nTab += 3;      if (pOnlyIdx) { -        openStatTable(pParse, iStatCur, pOnlyIdx->zName, "idx"); +        openStatTable(pParse, iStatCur, pOnlyIdx->def->name, "idx");      } else {          openStatTable(pParse, iStatCur, pTab->def->name, "tbl");      } diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 592c9a6fa..84e481de3 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -241,6 +241,8 @@ static void  freeIndex(sqlite3 * db, Index * p)  {      sql_expr_delete(db, p->pPartIdxWhere, false); +     if (p->def != NULL) +        index_def_delete(p->def);      sqlite3DbFree(db, p->zColAff);      sqlite3DbFree(db, p);  } @@ -259,7 +261,8 @@ sqlite3UnlinkAndDeleteIndex(sqlite3 * db, Index * pIndex)      struct session *user_session = current_session(); -    pIndex = sqlite3HashInsert(&pIndex->pTable->idxHash, pIndex->zName, 0); +    pIndex = sqlite3HashInsert(&pIndex->pTable->idxHash, +                   pIndex->def->name, 0);      if (ALWAYS(pIndex)) {          if (pIndex->pTable->pIndex == pIndex) {              pIndex->pTable->pIndex = pIndex->pNext; @@ -376,7 +379,7 @@ deleteTable(sqlite3 * db, Table * pTable)          pNext = pIndex->pNext;          assert(pIndex->pSchema == pTable->pSchema);          if ((db == 0 || db->pnBytesFreed == 0)) { -            char *zName = pIndex->zName; +            char *zName = pIndex->def->name;              TESTONLY(Index *                   pOld =) sqlite3HashInsert(&pTable->idxHash,                                 zName, 0); @@ -1041,7 +1044,7 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken)      Table *p = pParse->pNewTable;      if (p == NULL)          return; -    int i = p->def->field_count - 1; +    uint32_t i = p->def->field_count - 1;      sqlite3 *db = pParse->db;      char *zColl = sqlite3NameFromToken(db, pToken);      if (!zColl) @@ -1049,22 +1052,20 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken)      uint32_t *id = &p->def->fields[i].coll_id;      p->aCol[i].coll = sql_get_coll_seq(pParse, zColl, id);      if (p->aCol[i].coll != NULL) { -        Index *pIdx;          /* If the column is declared as " PRIMARY KEY COLLATE ",           * then an index may have been created on this column before the           * collation type was added. Correct this if it is the case.           */ -        for (pIdx = p->pIndex; pIdx; pIdx = pIdx->pNext) { -            assert(pIdx->nColumn == 1); -            if (pIdx->aiColumn[0] == i) { -                id = &pIdx->coll_id_array[0]; -                pIdx->coll_array[0] = +        for (struct Index *pIdx = p->pIndex; pIdx; pIdx = pIdx->pNext) { +            assert(pIdx->def->key_def->part_count == 1); +            if (pIdx->def->key_def->parts[0].fieldno == i) { +                pIdx->def->key_def->parts[0].coll_id = *id; +                pIdx->def->key_def->parts[0].coll =                      sql_column_collation(p->def, i, id);              }          } -    } else { -        sqlite3DbFree(db, zColl);      } +    sqlite3DbFree(db, zColl);  }  struct coll * @@ -1094,66 +1095,6 @@ sql_column_collation(struct space_def *def, uint32_t column, uint32_t *coll_id)      return space->format->fields[column].coll;  } -struct key_def* -sql_index_key_def(struct Index *idx) -{ -    uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->tnum); -    uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum); -    struct space *space = space_by_id(space_id); -    assert(space != NULL); -    struct index *index = space_index(space, index_id); -    assert(index != NULL && index->def != NULL); -    return index->def->key_def; -} - -struct coll * -sql_index_collation(Index *idx, uint32_t column, uint32_t *coll_id) -{ -    assert(idx != NULL); -    uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->pTable->tnum); -    struct space *space = space_by_id(space_id); - -    assert(column < idx->nColumn); -    /* -     * If space is still under construction, or it is -     * an ephemeral space, then fetch collation from -     * SQL internal structure. -     */ -    if (space == NULL) { -        assert(column < idx->nColumn); -        *coll_id = idx->coll_id_array[column]; -        return idx->coll_array[column]; -    } - -    struct key_def *key_def = sql_index_key_def(idx); -    assert(key_def != NULL && key_def->part_count >= column); -    *coll_id = key_def->parts[column].coll_id; -    return key_def->parts[column].coll; -} - -enum sort_order -sql_index_column_sort_order(Index *idx, uint32_t column) -{ -    assert(idx != NULL); -    uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->pTable->tnum); -    struct space *space = space_by_id(space_id); - -    assert(column < idx->nColumn); -    /* -     * If space is still under construction, or it is -     * an ephemeral space, then fetch collation from -     * SQL internal structure. -     */ -    if (space == NULL) { -        assert(column < idx->nColumn); -        return idx->sort_order[column]; -    } - -    struct key_def *key_def = sql_index_key_def(idx); -    assert(key_def != NULL && key_def->part_count >= column); -    return key_def->parts[column].sort_order; -} -  struct ExprList *  space_checks_expr_list(uint32_t space_id)  { @@ -1337,14 +1278,16 @@ createTableStmt(sqlite3 * db, Table * p)      return zStmt;  } -/* Return true if value x is found any of the first nCol entries of aiCol[] - */  static int -hasColumn(const i16 * aiCol, int nCol, int x) +hasColumn(const struct key_part *key_parts, int nCol, uint32_t fieldno)  { -    while (nCol-- > 0) -        if (x == *(aiCol++)) +    int i = 0; +    while (i < nCol) { +        if (fieldno == key_parts->fieldno)              return 1; +        key_parts++; +        i++; +    }      return 0;  } @@ -1364,13 +1307,12 @@ static void  convertToWithoutRowidTable(Parse * pParse, Table * pTab)  {      Index *pPk; -    int i, j;      sqlite3 *db = pParse->db;      /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables)       */      if (!db->init.imposterTable) { -        for (i = 0; i < (int)pTab->def->field_count; i++) { +        for (uint32_t i = 0; i < pTab->def->field_count; i++) {              if (pTab->aCol[i].is_primkey) {                  pTab->def->fields[i].nullable_action                      = ON_CONFLICT_ACTION_ABORT; @@ -1408,14 +1350,28 @@ convertToWithoutRowidTable(Parse * pParse, Table * pTab)           * "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)".  Later           * code assumes the PRIMARY KEY contains no repeated columns.           */ -        for (i = j = 1; i < pPk->nColumn; i++) { -            if (hasColumn(pPk->aiColumn, j, pPk->aiColumn[i])) { -                pPk->nColumn--; -            } else { -                pPk->aiColumn[j++] = pPk->aiColumn[i]; + +        struct key_part *parts = pPk->def->key_def->parts; +        uint32_t part_count = pPk->def->key_def->part_count; +        uint32_t new_part_count = part_count; + +        for (uint32_t i = 1; i < part_count; i++) { +            if (hasColumn(parts, i, parts[i].fieldno)){ +                new_part_count--; +                bool is_found = false; +                for (uint32_t j = i + 1; j < part_count; j++){ +                    if (!(hasColumn(parts, j, +                            parts[j].fieldno))) { +                        parts[i] = parts[j]; +                        is_found = true; +                        break; +                    } +                } +                if (!(is_found)) +                    break;              }          } -        pPk->nColumn = j; +        pPk->def->key_def->part_count = new_part_count;      }      assert(pPk != 0);  } @@ -1497,7 +1453,7 @@ createIndex(Parse * pParse, Index * pIndex, int iSpaceId, int iIndexId,      }      sqlite3VdbeAddOp4(v,                OP_String8, 0, iFirstCol + 2, 0, -              sqlite3DbStrDup(pParse->db, pIndex->zName), +              sqlite3DbStrDup(pParse->db, pIndex->def->name),                P4_DYNAMIC);      sqlite3VdbeAddOp4(v, OP_String8, 0, iFirstCol + 3, 0, "tree",                P4_STATIC); @@ -1534,7 +1490,7 @@ makeIndexSchemaRecord(Parse * pParse,      sqlite3VdbeAddOp4(v,                OP_String8, 0, iFirstCol, 0, -              sqlite3DbStrDup(pParse->db, pIndex->zName), +              sqlite3DbStrDup(pParse->db, pIndex->def->name),                P4_DYNAMIC);      if (pParse->pNewTable) { @@ -2463,15 +2419,16 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage)      } else {          tnum = pIndex->tnum;      } -    struct key_def *def = key_def_dup(sql_index_key_def(pIndex)); +    struct key_def *def = key_def_dup(pIndex->def->key_def);      if (def == NULL) {          sqlite3OomFault(db);          return;      }      /* Open the sorter cursor if we are to use one. */      iSorter = pParse->nTab++; -    sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nColumn, -              (char *)def, P4_KEYDEF); +    sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, +              pIndex->def->key_def->part_count, (char *)def, +              P4_KEYDEF);      /* Open the table. Loop through all rows of the table, inserting index       * records into the sorter. @@ -2504,7 +2461,8 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage)          sqlite3VdbeGoto(v, j2);          addr2 = sqlite3VdbeCurrentAddr(v);          sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, -                     regRecord, pIndex->nColumn); +                     regRecord, +                     pIndex->def->key_def->part_count);          VdbeCoverage(v);          parser_emit_unique_constraint(pParse, ON_CONFLICT_ACTION_ABORT,                            pIndex); @@ -2542,24 +2500,13 @@ sqlite3AllocateIndexObject(sqlite3 * db,    /* Database connection */      int nByte;        /* Bytes of space for Index object + arrays */      nByte = ROUND8(sizeof(Index)) +            /* Index structure   */ -        ROUND8(sizeof(struct coll *) * nCol) +  /* Index.coll_array  */ -        ROUND8(sizeof(uint32_t) * nCol) +       /* Index.coll_id_array*/ -        ROUND8(sizeof(LogEst) * (nCol + 1) +    /* Index.aiRowLogEst */ -           sizeof(i16) * nCol +            /* Index.aiColumn */ -           sizeof(enum sort_order) * nCol); /* Index.sort_order */ +        ROUND8(sizeof(LogEst) * (nCol + 1));    /* Index.aiRowLogEst */      p = sqlite3DbMallocZero(db, nByte + nExtra);      if (p) {          char *pExtra = ((char *)p) + ROUND8(sizeof(Index)); -        p->coll_array = (struct coll **)pExtra; -        pExtra += ROUND8(sizeof(struct coll **) * nCol); -        p->coll_id_array = (uint32_t *) pExtra; -        pExtra += ROUND8(sizeof(uint32_t) * nCol);          p->aiRowLogEst = (LogEst *) pExtra;          pExtra += sizeof(LogEst) * (nCol + 1); -        p->aiColumn = (i16 *) pExtra;          pExtra += sizeof(i16) * nCol; -        p->sort_order = (enum sort_order *) pExtra; -        p->nColumn = nCol;          *ppExtra = ((char *)p) + nByte;      }      return p; @@ -2648,18 +2595,136 @@ addIndexToTable(Index * pIndex, Table * pTab)      }  } -bool -index_is_unique(Index *idx) +static void +append_string_part(struct region *r, const char *str, +          size_t *total_sql_size, Parse *parse)  { -    assert(idx != NULL); -    uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->tnum); -    uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum); -    struct space *space = space_by_id(space_id); -    assert(space != NULL); -    struct index *tnt_index = space_index(space, index_id); -    assert(tnt_index != NULL); +    char * str_part = region_alloc(r, strlen(str)); +    if (str_part == NULL){ +        diag_set(OutOfMemory, strlen(str), +             "region_alloc", "str_part"); +        parse->rc = SQL_TARANTOOL_ERROR; +        parse->nErr++; +    } +    memcpy(str_part, str, strlen(str)); +    *total_sql_size += strlen(str); +} + +static void +set_index_def(Parse *parse, Index *index, Table *table, uint32_t iid, +          const char *name, uint32_t name_len, int on_error, +          struct ExprList *expr_list, u8 idx_type) +{ +    struct space_def *space_def = table->def; +    struct index_opts opts; +    index_opts_create(&opts); +    opts.is_unique = on_error != ON_CONFLICT_ACTION_NONE; + +    struct key_def *key_def = key_def_new(expr_list->nExpr); +    if (key_def == NULL) { +        parse->rc = SQL_TARANTOOL_ERROR; +        parse->nErr++; +        goto cleanup; +    } + +    /* +     * Build initial parts of SQL statement. +     */ + +    struct region *r = &parse->region; +    size_t total_sql_size = 0; + +    if (idx_type == SQLITE_IDXTYPE_APPDEF) { +        append_string_part(r, "CREATE INDEX ", &total_sql_size, +                   parse); +        append_string_part(r, name, &total_sql_size, parse); +        append_string_part(r, " ON ", &total_sql_size, parse); +        append_string_part(r, space_def->name, &total_sql_size, +                   parse); +        append_string_part(r, " (", &total_sql_size, parse); +    } + +    for (int i = 0; i < expr_list->nExpr; i++) { +        Expr *expr = expr_list->a[i].pExpr; +        sql_resolve_self_reference(parse, table, NC_IdxExpr, expr, 0); +        if (parse->nErr > 0) +            goto cleanup; + +        Expr *column_expr = sqlite3ExprSkipCollate(expr); +        if (column_expr->op != TK_COLUMN) { +            sqlite3ErrorMsg(parse, +                    "functional indexes aren't supported " +                    "in the current version"); +            goto cleanup; +        } + +        uint32_t fieldno = column_expr->iColumn; +        uint32_t coll_id; +        struct coll *coll; +        if (expr->op == TK_COLLATE) { +            coll = sql_get_coll_seq(parse, expr->u.zToken, +                        &coll_id); + +            if (idx_type == SQLITE_IDXTYPE_APPDEF) { +                append_string_part(r, name, +                           &total_sql_size, parse); +                append_string_part(r, " COLLATE ", +                           &total_sql_size, parse); +                const char *coll_name = expr->u.zToken; +                append_string_part(r, coll_name, +                           &total_sql_size, parse); +                append_string_part(r, ", ", +                           &total_sql_size, parse); +            } +        } else { +            coll = sql_column_collation(space_def, fieldno, +                            &coll_id); +            if (idx_type == SQLITE_IDXTYPE_APPDEF) { +                append_string_part(r, name, +                           &total_sql_size, parse); +                append_string_part(r, ", ", +                           &total_sql_size, parse); +            } +        } -    return tnt_index->def->opts.is_unique; +        /* +        * Tarantool: DESC indexes are not supported so far. +        * See gh-3016. +        */ +        key_def_set_part(key_def, i, fieldno, +                 space_def->fields[fieldno].type, +                 space_def->fields[fieldno].nullable_action, +                 coll, coll_id, SORT_ORDER_ASC); +    } + +    if (parse->nErr > 0) { +        index->def = NULL; +        goto cleanup; +    } + +    if (idx_type == SQLITE_IDXTYPE_APPDEF) { +        memcpy(region_alloc(r, 1), "\0", 1); +        total_sql_size += 1; +        opts.sql = region_join(r, total_sql_size); + +        /* +         * fix last ", " with ")\0" to finish the statement. +         */ +        opts.sql[total_sql_size - 3] = ')'; +        opts.sql[total_sql_size - 2] = '\0'; +    } + +    struct key_def *pk_key_def; +    if (idx_type == SQLITE_IDXTYPE_APPDEF) +        pk_key_def = table->pIndex->def->key_def; +    else +        pk_key_def = NULL; + +    index->def = index_def_new(space_def->id, iid, name, name_len, +                   TREE, &opts, key_def, pk_key_def); +    cleanup: +        if (key_def != NULL) +            key_def_delete(key_def);  }  void @@ -2668,16 +2733,14 @@ sql_create_index(struct Parse *parse, struct Token *token,           int on_error, struct Token *start, struct Expr *where,           enum sort_order sort_order, bool if_not_exist, u8 idx_type)  { -    Table *pTab = 0;    /* Table to be indexed */ -    Index *pIndex = 0;    /* The index to be created */ -    char *zName = 0;    /* Name of the index */ -    int nName;        /* Number of characters in zName */ -    int i, j; +    Table *pTab = NULL;    /* Table to be indexed */ +    Index *pIndex = NULL;    /* The index to be created */ +    char *name = NULL;    /* Name of the index */ +    int name_len;        /* Number of characters in zName */      DbFixer sFix;        /* For assigning database names to pTable */      sqlite3 *db = parse->db; -    struct ExprList_item *col_listItem;    /* For looping over col_list */      int nExtra = 0;        /* Space allocated for zExtra[] */ -    char *zExtra = 0;    /* Extra space after the Index object */ +    char *zExtra = NULL;    /* Extra space after the Index object */      struct session *user_session = current_session();      if (db->mallocFailed || parse->nErr > 0) { @@ -2749,24 +2812,24 @@ sql_create_index(struct Parse *parse, struct Token *token,       * our own name.       */      if (token) { -        zName = sqlite3NameFromToken(db, token); -        if (zName == 0) +        name = sqlite3NameFromToken(db, token); +        if (name == NULL)              goto exit_create_index;          assert(token->z != 0);          if (!db->init.busy) { -            if (sqlite3HashFind(&db->pSchema->tblHash, zName) != +            if (sqlite3HashFind(&db->pSchema->tblHash, name) !=                  NULL) {                  sqlite3ErrorMsg(parse,                          "there is already a table named %s", -                        zName); +                        name);                  goto exit_create_index;              }          } -        if (sqlite3HashFind(&pTab->idxHash, zName) != NULL) { +        if (sqlite3HashFind(&pTab->idxHash, name) != NULL) {              if (!if_not_exist) {                  sqlite3ErrorMsg(parse,                          "index %s.%s already exists", -                        pTab->def->name, zName); +                        pTab->def->name, name);              } else {                  assert(!db->init.busy);              } @@ -2778,10 +2841,9 @@ sql_create_index(struct Parse *parse, struct Token *token,          for (pLoop = pTab->pIndex, n = 1; pLoop;               pLoop = pLoop->pNext, n++) {          } -        zName = -            sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->def->name, -                   n); -        if (zName == 0) { +        name = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", +                      pTab->def->name, n); +        if (name == NULL) {              goto exit_create_index;          }      } @@ -2807,31 +2869,27 @@ sql_create_index(struct Parse *parse, struct Token *token,          sqlite3ExprListCheckLength(parse, col_list, "index");      } -    /* Figure out how many bytes of space are required to store explicitly -     * specified collation sequence names. -     */ -    for (i = 0; i < col_list->nExpr; i++) { -        Expr *pExpr = col_list->a[i].pExpr; -        assert(pExpr != 0); -        if (pExpr->op == TK_COLLATE) { -            nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); -        } -    } -      /*       * Allocate the index structure.       */ -    nName = sqlite3Strlen30(zName); +    name_len = sqlite3Strlen30(name); + +    if (name_len > BOX_NAME_MAX) { +        sqlite3ErrorMsg(parse, +                "%s.%s exceeds indexes' names length limit", +                pTab->def->name, name); +        goto exit_create_index; +    } + +    if (sqlite3CheckIdentifierName(parse, name) != SQLITE_OK) +        goto exit_create_index; +      pIndex = sqlite3AllocateIndexObject(db, col_list->nExpr, -                        nName + nExtra + 1, &zExtra); +                        name_len + nExtra + 1, &zExtra);      if (db->mallocFailed) {          goto exit_create_index;      }      assert(EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst)); -    assert(EIGHT_BYTE_ALIGNMENT(pIndex->coll_array)); -    pIndex->zName = zExtra; -    zExtra += nName + 1; -    memcpy(pIndex->zName, zName, nName + 1);      pIndex->pTable = pTab;      pIndex->onError = (u8) on_error;      /* @@ -2846,7 +2904,6 @@ sql_create_index(struct Parse *parse, struct Token *token,          pIndex->idxType = idx_type;      }      pIndex->pSchema = db->pSchema; -    pIndex->nColumn = col_list->nExpr;      /* Tarantool have access to each column by any index */      if (where) {          sql_resolve_self_reference(parse, pTab, NC_PartIdx, where, @@ -2855,59 +2912,27 @@ sql_create_index(struct Parse *parse, struct Token *token,          where = NULL;      } -    /* Analyze the list of expressions that form the terms of the index and -     * report any errors.  In the common case where the expression is exactly -     * a table column, store that column in aiColumn[]. -     * +    /*       * TODO: Issue a warning if two or more columns of the index are identical.       * TODO: Issue a warning if the table primary key is used as part of the       * index key.       */ -    for (i = 0, col_listItem = col_list->a; i < col_list->nExpr; -         i++, col_listItem++) { -        Expr *pCExpr;    /* The i-th index expression */ -        sql_resolve_self_reference(parse, pTab, NC_IdxExpr, -                       col_listItem->pExpr, NULL); -        if (parse->nErr > 0) -            goto exit_create_index; -        pCExpr = sqlite3ExprSkipCollate(col_listItem->pExpr); -        if (pCExpr->op != TK_COLUMN) { -            sqlite3ErrorMsg(parse, -                    "functional indexes aren't supported " -                    "in the current version"); -            goto exit_create_index; -        } else { -            j = pCExpr->iColumn; -            assert(j <= 0x7fff); -            if (j < 0) { -                j = pTab->iPKey; -            } -            pIndex->aiColumn[i] = (i16) j; -        } -        struct coll *coll; -        uint32_t id; -        if (col_listItem->pExpr->op == TK_COLLATE) { -            const char *coll_name = col_listItem->pExpr->u.zToken; -            coll = sql_get_coll_seq(parse, coll_name, &id); -            if (coll == NULL && -                sqlite3StrICmp(coll_name, "binary") != 0) { -                goto exit_create_index; -            } -        } else if (j >= 0) { -            coll = sql_column_collation(pTab->def, j, &id); -        } else { -            id = COLL_NONE; -            coll = NULL; -        } -        pIndex->coll_array[i] = coll; -        pIndex->coll_id_array[i] = id; +    uint32_t max_iid = 0; +    for (Index *index = pTab->pIndex; index; index = index->pNext) { +        max_iid = max_iid > index->def->iid ? +              max_iid : +              index->def->iid + 1; +    } -        /* Tarantool: DESC indexes are not supported so far. -         * See gh-3016. -         */ -        pIndex->sort_order[i] = SORT_ORDER_ASC; +    set_index_def(parse, pIndex, pTab, max_iid, name, name_len, on_error, +              col_list, idx_type); + +    if (pIndex->def == NULL || +        !index_def_is_valid(pIndex->def, pTab->def->name)) { +        goto exit_create_index;      } +      if (pTab == parse->pNewTable) {          /* This routine has been called to create an automatic index as a           * result of a PRIMARY KEY or UNIQUE clause on a column definition, or @@ -2932,25 +2957,27 @@ sql_create_index(struct Parse *parse, struct Token *token,           */          Index *pIdx;          for (pIdx = pTab->pIndex; pIdx; pIdx = pIdx->pNext) { -            int k; +            uint32_t k;              assert(IsUniqueIndex(pIdx));              assert(pIdx->idxType != SQLITE_IDXTYPE_APPDEF);              assert(IsUniqueIndex(pIndex)); -            if (pIdx->nColumn != pIndex->nColumn) +            if (pIdx->def->key_def->part_count != +                pIndex->def->key_def->part_count) {                  continue; -            for (k = 0; k < pIdx->nColumn; k++) { -                assert(pIdx->aiColumn[k] >= 0); -                if (pIdx->aiColumn[k] != pIndex->aiColumn[k]) +            } +            for (k = 0; k < pIdx->def->key_def->part_count; k++) { +                if (pIdx->def->key_def->parts[k].fieldno != + pIndex->def->key_def->parts[k].fieldno) {                      break; +                }                  struct coll *coll1, *coll2; -                uint32_t id; -                coll1 = sql_index_collation(pIdx, k, &id); -                coll2 = sql_index_collation(pIndex, k, &id); +                coll1 = pIdx->def->key_def->parts[k].coll; +                coll2 = pIndex->def->key_def->parts[k].coll;                  if (coll1 != coll2)                      break;              } -            if (k == pIdx->nColumn) { +            if (k == pIdx->def->key_def->part_count) {                  if (pIdx->onError != pIndex->onError) {                      /* This constraint creates the same index as a previous                       * constraint specified somewhere in the CREATE TABLE statement. @@ -2984,7 +3011,7 @@ sql_create_index(struct Parse *parse, struct Token *token,      assert(parse->nErr == 0);      if (db->init.busy) {          Index *p; -        p = sqlite3HashInsert(&pTab->idxHash, pIndex->zName, pIndex); +        p = sqlite3HashInsert(&pTab->idxHash, pIndex->def->name, pIndex);          if (p) {              assert(p == pIndex);    /* Malloc must have failed */              sqlite3OomFault(db); @@ -3082,44 +3109,7 @@ sql_create_index(struct Parse *parse, struct Token *token,      sql_expr_delete(db, where, false);      sql_expr_list_delete(db, col_list);      sqlite3SrcListDelete(db, tbl_name); -    sqlite3DbFree(db, zName); -} - -/** - * Return number of columns in given index. - * If space is ephemeral, use internal - * SQL structure to fetch the value. - */ -uint32_t -index_column_count(const Index *idx) -{ -    assert(idx != NULL); -    uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->tnum); -    struct space *space = space_by_id(space_id); -    /* It is impossible to find an ephemeral space by id. */ -    if (space == NULL) -        return idx->nColumn; - -    uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum); -    struct index *index = space_index(space, index_id); -    assert(index != NULL); -    return index->def->key_def->part_count; -} - -/** Return true if given index is unique and not nullable. */ -bool -index_is_unique_not_null(const Index *idx) -{ -    assert(idx != NULL); -    uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->tnum); -    struct space *space = space_by_id(space_id); -    assert(space != NULL); - -    uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum); -    struct index *index = space_index(space, index_id); -    assert(index != NULL); -    return (index->def->opts.is_unique && -        !index->def->key_def->is_nullable); +    sqlite3DbFree(db, name);  }  void @@ -3745,9 +3735,9 @@ parser_emit_unique_constraint(struct Parse *parser,      const struct space_def *def = index->pTable->def;      StrAccum err_accum;      sqlite3StrAccumInit(&err_accum, parser->db, 0, 0, 200); -    for (int j = 0; j < index->nColumn; ++j) { -        assert(index->aiColumn[j] >= 0); -        const char *col_name = def->fields[index->aiColumn[j]].name; +    struct key_part *part = index->def->key_def->parts; +    for (uint32_t j = 0; j < index->def->key_def->part_count; ++j, part++) { +        const char *col_name = def->fields[part->fieldno].name;          if (j != 0)              sqlite3StrAccumAppend(&err_accum, ", ", 2);          sqlite3XPrintf(&err_accum, "%s.%s", def->name, col_name); @@ -3768,11 +3758,11 @@ static bool  collationMatch(struct coll *coll, struct Index *index)  {      assert(coll != NULL); -    for (int i = 0; i < index->nColumn; i++) { -        uint32_t id; -        struct coll *idx_coll = sql_index_collation(index, i, &id); -        assert(idx_coll != 0 || index->aiColumn[i] < 0); -        if (index->aiColumn[i] >= 0 && coll == idx_coll) +    struct key_part *part = index->def->key_def->parts; +    for (uint32_t i = 0; i < index->def->key_def->part_count; i++, part++) { +        struct coll *idx_coll = part->coll; +        assert(idx_coll != NULL); +        if (coll == idx_coll)              return true;      }      return false; diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c index 8b13f6077..931a15a60 100644 --- a/src/box/sql/delete.c +++ b/src/box/sql/delete.c @@ -269,11 +269,12 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,          /* Extract the primary key for the current row */          if (!is_view) { -            for (int i = 0; i < pk_len; i++) { +            struct key_part *part = pk_def->parts; +            for (int i = 0; i < pk_len; i++, part++) {                  struct space_def *def = space->def;                  sqlite3ExprCodeGetColumnOfTable(v, def,                                  tab_cursor, -                                pk_def->parts[i].fieldno, +                                part->fieldno,                                  reg_pk + i);              }          } else { @@ -569,13 +570,14 @@ sql_generate_index_key(struct Parse *parse, struct Index *index, int cursor,              *part_idx_label = 0;          }      } -    int col_cnt = index_column_count(index); +    int col_cnt = index->def->key_def->part_count;      int reg_base = sqlite3GetTempRange(parse, col_cnt);      if (prev != NULL && (reg_base != reg_prev ||                   prev->pPartIdxWhere != NULL))          prev = NULL;      for (int j = 0; j < col_cnt; j++) { -        if (prev != NULL && prev->aiColumn[j] == index->aiColumn[j]) { +        if (prev != NULL && prev->def->key_def->parts[j].fieldno == + index->def->key_def->parts[j].fieldno) {              /*               * This column was already computed by the               * previous index. diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index f03c7a3cd..b752084d4 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -2423,20 +2423,24 @@ sqlite3FindInIndex(Parse * pParse,    /* Parsing context */                   pIdx = pIdx->pNext) {                  Bitmask colUsed; /* Columns of the index used */                  Bitmask mCol;    /* Mask for the current column */ -                if (pIdx->nColumn < nExpr) +                uint32_t part_count = pIdx->def->key_def-> +                    part_count; +                struct key_part *parts = pIdx->def->key_def-> +                    parts; +                if ((int)part_count < nExpr)                      continue;                  /* Maximum nColumn is BMS-2, not BMS-1, so that we can compute                   * BITMASK(nExpr) without overflowing                   */ -                testcase(pIdx->nColumn == BMS - 2); -                testcase(pIdx->nColumn == BMS - 1); -                if (pIdx->nColumn >= BMS - 1) +                testcase(part_count == BMS - 2); +                testcase(>part_count == BMS - 1); +                if (part_count >= BMS - 1)                      continue;                  if (mustBeUnique) { -                    if (pIdx->nColumn > nExpr -                        || (pIdx->nColumn > nExpr -                        && !index_is_unique(pIdx))) { -                            continue;    /* This index is not unique over the IN RHS columns */ +                    if ((int)part_count > nExpr +                        || !pIdx->def->opts.is_unique) { +                        /* This index is not unique over the IN RHS columns */ +                        continue;                      }                  } @@ -2450,12 +2454,13 @@ sqlite3FindInIndex(Parse * pParse,    /* Parsing context */                      int j;                      for (j = 0; j < nExpr; j++) { -                        if (pIdx->aiColumn[j] != -                            pRhs->iColumn) { +                        if ((int) parts[j].fieldno +                            != pRhs->iColumn) {                              continue;                          } -                        struct coll *idx_coll; -                        idx_coll = sql_index_collation(pIdx, j, &id); + +                        struct coll *idx_coll = +                                 parts[j].coll;                          if (pReq != NULL &&                              pReq != idx_coll) {                              continue; @@ -2484,18 +2489,17 @@ sqlite3FindInIndex(Parse * pParse,    /* Parsing context */                                0, 0, 0,                                sqlite3MPrintf(db,                                "USING INDEX %s FOR IN-OPERATOR", -                              pIdx->zName), +                              pIdx->def->name),                                P4_DYNAMIC);                      struct space *space = space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum));                      vdbe_emit_open_cursor(pParse, iTab,                                    pIdx->tnum, space); -                    VdbeComment((v, "%s", pIdx->zName)); +                    VdbeComment((v, "%s", pIdx->def->name));                      assert(IN_INDEX_INDEX_DESC ==                             IN_INDEX_INDEX_ASC + 1);                      eType = IN_INDEX_INDEX_ASC + -                        sql_index_column_sort_order(pIdx, -                                        0); +                        parts[0].sort_order;                      if (prRhsHasNull) {  #ifdef SQLITE_ENABLE_COLUMN_USED_MASK @@ -2517,7 +2521,7 @@ sqlite3FindInIndex(Parse * pParse,    /* Parsing context */                              /* Tarantool: Check for null is performed on first key of the index.  */                              sqlite3SetHasNullFlag(v,                                            iTab, -                                          pIdx->aiColumn[0], +                                          parts[0].fieldno,                                            *prRhsHasNull);                          }                      } @@ -3148,12 +3152,12 @@ sqlite3ExprCodeIN(Parse * pParse,    /* Parsing and code generating context */          struct Index *pk = sqlite3PrimaryKeyIndex(tab);          assert(pk); +        uint32_t fieldno = pk->def->key_def->parts[0].fieldno;          enum affinity_type affinity = -            tab->def->fields[pk->aiColumn[0]].affinity; -        if (pk->nColumn == 1 +            tab->def->fields[fieldno].affinity; +        if (pk->def->key_def->part_count == 1              && affinity == AFFINITY_INTEGER -            && pk->aiColumn[0] < nVector) { -            int reg_pk = rLhs + pk->aiColumn[0]; +            && (int) fieldno < nVector) { int reg_pk = rLhs + (int)fieldno;              sqlite3VdbeAddOp2(v, OP_MustBeInt, reg_pk, destIfFalse);          }      } @@ -3485,7 +3489,7 @@ sqlite3ExprCodeLoadIndexColumn(Parse * pParse,    /* The parsing context */                     int regOut    /* Store the index column value in this register */      )  { -    i16 iTabCol = pIdx->aiColumn[iIdxCol]; +    i16 iTabCol = pIdx->def->key_def->parts[iIdxCol].fieldno;      sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable->def,                      iTabCur, iTabCol, regOut);  } diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c index e3fff37fe..c5fec3161 100644 --- a/src/box/sql/fkey.c +++ b/src/box/sql/fkey.c @@ -257,8 +257,8 @@ sqlite3FkLocateIndex(Parse * pParse,    /* Parse context to store any error in */      }      for (pIdx = pParent->pIndex; pIdx; pIdx = pIdx->pNext) { -        int nIdxCol = index_column_count(pIdx); -        if (nIdxCol == nCol && index_is_unique(pIdx) +        int nIdxCol = pIdx->def->key_def->part_count; +        if (nIdxCol == nCol && pIdx->def->opts.is_unique              && pIdx->pPartIdxWhere == 0) {              /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number               * of columns. If each indexed column corresponds to a foreign key @@ -287,8 +287,10 @@ sqlite3FkLocateIndex(Parse * pParse,    /* Parse context to store any error in */                   * the default collation sequences for each column.                   */                  int i, j; -                for (i = 0; i < nCol; i++) { -                    i16 iCol = pIdx->aiColumn[i];    /* Index of column in parent tbl */ +                struct key_part *part = +                    pIdx->def->key_def->parts; +                for (i = 0; i < nCol; i++, part++) { +                    i16 iCol = (int) part->fieldno;    /* Index of column in parent tbl */                      char *zIdxCol;    /* Name of indexed column */                      if (iCol < 0) @@ -303,9 +305,7 @@ sqlite3FkLocateIndex(Parse * pParse,    /* Parse context to store any error in */                      def_coll = sql_column_collation(pParent->def,                                      iCol,                                      &id); -                    struct coll *coll = -                        sql_index_collation(pIdx, i, -                                    &id); +                    struct coll *coll = part->coll;                      if (def_coll != coll)                          break; @@ -465,13 +465,15 @@ fkLookupParent(Parse * pParse,    /* Parse context */                  for (i = 0; i < nCol; i++) {                      int iChild = aiCol[i] + 1 + regData;                      int iParent = -                        pIdx->aiColumn[i] + 1 + regData; -                    assert(pIdx->aiColumn[i] >= 0); +                        (int) pIdx->def->key_def->parts[i].fieldno +                        + 1 + regData;                      assert(aiCol[i] != pTab->iPKey); -                    if (pIdx->aiColumn[i] == pTab->iPKey) { +                    if ((int)pIdx->def->key_def-> +                        parts[i].fieldno == pTab->iPKey) {                          /* The parent key is a composite key that includes the IPK column */                          iParent = regData;                      } +                      sqlite3VdbeAddOp3(v, OP_Ne, iChild,                                iJump, iParent);                      VdbeCoverage(v); @@ -623,7 +625,7 @@ fkScanChildren(Parse * pParse,    /* Parse context */      Vdbe *v = sqlite3GetVdbe(pParse);      assert(pIdx == 0 || pIdx->pTable == pTab); -    assert(pIdx == 0 || (int)index_column_count(pIdx) == pFKey->nCol); +    assert(pIdx == 0 || (int) pIdx->def->key_def->part_count == pFKey->nCol);      assert(pIdx != 0);      if (nIncr < 0) { @@ -647,7 +649,8 @@ fkScanChildren(Parse * pParse,    /* Parse context */          i16 iCol;    /* Index of column in child table */          const char *zCol;    /* Name of column in child table */ -        iCol = pIdx ? pIdx->aiColumn[i] : -1; +        iCol = pIdx != NULL ? +               pIdx->def->key_def->parts[i].fieldno : -1;          pLeft = exprTableRegister(pParse, pTab, regData, iCol);          iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;          assert(iCol >= 0); @@ -672,10 +675,9 @@ fkScanChildren(Parse * pParse,    /* Parse context */          Expr *pEq, *pAll = 0;          Index *pPk = sqlite3PrimaryKeyIndex(pTab);          assert(pIdx != 0); -        int col_count = index_column_count(pPk); +        int col_count = pPk->def->key_def->part_count;          for (i = 0; i < col_count; i++) { -            i16 iCol = pIdx->aiColumn[i]; -            assert(iCol >= 0); +            i16 iCol = (int) pIdx->def->key_def->parts[i].fieldno;              pLeft = exprTableRegister(pParse, pTab, regData, iCol);              pRight =                  exprTableColumn(db, pTab->def, @@ -982,7 +984,6 @@ sqlite3FkCheck(Parse * pParse,    /* Parse context */              if (aiCol[i] == pTab->iPKey) {                  aiCol[i] = -1;              } -            assert(pIdx == 0 || pIdx->aiColumn[i] >= 0);          }          pParse->nTab++; @@ -1116,10 +1117,10 @@ sqlite3FkOldmask(Parse * pParse,    /* Parse context */              Index *pIdx = 0;              sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0);              if (pIdx) { -                int nIdxCol = index_column_count(pIdx); +                int nIdxCol = pIdx->def->key_def->part_count;                  for (i = 0; i < nIdxCol; i++) { -                    assert(pIdx->aiColumn[i] >= 0); -                    mask |= COLUMN_MASK(pIdx->aiColumn[i]); +                    mask |= COLUMN_MASK(pIdx->def-> +                        key_def->parts[i].fieldno);                  }              }          } @@ -1254,11 +1255,12 @@ fkActionTrigger(Parse * pParse,    /* Parse context */                     || (pTab->iPKey >= 0                     && pTab->iPKey <                        (int)pTab->def->field_count)); -            assert(pIdx == 0 || pIdx->aiColumn[i] >= 0); + +            uint32_t fieldno = pIdx != NULL ? + pIdx->def->key_def->parts[i].fieldno : +                       (uint32_t)pTab->iPKey;              sqlite3TokenInit(&tToCol, -                     pTab->def->fields[pIdx ? pIdx-> -                            aiColumn[i] : pTab->iPKey]. -                     name); +                     pTab->def->fields[fieldno].name);              sqlite3TokenInit(&tFromCol,                       pFKey->pFrom->def->fields[                          iFromCol].name); diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 70555c3ec..b535763e9 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -90,14 +90,14 @@ sqlite3IndexAffinityStr(sqlite3 *db, Index *index)       * sqliteDeleteIndex() when the Index structure itself is       * cleaned up.       */ -    int column_count = index_column_count(index); +    int column_count = index->def->key_def->part_count;      index->zColAff = (char *) sqlite3DbMallocRaw(0, column_count + 1);      if (index->zColAff == NULL) {          sqlite3OomFault(db);          return NULL;      }      for (int n = 0; n < column_count; n++) { -        uint16_t x = index->aiColumn[n]; +        uint16_t x = index->def->key_def->parts[n].fieldno;          index->zColAff[n] = index->pTable->def->fields[x].affinity;      }      index->zColAff[column_count] = 0; @@ -647,7 +647,7 @@ sqlite3Insert(Parse * pParse,    /* Parser context */               pIdx = pIdx->pNext, i++) {              assert(pIdx);              aRegIdx[i] = ++pParse->nMem; -            pParse->nMem += index_column_count(pIdx); +            pParse->nMem += pIdx->def->key_def->part_count;          }      } @@ -1089,7 +1089,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,        /* The parser context */      nCol = def->field_count;      pPk = sqlite3PrimaryKeyIndex(pTab); -    nPkField = index_column_count(pPk); +    nPkField = pPk->def->key_def->part_count;      /* Record that this module has started */      VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)", @@ -1253,10 +1253,10 @@ sqlite3GenerateConstraintChecks(Parse * pParse,        /* The parser context */           * the insert or update.  Store that record in the aRegIdx[ix] register           */          regIdx = aRegIdx[ix] + 1; -        int nIdxCol = (int) index_column_count(pIdx); +        int nIdxCol = (int) pIdx->def->key_def->part_count;          if (uniqueByteCodeNeeded) {              for (i = 0; i < nIdxCol; ++i) { -                int fieldno = pIdx->aiColumn[i]; +                int fieldno = pIdx->def->key_def->parts[i].fieldno;                  int reg;                  /*                   * OP_SCopy copies value in @@ -1284,8 +1284,12 @@ sqlite3GenerateConstraintChecks(Parse * pParse,        /* The parser context */              /* If PK is marked as INTEGER, use it as strict type,               * not as affinity. Emit code for type checking */              if (nIdxCol == 1) { -                reg_pk = regNewData + 1 + pIdx->aiColumn[0]; -                if (pTab->zColAff[pIdx->aiColumn[0]] == +                reg_pk = regNewData + 1 + + pIdx->def->key_def->parts[0].fieldno; + +                int fieldno = (int) pIdx->def->key_def-> +                    parts[0].fieldno; +                if (pTab->zColAff[fieldno] ==                      AFFINITY_INTEGER) {                      int skip_if_null = sqlite3VdbeMakeLabel(v);                      if ((pTab->tabFlags & TF_Autoincrement) != 0) { @@ -1303,7 +1307,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,        /* The parser context */              sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData + 1,                        def->field_count, aRegIdx[ix]); -            VdbeComment((v, "for %s", pIdx->zName)); +            VdbeComment((v, "for %s", pIdx->def->name));          }          /* In an UPDATE operation, if this index is the PRIMARY KEY @@ -1391,7 +1395,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,        /* The parser context */          if (uniqueByteCodeNeeded) {              sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur,                           addrUniqueOk, regIdx, -                         index_column_count(pIdx)); + pIdx->def->key_def->part_count);          }          VdbeCoverage(v); @@ -1401,14 +1405,13 @@ sqlite3GenerateConstraintChecks(Parse * pParse,        /* The parser context */                                   nPkField);          if (isUpdate || on_error == ON_CONFLICT_ACTION_REPLACE) {              int x; -            int nPkCol = index_column_count(pPk); +            int nPkCol = pPk->def->key_def->part_count;              /* Extract the PRIMARY KEY from the end of the index entry and               * store it in registers regR..regR+nPk-1               */              if (pIdx != pPk) {                  for (i = 0; i < nPkCol; i++) { -                    assert(pPk->aiColumn[i] >= 0); -                    x = pPk->aiColumn[i]; +                    x = pPk->def->key_def->parts[i].fieldno;                      sqlite3VdbeAddOp3(v, OP_Column,                                iThisCur, x, regR + i);                      VdbeComment((v, "%s.%s", def->name, @@ -1430,10 +1433,10 @@ sqlite3GenerateConstraintChecks(Parse * pParse,        /* The parser context */                            regIdx : regR);                  for (i = 0; i < nPkCol; i++) { -                    uint32_t id; -                    char *p4 = (char *)sql_index_collation(pPk, i, &id); -                    x = pPk->aiColumn[i]; -                    assert(x >= 0); +                    char *p4 = (char *) pPk->def->key_def->parts[i].coll; +                    x = pPk->def->key_def->parts[i].fieldno; +                    if (pPk->tnum==0) +                        x = -1;                      if (i == (nPkCol - 1)) {                          addrJump = addrUniqueOk;                          op = OP_Eq; @@ -1610,8 +1613,8 @@ sqlite3OpenTableAndIndices(Parse * pParse,    /* Parsing context */              IsPrimaryKeyIndex(pIdx) ||        /* Condition 2 */              sqlite3FkReferences(pTab) ||    /* Condition 3 */              /* Condition 4 */ -            (index_is_unique(pIdx) && pIdx->onError != -             ON_CONFLICT_ACTION_DEFAULT && +            (pIdx->def->opts.is_unique && +             pIdx->onError != ON_CONFLICT_ACTION_DEFAULT &&               /* Condition 4.1 */               pIdx->onError != ON_CONFLICT_ACTION_ABORT) ||               /* Condition 4.2 */ @@ -1629,7 +1632,7 @@ sqlite3OpenTableAndIndices(Parse * pParse,    /* Parsing context */                            space_ptr_reg);                  sql_vdbe_set_p4_key_def(pParse, pIdx);                  sqlite3VdbeChangeP5(v, p5); -                VdbeComment((v, "%s", pIdx->zName)); +                VdbeComment((v, "%s", pIdx->def->name));              }          }      } @@ -1666,27 +1669,23 @@ xferCompatibleIndex(Index * pDest, Index * pSrc)      uint32_t i;      assert(pDest && pSrc);      assert(pDest->pTable != pSrc->pTable); -    uint32_t nDestCol = index_column_count(pDest); -    uint32_t nSrcCol = index_column_count(pSrc); +    uint32_t nDestCol = pDest->def->key_def->part_count; +    uint32_t nSrcCol = pSrc->def->key_def->part_count;      if (nDestCol != nSrcCol) {          return 0;    /* Different number of columns */      }      if (pDest->onError != pSrc->onError) {          return 0;    /* Different conflict resolution strategies */      } -    for (i = 0; i < nSrcCol; i++) { -        if (pSrc->aiColumn[i] != pDest->aiColumn[i]) { +    struct key_part *src_part = pSrc->def->key_def->parts; +    struct key_part *dest_part = pDest->def->key_def->parts; +    for (i = 0; i < nSrcCol; i++, src_part++, dest_part++) { +        if (src_part->fieldno != dest_part->fieldno)              return 0;    /* Different columns indexed */ -        } -        if (sql_index_column_sort_order(pSrc, i) != -            sql_index_column_sort_order(pDest, i)) { +        if (src_part->sort_order != dest_part->sort_order)              return 0;    /* Different sort orders */ -        } -        uint32_t id; -        if (sql_index_collation(pSrc, i, &id) != -            sql_index_collation(pDest, i, &id)) { +        if (src_part->coll != dest_part->coll)              return 0;    /* Different collating sequences */ -        }      }      if (sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1)) {          return 0;    /* Different WHERE clauses */ @@ -1858,16 +1857,15 @@ xferOptimization(Parse * pParse,    /* Parser context */          }      }      for (pDestIdx = pDest->pIndex; pDestIdx; pDestIdx = pDestIdx->pNext) { -        if (index_is_unique(pDestIdx)) { +        if (pDestIdx->def->opts.is_unique)              destHasUniqueIdx = 1; -        }          for (pSrcIdx = pSrc->pIndex; pSrcIdx; pSrcIdx = pSrcIdx->pNext) {              if (xferCompatibleIndex(pDestIdx, pSrcIdx))                  break;          } -        if (pSrcIdx == 0) { -            return 0;    /* pDestIdx has no corresponding index in pSrc */ -        } +        /* pDestIdx has no corresponding index in pSrc */ +        if (pSrcIdx == 0) +            return 0;      }      /* Get server checks. */      ExprList *pCheck_src = space_checks_expr_list( @@ -1943,12 +1941,12 @@ xferOptimization(Parse * pParse,    /* Parser context */          struct space *src_space = space_by_id(SQLITE_PAGENO_TO_SPACEID(pSrcIdx->tnum));          vdbe_emit_open_cursor(pParse, iSrc, pSrcIdx->tnum, src_space); -        VdbeComment((v, "%s", pSrcIdx->zName)); +        VdbeComment((v, "%s", pSrcIdx->def->name));          struct space *dest_space = space_by_id(SQLITE_PAGENO_TO_SPACEID(pDestIdx->tnum));          vdbe_emit_open_cursor(pParse, iDest, pDestIdx->tnum, dest_space);          sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); -        VdbeComment((v, "%s", pDestIdx->zName)); +        VdbeComment((v, "%s", pDestIdx->def->name));          addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);          VdbeCoverage(v);          sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData); diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c index 5fb29c75c..7067a5ab1 100644 --- a/src/box/sql/pragma.c +++ b/src/box/sql/pragma.c @@ -370,7 +370,8 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */                  k = 1;              } else {                  for (k = 1; k <= def->field_count && -                     pk->aiColumn[k - 1] != (int) i; ++k) { +                     pk->def->key_def->parts[k - 1].fieldno +                     != i; ++k) {                  }              }              bool is_nullable = def->fields[i].is_nullable; @@ -414,7 +415,7 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */                      size_t avg_tuple_size_idx =                          sql_index_tuple_size(space, idx);                      sqlite3VdbeMultiLoad(v, 2, "sii", -                                 pIdx->zName, +                                 pIdx->def->name,                                   avg_tuple_size_idx,                                   index_field_tuple_est(pIdx, 0));                      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, @@ -443,11 +444,13 @@ sqlite3Pragma(Parse * pParse, Token * pId,    /* First part of [schema.]id field */                           */                          pParse->nMem = 3;                      } -                    mx = index_column_count(pIdx); +                    mx = pIdx->def->key_def->part_count;                      assert(pParse->nMem <=                             pPragma->nPragCName); -                    for (i = 0; i < mx; i++) { -                        i16 cnum = pIdx->aiColumn[i]; +                    struct key_part *part = +                        pIdx->def->key_def->parts; +                    for (i = 0; i < mx; i++, part++) { +                        i16 cnum = (int) part->fieldno;                          assert(pIdx->pTable);                          sqlite3VdbeMultiLoad(v, 1,                                       "iis", i, @@ -461,19 +464,18 @@ sqlite3Pragma(Parse * pParse, Token * pId,    /* First part of [schema.]id field */                                       name);                          if (pPragma->iArg) {                              const char *c_n; -                            uint32_t id; +                            uint32_t id = +                                part->coll_id;                              struct coll *coll = -                                sql_index_collation(pIdx, i, &id); +                                part->coll;                              if (coll != NULL)                                  c_n = coll_by_id(id)->name;                              else                                  c_n = "BINARY"; -                            enum sort_order sort_order; -                            sort_order = sql_index_column_sort_order(pIdx, -                                                 i);                              sqlite3VdbeMultiLoad(v,                                           4,                                           "isi", +                                         part->                                           sort_order,                                           c_n,                                           i < @@ -503,10 +505,8 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */                              { "c", "u", "pk" };                          sqlite3VdbeMultiLoad(v, 1,                                       "isisi", i, -                                     pIdx-> -                                     zName, -                                     index_is_unique -                                     (pIdx), +                                     pIdx->def->name, + pIdx->def->opts.is_unique,                                       azOrigin                                       [pIdx->                                        idxType], diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 368bcd6f0..c7c186d9d 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -4367,7 +4367,7 @@ sqlite3IndexedByLookup(Parse * pParse, struct SrcList_item *pFrom)          char *zIndexedBy = pFrom->u1.zIndexedBy;          Index *pIdx;          for (pIdx = pTab->pIndex; -             pIdx && strcmp(pIdx->zName, zIndexedBy); +             pIdx && strcmp(pIdx->def->name, zIndexedBy);               pIdx = pIdx->pNext) ;          if (!pIdx) {              sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 47360fa5b..f696591fd 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -2070,27 +2070,17 @@ struct UnpackedRecord {   * Each SQL index is represented in memory by an   * instance of the following structure.   * - * The columns of the table that are to be indexed are described - * by the aiColumn[] field of this structure.  For example, suppose - * we have the following table and index: - * - *     CREATE TABLE Ex1(c1 int, c2 int, c3 text); - *     CREATE INDEX Ex2 ON Ex1(c3,c1); - * - * In the Table structure describing Ex1, nCol==3 because there are - * three columns in the table.  In the Index structure describing - * Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed. - * The value of aiColumn is {2, 0}.  aiColumn[0]==2 because the - * first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. - * The second column to be indexed (c1) has an index of 0 in - * Ex1.aCol[], hence Ex2.aiColumn[1]==0. - * - * The Index.onError field determines whether or not the indexed columns - * must be unique and what to do if they are not.  When Index.onError= - * ON_CONFLICT_ACTION_NONE, it means this is not a unique index. - * Otherwise it is a unique index and the value of Index.onError indicate - * the which conflict resolution algorithm to employ whenever an attempt - * is made to insert a non-unique element. + * Indexes name, corresponding space_id, type (in tarantool + * sense - HASH, TREE, etc) are stored in index definition - in + * Index.def. + * SQL statement which created the index and 'is_unique' flag are + * stored in Index.def.opts. Information about index parts (part + * count, corresponding space fields' numbers, parts' collations + * and sort orders, etc) are stored in Index.def.key_def.parts + * + * Index.onError indicate the which conflict resolution algorithm + * to employ whenever an attempt is made to insert a non-unique + * element in unique index.   *   * While parsing a CREATE TABLE or CREATE INDEX statement in order to   * generate VDBE code (as opposed to reading from Tarantool's _space @@ -2101,26 +2091,18 @@ struct UnpackedRecord {   * program is executed). See convertToWithoutRowidTable() for details.   */  struct Index { -    char *zName;        /* Name of this index */ -    i16 *aiColumn;        /* Which columns are used by this index.  1st is 0 */      LogEst *aiRowLogEst;    /* From ANALYZE: Est. rows selected by each column */      Table *pTable;        /* The SQL table being indexed */      char *zColAff;        /* String defining the affinity of each column */      Index *pNext;        /* The next index associated with the same table */      Schema *pSchema;    /* Schema containing this index */ -    /** Sorting order for each column. */ -    enum sort_order *sort_order; -    /** Array of collation sequences for index. */ -    struct coll **coll_array; -    /** Array of collation identifiers. */ -    uint32_t *coll_id_array;      Expr *pPartIdxWhere;    /* WHERE clause for partial indices */      int tnum;        /* DB Page containing root of this index */ -    u16 nColumn;        /* Number of columns stored in the index */      u8 onError;        /* ON_CONFLICT_ACTION_ABORT, _IGNORE, _REPLACE,                   * or _NONE                   */      unsigned idxType:2;    /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ +    struct index_def *def;  };  /** @@ -3546,34 +3528,6 @@ void sqlite3AddCollateType(Parse *, Token *);   */  struct coll *  sql_column_collation(struct space_def *def, uint32_t column, uint32_t *coll_id); -/** - * Return name of given column collation from index. - * - * @param idx Index which is used to fetch column. - * @param column Number of column. - * @param[out] coll_id Collation identifier. - * @retval Pointer to collation. - */ -struct coll * -sql_index_collation(Index *idx, uint32_t column, uint32_t *id); - -/** - * Return key_def of provided struct Index. - * @param idx Pointer to `struct Index` object. - * @retval Pointer to `struct key_def`. - */ -struct key_def* -sql_index_key_def(struct Index *idx); - -/** - * Return sort order of given column from index. - * - * @param idx Index which is used to fetch column. - * @param column Number of column. - * @retval Sort order of requested column. - */ -enum sort_order -sql_index_column_sort_order(Index *idx, uint32_t column);  void sqlite3EndTable(Parse *, Token *, Token *, Select *); @@ -3661,8 +3615,6 @@ void sqlite3SrcListAssignCursors(Parse *, SrcList *);  void sqlite3IdListDelete(sqlite3 *, IdList *);  void sqlite3SrcListDelete(sqlite3 *, SrcList *);  Index *sqlite3AllocateIndexObject(sqlite3 *, i16, int, char **); -bool -index_is_unique(Index *);  /**   * Create a new index for an SQL table.  name is the name of the @@ -4381,8 +4333,6 @@ int sqlite3InvokeBusyHandler(BusyHandler *);  int  sql_analysis_load(struct sqlite3 *db); -uint32_t -index_column_count(const Index *);  bool  index_is_unique_not_null(const Index *);  void sqlite3RegisterLikeFunctions(sqlite3 *, int); diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c index 042226cde..ad8e2438f 100644 --- a/src/box/sql/trigger.c +++ b/src/box/sql/trigger.c @@ -873,8 +873,6 @@ codeRowTrigger(Parse * pParse,    /* Current parse context */      pSubParse->pToplevel = pTop;      pSubParse->eTriggerOp = pTrigger->op;      pSubParse->nQueryLoop = pParse->nQueryLoop; -    struct region *region = &fiber()->gc; -    pSubParse->region_initial_size = region_used(region);      v = sqlite3GetVdbe(pSubParse);      if (v) { diff --git a/src/box/sql/update.c b/src/box/sql/update.c index 10385eb78..fc479fb05 100644 --- a/src/box/sql/update.c +++ b/src/box/sql/update.c @@ -238,14 +238,14 @@ sqlite3Update(Parse * pParse,        /* The parser context */       */      for (j = 0, pIdx = pTab->pIndex; pIdx; pIdx = pIdx->pNext, j++) {          int reg; -        int nIdxCol = index_column_count(pIdx); +        int nIdxCol = pIdx->def->key_def->part_count;          if (chngPk || hasFK || pIdx->pPartIdxWhere || pIdx == pPk) {              reg = ++pParse->nMem;              pParse->nMem += nIdxCol;          } else {              reg = 0;              for (i = 0; i < nIdxCol; i++) { -                i16 iIdxCol = pIdx->aiColumn[i]; +                i16 iIdxCol = pIdx->def->key_def->parts[i].fieldno;                  if (iIdxCol < 0 || aXRef[iIdxCol] >= 0) {                      reg = ++pParse->nMem;                      pParse->nMem += nIdxCol; @@ -307,7 +307,7 @@ sqlite3Update(Parse * pParse,        /* The parser context */          nPk = nKey;      } else {          assert(pPk != 0); -        nPk = index_column_count(pPk); +        nPk = pPk->def->key_def->part_count;      }      iPk = pParse->nMem + 1;      pParse->nMem += nPk; @@ -334,9 +334,9 @@ sqlite3Update(Parse * pParse,        /* The parser context */          }      } else {          for (i = 0; i < nPk; i++) { -            assert(pPk->aiColumn[i] >= 0);              sqlite3ExprCodeGetColumnOfTable(v, def, iDataCur, -                            pPk->aiColumn[i], +                            pPk->def->key_def-> +                                parts[i].fieldno,                              iPk + i);          }      } diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 679bd0bc1..520b309d9 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -1165,7 +1165,7 @@ sql_vdbe_set_p4_key_def(struct Parse *parse, struct Index *idx)      struct Vdbe *v = parse->pVdbe;      assert(v != NULL);      assert(idx != NULL); -    struct key_def *def = key_def_dup(sql_index_key_def(idx)); +    struct key_def *def = key_def_dup(idx->def->key_def);      if (def == NULL)          sqlite3OomFault(parse->db);      else diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c index f408b7701..51b5d516e 100644 --- a/src/box/sql/vdbemem.c +++ b/src/box/sql/vdbemem.c @@ -1087,7 +1087,7 @@ valueNew(sqlite3 * db, struct ValueNewStat4Ctx *p)              Index *pIdx = p->pIdx;    /* Index being probed */              int nByte;    /* Bytes of space to allocate */              int i;    /* Counter variable */ -            int nCol = index_column_count(pIdx); +            int nCol = pIdx->def->key_def->part_count;              nByte = sizeof(Mem) * nCol +                  ROUND8(sizeof(UnpackedRecord)); @@ -1095,7 +1095,7 @@ valueNew(sqlite3 * db, struct ValueNewStat4Ctx *p)                  (UnpackedRecord *) sqlite3DbMallocZero(db, nByte);              if (pRec == NULL)                  return NULL; -            pRec->key_def = key_def_dup(sql_index_key_def(pIdx)); +            pRec->key_def = key_def_dup(pIdx->def->key_def);              if (pRec->key_def == NULL) {                  sqlite3DbFree(db, pRec);                  sqlite3OomFault(db); diff --git a/src/box/sql/where.c b/src/box/sql/where.c index e6c34f34a..3f95c4243 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -372,13 +372,19 @@ whereScanInit(WhereScan * pScan,    /* The WhereScan object being initialized */      pScan->is_column_seen = false;      if (pIdx) {          int j = iColumn; -        iColumn = pIdx->aiColumn[j]; +        iColumn = pIdx->def->key_def->parts[j].fieldno; +        /* +         * pIdx->tnum == 0 means that pIdx is a fake +         * integer primary key index +         */ +        if (pIdx->tnum == 0) +            iColumn = -1; +          if (iColumn >= 0) {              char affinity = pIdx->pTable->def->fields[iColumn].affinity;              pScan->idxaff = affinity; -            uint32_t id; -            pScan->coll = sql_index_collation(pIdx, j, &id); +            pScan->coll = pIdx->def->key_def->parts[j].coll;              pScan->is_column_seen = true;          }      } @@ -541,47 +547,24 @@ findIndexCol(Parse * pParse,    /* Parse context */           Index * pIdx,    /* Index to match column of */           int iCol)        /* Column of index to match */  { +    struct key_part *part_to_match = &pIdx->def->key_def->parts[iCol];      for (int i = 0; i < pList->nExpr; i++) {          Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr); -        if (p->op == TK_COLUMN && -            p->iColumn == pIdx->aiColumn[iCol] && -            p->iTable == iBase) { +        if (p->op == TK_COLUMN && p->iTable == iBase && +            p->iColumn == (int) part_to_match->fieldno) {              bool is_found;              uint32_t id;              struct coll *coll = sql_expr_coll(pParse,                                pList->a[i].pExpr,                                &is_found, &id); -            if (is_found && -                coll == sql_index_collation(pIdx, iCol, &id)) { +            if (is_found && coll == part_to_match->coll)                  return i; -            }          }      }      return -1;  } -/* - * Return TRUE if the iCol-th column of index pIdx is NOT NULL - */ -static int -indexColumnNotNull(Index * pIdx, int iCol) -{ -    int j; -    assert(pIdx != 0); -    assert(iCol >= 0 && iCol < (int)index_column_count(pIdx)); -    j = pIdx->aiColumn[iCol]; -    if (j >= 0) { -        return !pIdx->pTable->def->fields[j].is_nullable; -    } else if (j == (-1)) { -        return 1; -    } else { -        assert(j == (-2)); -        return 0;    /* Assume an indexed expression can always yield a NULL */ - -    } -} -  /*   * Return true if the DISTINCT expression-list passed as the third argument   * is redundant. @@ -633,9 +616,9 @@ isDistinctRedundant(Parse * pParse,        /* Parsing context */       *      contain a "col=X" term are subject to a NOT NULL constraint.       */      for (pIdx = pTab->pIndex; pIdx; pIdx = pIdx->pNext) { -        if (!index_is_unique(pIdx)) +        if (!pIdx->def->opts.is_unique)              continue; -        int col_count = index_column_count(pIdx); +        int col_count = pIdx->def->key_def->part_count;          for (i = 0; i < col_count; i++) {              if (0 ==                  sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask) 0, @@ -643,11 +626,12 @@ isDistinctRedundant(Parse * pParse, /* Parsing context */                  if (findIndexCol                      (pParse, pDistinct, iBase, pIdx, i) < 0)                      break; -                if (indexColumnNotNull(pIdx, i) == 0) +                uint32_t j = pIdx->def->key_def->parts[i].fieldno; +                if (pIdx->pTable->def->fields[j].is_nullable)                      break;              }          } -        if (i == (int)index_column_count(pIdx)) { +        if (i == (int) pIdx->def->key_def->part_count) {              /* This index implies that the DISTINCT qualifier is redundant. */              return 1;          } @@ -1184,7 +1168,7 @@ whereRangeAdjust(WhereTerm * pTerm, LogEst nNew)  char  sqlite3IndexColumnAffinity(sqlite3 * db, Index * pIdx, int iCol)  { -    assert(iCol >= 0 && iCol < (int)index_column_count(pIdx)); +    assert(iCol >= 0 && iCol < (int) pIdx->def->key_def->part_count);      if (!pIdx->zColAff) {          if (sqlite3IndexAffinityStr(db, pIdx) == 0)              return AFFINITY_BLOB; @@ -1246,13 +1230,12 @@ whereRangeSkipScanEst(Parse * pParse,     /* Parsing & code generating context */      int nUpper = index->def->opts.stat->sample_count + 1;      int rc = SQLITE_OK;      u8 aff = sqlite3IndexColumnAffinity(db, p, nEq); -    uint32_t id;      sqlite3_value *p1 = 0;    /* Value extracted from pLower */      sqlite3_value *p2 = 0;    /* Value extracted from pUpper */      sqlite3_value *pVal = 0;    /* Value extracted from record */ -    struct coll *pColl = sql_index_collation(p, nEq, &id); +    struct coll *pColl = p->def->key_def->parts[nEq].coll;      if (pLower) {          rc = sqlite3Stat4ValueFromExpr(pParse, pLower->pExpr->pRight,                             aff, &p1); @@ -1448,7 +1431,7 @@ whereRangeScanEst(Parse * pParse,    /* Parsing & code generating context */                     || (pLower->eOperator & (WO_GT | WO_GE)) != 0);              assert(pUpper == 0                     || (pUpper->eOperator & (WO_LT | WO_LE)) != 0); -            if (sql_index_column_sort_order(p, nEq) != +            if (p->def->key_def->parts[nEq].sort_order !=                  SORT_ORDER_ASC) {                  /* The roles of pLower and pUpper are swapped for a DESC index */                  SWAP(pLower, pUpper); @@ -1598,7 +1581,7 @@ whereEqualScanEst(Parse * pParse,    /* Parsing & code generating context */      int bOk;      assert(nEq >= 1); -    assert(nEq <= (int)index_column_count(p)); +    assert(nEq <= (int) p->def->key_def->part_count);      assert(pBuilder->nRecValid < nEq);      /* If values are not available for all fields of the index to the left @@ -1619,7 +1602,7 @@ whereEqualScanEst(Parse * pParse,    /* Parsing & code generating context */      whereKeyStats(pParse, p, pRec, 0, a);      WHERETRACE(0x10, ("equality scan regions %s(%d): %d\n", -              p->zName, nEq - 1, (int)a[1])); +              p->def->name, nEq - 1, (int)a[1]));      *pnRow = a[1];      return rc; @@ -1751,7 +1734,7 @@ whereLoopPrint(WhereLoop * p, WhereClause * pWC)                 pItem->zAlias ? pItem->zAlias : pTab->def->name);  #endif      const char *zName; -    if (p->pIndex && (zName = p->pIndex->zName) != 0) { +    if (p->pIndex && (zName = p->pIndex->def->name) != 0) {          if (strncmp(zName, "sqlite_autoindex_", 17) == 0) {              int i = sqlite3Strlen30(zName) - 1;              while (zName[i] != '_') @@ -2314,7 +2297,7 @@ whereRangeVectorLen(Parse * pParse,    /* Parsing context */      int nCmp = sqlite3ExprVectorSize(pTerm->pExpr->pLeft);      int i; -    nCmp = MIN(nCmp, (int)(index_column_count(pIdx) - nEq)); +    nCmp = MIN(nCmp, (int)(pIdx->def->key_def->part_count - nEq));      for (i = 1; i < nCmp; i++) {          /* Test if comparison i of pTerm is compatible with column (i+nEq)           * of the index. If not, exit the loop. @@ -2335,13 +2318,11 @@ whereRangeVectorLen(Parse * pParse,    /* Parsing context */           * order of the index column is the same as the sort order of the           * leftmost index column.           */ -        if (pLhs->op != TK_COLUMN -            || pLhs->iTable != iCur -            || pLhs->iColumn != pIdx->aiColumn[i + nEq] -            || sql_index_column_sort_order(pIdx, i + nEq) != -               sql_index_column_sort_order(pIdx, nEq)) { +        if (pLhs->op != TK_COLUMN || pLhs->iTable != iCur +            || pLhs->iColumn != (int)pIdx->def->key_def->parts[i + nEq].fieldno +            || pIdx->def->key_def->parts[i + nEq].sort_order != + pIdx->def->key_def->parts[nEq].sort_order)              break; -        }          aff = sqlite3CompareAffinity(pRhs, sqlite3ExprAffinity(pLhs));          idxaff = @@ -2353,7 +2334,7 @@ whereRangeVectorLen(Parse * pParse,    /* Parsing context */          pColl = sql_binary_compare_coll_seq(pParse, pLhs, pRhs, &id);          if (pColl == 0)              break; -            if (sql_index_collation(pIdx, i + nEq, &id) != pColl) +        if (pIdx->def->key_def->parts[(i + nEq)].coll != pColl)              break;      }      return i; @@ -2396,13 +2377,13 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder,    /* The WhereLoop factory */      LogEst rSize;        /* Number of rows in the table */      LogEst rLogSize;    /* Logarithm of table size */      WhereTerm *pTop = 0, *pBtm = 0;    /* Top and bottom range constraints */ -    uint32_t nProbeCol = index_column_count(pProbe); +    uint32_t nProbeCol = pProbe->def->key_def->part_count;      pNew = pBuilder->pNew;      if (db->mallocFailed)          return SQLITE_NOMEM_BKPT;      WHERETRACE(0x800, ("BEGIN addBtreeIdx(%s), nEq=%d\n", -               pProbe->zName, pNew->nEq)); +               pProbe->def->name, pNew->nEq));      assert((pNew->wsFlags & WHERE_TOP_LIMIT) == 0);      if (pNew->wsFlags & WHERE_BTM_LIMIT) { @@ -2452,8 +2433,9 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder,    /* The WhereLoop factory */          LogEst nOutUnadjusted;    /* nOut before IN() and WHERE adjustments */          int nIn = 0;          int nRecValid = pBuilder->nRecValid; +        uint32_t j = pProbe->def->key_def->parts[saved_nEq].fieldno;          if ((eOp == WO_ISNULL || (pTerm->wtFlags & TERM_VNULL) != 0) -            && indexColumnNotNull(pProbe, saved_nEq) +            && !pProbe->pTable->def->fields[j].is_nullable              ) {              continue;    /* ignore IS [NOT] NULL constraints on NOT NULL columns */          } @@ -2523,14 +2505,16 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder,    /* The WhereLoop factory */                               */              }          } else if (eOp & WO_EQ) { -            int iCol = pProbe->aiColumn[saved_nEq]; +            int iCol = pProbe->def->key_def->parts[saved_nEq].fieldno;              pNew->wsFlags |= WHERE_COLUMN_EQ;              assert(saved_nEq == pNew->nEq); -            if ((iCol > 0 && nInMul == 0 -                && saved_nEq == nProbeCol - 1) -                ) { -                if (iCol >= 0 && -                    !index_is_unique_not_null(pProbe)) { +            if ((iCol > 0 && nInMul == 0 && +                 saved_nEq == nProbeCol - 1)) { +                bool index_is_unique_not_null = +                    pProbe->def->key_def->is_nullable && +                    pProbe->def->opts.is_unique; +                if (pProbe->tnum != 0 && +                    !index_is_unique_not_null) {                      pNew->wsFlags |= WHERE_UNQ_WANTED;                  } else {                      pNew->wsFlags |= WHERE_ONEROW; @@ -2592,8 +2576,7 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder,    /* The WhereLoop factory */              assert(eOp & (WO_ISNULL | WO_EQ | WO_IN));              assert(pNew->nOut == saved_nOut); -            if (pTerm->truthProb <= 0 -                && pProbe->aiColumn[saved_nEq] >= 0) { +            if (pTerm->truthProb <= 0 && pProbe->tnum != 0 ) {                  assert((eOp & WO_IN) || nIn == 0);                  testcase(eOp & WO_IN);                  pNew->nOut += pTerm->truthProb; @@ -2749,7 +2732,7 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder,    /* The WhereLoop factory */      }      WHERETRACE(0x800, ("END addBtreeIdx(%s), nEq=%d, rc=%d\n", -               pProbe->zName, saved_nEq, rc)); +               pProbe->def->name, saved_nEq, rc));      return rc;  } @@ -2792,7 +2775,7 @@ indexMightHelpWithOrderBy(WhereLoopBuilder * pBuilder,  {      ExprList *pOB;      int ii, jj; -    int nIdxCol = index_column_count(pIndex); +    int nIdxCol = pIndex->def->key_def->part_count;      if (index_is_unordered(pIndex))          return 0;      if ((pOB = pBuilder->pWInfo->pOrderBy) == 0) @@ -2803,7 +2786,8 @@ indexMightHelpWithOrderBy(WhereLoopBuilder * pBuilder,              if (pExpr->iColumn < 0)                  return 1;              for (jj = 0; jj < nIdxCol; jj++) { -                if (pExpr->iColumn == pIndex->aiColumn[jj]) +                if (pExpr->iColumn == (int) + pIndex->def->key_def->parts[jj].fieldno)                      return 1;              }          } @@ -2882,7 +2866,6 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder,    /* WHERE clause information */      Index *pProbe;        /* An index we are evaluating */      Index sPk;        /* A fake index object for the primary key */      LogEst aiRowEstPk[2];    /* The aiRowLogEst[] value for the sPk index */ -    i16 aiColumnPk = -1;    /* The aColumn[] value for the sPk index */      SrcList *pTabList;    /* The FROM clause */      struct SrcList_item *pSrc;    /* The FROM clause btree term to add */      WhereLoop *pNew;    /* Template WhereLoop object */ @@ -2913,11 +2896,29 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder,    /* WHERE clause information */           */          Index *pFirst;    /* First of real indices on the table */          memset(&sPk, 0, sizeof(Index)); -        sPk.nColumn = 1; -        sPk.aiColumn = &aiColumnPk;          sPk.aiRowLogEst = aiRowEstPk;          sPk.onError = ON_CONFLICT_ACTION_REPLACE;          sPk.pTable = pTab; + +        struct key_def *key_def = key_def_new(1); +        if (key_def == NULL) +            return SQLITE_ERROR; + +        key_def_set_part(key_def, 0, 0, pTab->def->fields[0].type, +                 ON_CONFLICT_ACTION_ABORT, +                 NULL, COLL_NONE, SORT_ORDER_ASC); + +        struct index_opts index_opts = index_opts_default; + +        sPk.def = index_def_new(pTab->def->id, 0, "primary", +                    sizeof("primary") - 1, TREE, &index_opts, +                    key_def, NULL); +        key_def_delete(key_def); + +        if (sPk.def == NULL) { +            return SQLITE_ERROR; +        } +          aiRowEstPk[0] = sql_space_tuple_log_count(pTab);          aiRowEstPk[1] = 0;          pFirst = pSrc->pTab->pIndex; @@ -3392,8 +3393,8 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo,    /* The WHERE clause */                     index_is_unordered(pIndex)) {                  return 0;              } else { -                nColumn = index_column_count(pIndex); -                isOrderDistinct = index_is_unique(pIndex); +                nColumn = pIndex->def->key_def->part_count; +                isOrderDistinct = pIndex->def->opts.is_unique;              }              /* Loop through all columns of the index and deal with the ones @@ -3454,9 +3455,10 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo,    /* The WHERE clause */                   * (revIdx) for the j-th column of the index.                   */                  if (pIndex != NULL) { -                    iColumn = pIndex->aiColumn[j]; -                    revIdx = sql_index_column_sort_order(pIndex, -                                         j); +                    iColumn = pIndex->def->key_def-> +                        parts[j].fieldno; +                    revIdx = pIndex->def->key_def-> +                        parts[j].sort_order;                      if (iColumn == pIndex->pTable->iPKey)                          iColumn = -1;                  } else { @@ -3506,8 +3508,7 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo,    /* The WHERE clause */                                        pOrderBy->a[i].pExpr,                                        &is_found, &id);                          struct coll *idx_coll = -                            sql_index_collation(pIndex, -                                        j, &id); + pIndex->def->key_def->parts[j].coll;                          if (is_found &&                              coll != idx_coll)                              continue; @@ -4785,7 +4786,7 @@ sqlite3WhereBegin(Parse * pParse,    /* The parser context */                      sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ);    /* Hint to COMDB2 */                  }                  if (pIx != NULL) -                    VdbeComment((v, "%s", pIx->zName)); +                    VdbeComment((v, "%s", pIx->def->name));                  else                      VdbeComment((v, "%s", idx_def->name));  #ifdef SQLITE_ENABLE_COLUMN_USED_MASK @@ -4918,7 +4919,7 @@ sqlite3WhereEnd(WhereInfo * pWInfo)          if (pLevel->addrSkip) {              sqlite3VdbeGoto(v, pLevel->addrSkip);              VdbeComment((v, "next skip-scan on %s", -                     pLoop->pIndex->zName)); +                     pLoop->pIndex->def->name));              sqlite3VdbeJumpHere(v, pLevel->addrSkip);              sqlite3VdbeJumpHere(v, pLevel->addrSkip - 2);          } diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index eaab0b657..a04013835 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -48,7 +48,7 @@  static const char *  explainIndexColumnName(Index * pIdx, int i)  { -    i = pIdx->aiColumn[i]; +    i = pIdx->def->key_def->parts[i].fieldno;      return pIdx->pTable->def->fields[i].name;  } @@ -243,7 +243,7 @@ sqlite3WhereExplainOneScan(Parse * pParse, /* Parse context */              if (zFmt) {                  sqlite3StrAccumAppend(&str, " USING ", 7);                  if (pIdx != NULL) -                    sqlite3XPrintf(&str, zFmt, pIdx->zName); +                    sqlite3XPrintf(&str, zFmt, pIdx->def->name);                  else if (idx_def != NULL)                      sqlite3XPrintf(&str, zFmt, idx_def->name);                  else @@ -488,7 +488,7 @@ codeEqualityTerm(Parse * pParse,    /* The parsing context */          int *aiMap = 0;          if (pLoop->pIndex != 0 && -            sql_index_column_sort_order(pLoop->pIndex, iEq)) { + pLoop->pIndex->def->key_def->parts[iEq].sort_order) {              testcase(iEq == 0);              testcase(bRev);              bRev = !bRev; @@ -736,7 +736,7 @@ codeAllEqualityTerms(Parse * pParse,    /* Parsing context */          sqlite3VdbeAddOp1(v, (bRev ? OP_Last : OP_Rewind), iIdxCur);          VdbeCoverageIf(v, bRev == 0);          VdbeCoverageIf(v, bRev != 0); -        VdbeComment((v, "begin skip-scan on %s", pIdx->zName)); +        VdbeComment((v, "begin skip-scan on %s", pIdx->def->name));          j = sqlite3VdbeAddOp0(v, OP_Goto);          pLevel->addrSkip =              sqlite3VdbeAddOp4Int(v, (bRev ? OP_SeekLT : OP_SeekGT), @@ -746,7 +746,8 @@ codeAllEqualityTerms(Parse * pParse,    /* Parsing context */          sqlite3VdbeJumpHere(v, j);          for (j = 0; j < nSkip; j++) {              sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, -                      pIdx->aiColumn[j], regBase + j); + pIdx->def->key_def->parts[j].fieldno, +                      regBase + j);              VdbeComment((v, "%s", explainIndexColumnName(pIdx, j)));          }      } @@ -1275,12 +1276,12 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,    /* Complete information about t                 || (pWInfo->wctrlFlags & WHERE_ORDERBY_MIN) == 0);          int nIdxCol;          if (pIdx != NULL) -            nIdxCol = index_column_count(pIdx); +            nIdxCol = pIdx->def->key_def->part_count;          else              nIdxCol = idx_def->key_def->part_count;          if ((pWInfo->wctrlFlags & WHERE_ORDERBY_MIN) != 0              && pWInfo->nOBSat > 0 && (nIdxCol > nEq)) { -            j = pIdx->aiColumn[nEq]; +            j = pIdx->def->key_def->parts[nEq].fieldno;              /* Allow seek for column with `NOT NULL` == false attribute.               * If a column may contain NULL-s, the comparator installed               * by Tarantool is prepared to seek using a NULL value. @@ -1291,8 +1292,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,    /* Complete information about t               * FYI: entries in an index are ordered as follows:               *      NULL, ... NULL, min_value, ...               */ -            if (j >= 0 && - pIdx->pTable->def->fields[j].is_nullable) { +            if (pIdx->pTable->def->fields[j].is_nullable) {                  assert(pLoop->nSkip == 0);                  bSeekPastNull = 1;                  nExtraReg = 1; @@ -1331,14 +1331,14 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,    /* Complete information about t                  assert((bRev & ~1) == 0);                  pLevel->iLikeRepCntr <<= 1;                  pLevel->iLikeRepCntr |= -                    bRev ^ (sql_index_column_sort_order(pIdx, nEq) == +                    bRev ^ (pIdx->def->key_def-> +                          parts[nEq].sort_order ==                          SORT_ORDER_DESC);              }  #endif              if (pRangeStart == 0) { -                j = pIdx->aiColumn[nEq]; -                if (j >= 0 && - pIdx->pTable->def->fields[j].is_nullable) +                j = pIdx->def->key_def->parts[nEq].fieldno; +                if (pIdx->pTable->def->fields[j].is_nullable)                      bSeekPastNull = 1;              }          } @@ -1350,7 +1350,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,    /* Complete information about t           * start and end terms (pRangeStart and pRangeEnd).           */          if ((nEq < nIdxCol && -             bRev == (sql_index_column_sort_order(pIdx, nEq) == +             bRev == (pIdx->def->key_def->parts[nEq].sort_order ==                    SORT_ORDER_ASC)) ||              (bRev && nIdxCol == nEq)) {              SWAP(pRangeEnd, pRangeStart); @@ -1433,13 +1433,14 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,    /* Complete information about t              }          } else {              pk = sqlite3PrimaryKeyIndex(pIdx->pTable); +            uint32_t fieldno = pk->def->key_def->parts[0].fieldno;              affinity = - pIdx->pTable->def->fields[pk->aiColumn[0]].affinity; + pIdx->pTable->def->fields[fieldno].affinity;          }          int nPkCol;          if (pk != NULL) -            nPkCol = index_column_count(pk); +            nPkCol = pk->def->key_def->part_count;          else              nPkCol = idx_pk->key_def->part_count;          if (nPkCol == 1 && affinity == AFFINITY_INTEGER) { @@ -1450,8 +1451,9 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,    /* Complete information about t               */              int limit = pRangeStart == NULL ? nEq : nEq + 1;              for (int i = 0; i < limit; i++) { -                if ((pIdx != NULL && pIdx->aiColumn[i] == -                     pk->aiColumn[0]) || +                if ((pIdx != NULL && + pIdx->def->key_def->parts[i].fieldno == +                     pk->def->key_def->parts[0].fieldno) ||                      (idx_pk != NULL &&                       idx_def->key_def->parts[i].fieldno ==                       idx_pk->key_def->parts[0].fieldno)) { @@ -1563,10 +1565,10 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,    /* Complete information about t              /* pIdx is a covering index.  No need to access the main table. */          }  else if (iCur != iIdxCur) {              Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); -            int nPkCol = index_column_count(pPk); +            int nPkCol = pPk->def->key_def->part_count;              int iKeyReg = sqlite3GetTempRange(pParse, nPkCol);              for (j = 0; j < nPkCol; j++) { -                k = pPk->aiColumn[j]; +                k = pPk->def->key_def->parts[j].fieldno;                  sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k,                            iKeyReg + j);              } @@ -1671,7 +1673,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,    /* Complete information about t           */          if ((pWInfo->wctrlFlags & WHERE_DUPLICATES_OK) == 0) {              Index *pPk = sqlite3PrimaryKeyIndex(pTab); -            int nPkCol = index_column_count(pPk); +            int nPkCol = pPk->def->key_def->part_count;              regRowset = pParse->nTab++;              sqlite3VdbeAddOp2(v, OP_OpenTEphemeral,                        regRowset, nPkCol); @@ -1775,13 +1777,16 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,    /* Complete information about t                          int iSet =                              ((ii == pOrWc->nTerm - 1) ? -1 : ii);                          Index *pPk = sqlite3PrimaryKeyIndex (pTab); -                        int nPk = index_column_count(pPk); +                        int nPk = pPk->def->key_def->part_count;                          int iPk;                          /* Read the PK into an array of temp registers. */                          r = sqlite3GetTempRange(pParse, nPk);                          for (iPk = 0; iPk < nPk; iPk++) { -                            int iCol = pPk->aiColumn[iPk]; +                            int iCol = pPk->def-> +                                key_def-> +                                parts[iPk]. +                                fieldno;                              sqlite3ExprCodeGetColumnToReg                                  (pParse, pTab->def,                                   iCol, iCur, --