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 7300725389 for ; Mon, 18 Jun 2018 14:45:32 -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 40zZ22elY3c0 for ; Mon, 18 Jun 2018 14:45:32 -0400 (EDT) Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (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 E9FFB251C7 for ; Mon, 18 Jun 2018 14:45:30 -0400 (EDT) Subject: [tarantool-patches] Re: [PATCH v3] sql: add index_def to struct Index References: <9A0A687D-2E0B-4AB9-B223-1A1287817824@tarantool.org> From: Kirill Shcherbatov Message-ID: Date: Mon, 18 Jun 2018 21:45:27 +0300 MIME-Version: 1.0 In-Reply-To: <9A0A687D-2E0B-4AB9-B223-1A1287817824@tarantool.org> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org, Ivan Koptelov Cc: "v.shpilevoy@tarantool.org" 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); >> >> /* 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); >> 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. >> +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. >> + 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. >> + >> + 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; >> 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. >> 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; - } >> 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; >> } >> /* 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? >> + 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. >> + 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; - } >> } >> @@ -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. >> 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; - } >> >> @@ -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. >> + >> 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. >> return 0; >> } >> >> --