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