[tarantool-patches] Re: [PATCH 2/2] sql: replace KeyInfo with key_def
Kirill Yukhin
kyukhin at tarantool.org
Fri May 11 15:56:23 MSK 2018
Hi Vlad,
On 11 мая 14:22, Vladislav Shpilevoy wrote:
>
> Hello. Thanks for fixes. See travis: https://travis-ci.org/tarantool/tarantool/jobs/377267310.
>
> See 10 comments below.
Thanks, I've updated the patch (in the bottom). Answers inlined.
> > diff --git a/src/box/sql/build.c b/src/box/sql/build.c
> > index 029c71e..bfaf3af 100644
> > --- a/src/box/sql/build.c
> > +++ b/src/box/sql/build.c
> > @@ -1119,10 +1131,9 @@ sql_index_collation(Index *idx, uint32_t column)
> > return idx->coll_array[column];
> > }
> > - uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum);
> > - struct index *index = space_index(space, index_id);
> > - assert(index != NULL && index->def->key_def->part_count >= column);
> > - return index->def->key_def->parts[column].coll;
> > + struct key_def *key_def = sql_index_key_def(idx);
>
> 1. Sql_index_key_def makes dup, that is not needed to get the collation.
>
> 2. It leaks.
I've added a flag which signals if duplication is needed to sql_index_key_def.
> > + assert(key_def != NULL && key_def->part_count >= column);
>
> 3. Assertion can fail on OOM.
No more mallocs, see p 1, 2.
> > @@ -1143,10 +1154,9 @@ sql_index_column_sort_order(Index *idx, uint32_t column)
> > return idx->sort_order[column];
> > }
> > - uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum);
> > - struct index *index = space_index(space, index_id);
> > - assert(index != NULL && index->def->key_def->part_count >= column);
> > - return index->def->key_def->parts[column].sort_order;
> > + 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;
>
> 4. All the same. Maybe it is better to do not dup key_def in sql_index_key_def
> and just return it as is. And do dup() in caller code.
Ditto.
> > @@ -2643,14 +2650,13 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage)
> > } else {
> > tnum = pIndex->tnum;
> > }
> > - pKey = sqlite3KeyInfoOfIndex(pParse, db, pIndex);
> > - assert(pKey != 0 || db->mallocFailed || pParse->nErr);
> > + struct key_def *def = sql_index_key_def(pIndex);
> > + assert(def != NULL || db->mallocFailed || pParse->nErr);
>
> 5. Assertion can fail - when sql_index_key_def fails to do dup(),
> it does not set mallocFailed and nErr.
Ditto.
> > diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
> > index 3f74b93..b6fc135 100644
> > --- a/src/box/sql/delete.c
> > +++ b/src/box/sql/delete.c
> > @@ -386,10 +386,10 @@ sqlite3DeleteFrom(Parse * pParse, /* The parser context */
> > iPk = pParse->nMem + 1;
> > pParse->nMem += nPk;
> > iEphCur = pParse->nTab++;
> > - KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nPk, 0);
> > + struct key_def *def = key_def_new(nPk);
>
> 6. Nobody sets pParse->rc. Maybe it is better to declare a function like
> parser_key_def_new, that takes all the same as key_def + struct Parse, and sets
> rc = SQL_TARANTOOL_ERROR to get OOM from diag.
I think we should refactor all error reporting, so no need to do that right now.
I've added check for OOM.
> > diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
> > index cc969ca..635357b 100644
> > --- a/src/box/sql/expr.c
> > +++ b/src/box/sql/expr.c
> > @@ -1766,10 +1766,13 @@ sqlite3ExprListSetSortOrder(ExprList * p, int iSortOrder)
> > return;
> > assert(p->nExpr > 0);
> > if (iSortOrder == SORT_ORDER_UNDEF) {
> > - assert(p->a[p->nExpr - 1].sortOrder == SORT_ORDER_ASC);
> > + assert(p->a[p->nExpr - 1].sort_order == SORT_ORDER_ASC);
> > return;
> > }
> > - p->a[p->nExpr - 1].sortOrder = (u8) iSortOrder;
> > + if (iSortOrder == 0)
> > + p->a[p->nExpr - 1].sort_order = SORT_ORDER_ASC;
> > + else
> > + p->a[p->nExpr - 1].sort_order = SORT_ORDER_DESC;
>
> 7. Lets make iSortOrder be enum sort_order and remove this 'if's.
Done. Refactored sqlite3CreateIndex() as well
> > @@ -2761,7 +2763,7 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */
> > pExpr->is_ephemeral = 1;
> > addr = sqlite3VdbeAddOp2(v, OP_OpenTEphemeral,
> > pExpr->iTable, nVal);
> > - pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
> > + struct key_def *key_def = key_def_new(nVal);
>
> 8. pParse->rc is not set to error.
Fixed.
> > @@ -2787,29 +2789,34 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */
> > pSelect->iLimit = 0;
> > testcase(pSelect->
> > selFlags & SF_Distinct);
> > - testcase(pKeyInfo == 0); /* Caused by OOM in sqlite3KeyInfoAlloc() */
> > if (sqlite3Select
> > (pParse, pSelect, &dest)) {
> > sqlite3DbFree(pParse->db,
> > dest.zAffSdst);
> > - sqlite3KeyInfoUnref(pKeyInfo);
> > + if (key_def != NULL)
> > + free(key_def);
> > return 0;
> > }
> > sqlite3DbFree(pParse->db,
> > dest.zAffSdst);
> > - assert(pKeyInfo != 0); /* OOM will cause exit after sqlite3Select() */
> > + assert(key_def != NULL);
>
> 9. Assertion fails, if key_def == NULL. Maybe it is better to check key_def == NULL once right
> after key_def_new, return on error, and remove this 'if (key_def != NULL)' everywhere.
Done.
> > diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
> > index 1a34f71..95a2610 100644
> > --- a/src/box/sql/insert.c
> > +++ b/src/box/sql/insert.c
> > @@ -565,9 +565,9 @@ sqlite3Insert(Parse * pParse, /* Parser context */
> > regRec = sqlite3GetTempReg(pParse);
> > regCopy = sqlite3GetTempRange(pParse, nColumn);
> > regTempId = sqlite3GetTempReg(pParse);
> > - KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, 1+nColumn, 0);
> > + struct key_def *def = key_def_new(nColumn + 1);
>
> 10. No error code is set. I will not repeat this comment below, but the error code is not
> set in more places.
Fixed.
--
Regards, Kirill Yukhin
commit db01ff515830b422ee7a874f5c0d34e6814222c5
Author: Kirill Yukhin <kyukhin at tarantool.org>
Date: Fri May 4 16:11:02 2018 +0300
sql: replace KeyInfo with key_def
KeyInfo is a legacy struct which was heavily used in SQL
front-end. This patch replaces all its usages w/ Tarantool's
natural key description structure called key_def.
This change is a part of data dictionary integration effort:
Tarantool indexes don't aware of KeyInfo, that is why it was
evicted.
Legacy KeyInfo memory handling was ref-counting based and now
is replaced w/ memory duplication. This state of affairs should
be improved in future.
Part of #3235
diff --git a/src/box/sql.c b/src/box/sql.c
index e312d03..79da550 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -357,7 +357,7 @@ int tarantoolSqlite3Count(BtCursor *pCur, i64 *pnEntry)
return SQLITE_OK;
}
-/*
+/**
* Create ephemeral space and set cursor to the first entry. Features of
* ephemeral spaces: id == 0, name == "ephemeral", memtx engine (in future it
* can be changed, but now only memtx engine is supported), primary index
@@ -366,12 +366,12 @@ int tarantoolSqlite3Count(BtCursor *pCur, i64 *pnEntry)
*
* @param pCur Cursor which will point to the new ephemeral space.
* @param field_count Number of fields in ephemeral space.
- * @param aColl Collation sequence of ephemeral space.
+ * @param def Keys description for new ephemeral space.
*
* @retval SQLITE_OK on success, SQLITE_TARANTOOL_ERROR otherwise.
*/
int tarantoolSqlite3EphemeralCreate(BtCursor *pCur, uint32_t field_count,
- struct coll *aColl)
+ struct key_def *def)
{
assert(pCur);
assert(pCur->curFlags & BTCF_TEphemCursor);
@@ -380,12 +380,13 @@ int tarantoolSqlite3EphemeralCreate(BtCursor *pCur, uint32_t field_count,
if (ephemer_key_def == NULL)
return SQL_TARANTOOL_ERROR;
for (uint32_t part = 0; part < field_count; ++part) {
- key_def_set_part(ephemer_key_def, part /* part no */,
- part /* filed no */,
- FIELD_TYPE_SCALAR,
- ON_CONFLICT_ACTION_NONE /* nullable_action */,
- aColl /* coll */,
- SORT_ORDER_ASC);
+ struct coll *coll;
+ if (part < def->part_count)
+ coll = def->parts[part].coll;
+ else
+ coll = NULL;
+ key_def_set_part(ephemer_key_def, part, part, FIELD_TYPE_SCALAR,
+ ON_CONFLICT_ACTION_NONE, coll, SORT_ORDER_ASC);
}
struct index_def *ephemer_index_def =
@@ -929,16 +930,13 @@ rename_fail:
return SQL_TARANTOOL_ERROR;
}
-/*
- * Performs exactly as extract_key + sqlite3VdbeCompareMsgpack,
- * only faster.
- */
-int tarantoolSqlite3IdxKeyCompare(BtCursor *pCur, UnpackedRecord *pUnpacked,
- int *res)
+int
+tarantoolSqlite3IdxKeyCompare(struct BtCursor *cursor,
+ struct UnpackedRecord *unpacked, int *res)
{
- assert(pCur->curFlags & BTCF_TaCursor);
- assert(pCur->iter != NULL);
- assert(pCur->last_tuple != NULL);
+ assert(cursor->curFlags & BTCF_TaCursor);
+ assert(cursor->iter != NULL);
+ assert(cursor->last_tuple != NULL);
const box_key_def_t *key_def;
const struct tuple *tuple;
@@ -955,9 +953,9 @@ int tarantoolSqlite3IdxKeyCompare(BtCursor *pCur, UnpackedRecord *pUnpacked,
uint32_t key_size;
#endif
- key_def = box_iterator_key_def(pCur->iter);
- n = MIN(pUnpacked->nField, key_def->part_count);
- tuple = pCur->last_tuple;
+ key_def = box_iterator_key_def(cursor->iter);
+ n = MIN(unpacked->nField, key_def->part_count);
+ tuple = cursor->last_tuple;
base = tuple_data(tuple);
format = tuple_format(tuple);
field_map = tuple_field_map(tuple);
@@ -991,28 +989,28 @@ int tarantoolSqlite3IdxKeyCompare(BtCursor *pCur, UnpackedRecord *pUnpacked,
} else {
p = base + field_map[
format->fields[fieldno].offset_slot
-];
+ ];
}
}
next_fieldno = fieldno + 1;
- rc = sqlite3VdbeCompareMsgpack(&p, pUnpacked, i);
+ rc = sqlite3VdbeCompareMsgpack(&p, unpacked, i);
if (rc != 0) {
- if (pUnpacked->pKeyInfo->aSortOrder[i]) {
+ if (unpacked->key_def->parts[i].sort_order !=
+ SORT_ORDER_ASC) {
rc = -rc;
}
*res = rc;
goto out;
}
}
- *res = pUnpacked->default_rc;
+ *res = unpacked->default_rc;
out:
#ifndef NDEBUG
/* Sanity check. */
original_size = region_used(&fiber()->gc);
key = tuple_extract_key(tuple, key_def, &key_size);
if (key != NULL) {
- rc = sqlite3VdbeRecordCompareMsgpack((int)key_size, key,
- pUnpacked);
+ rc = sqlite3VdbeRecordCompareMsgpack(key, unpacked);
region_truncate(&fiber()->gc, original_size);
assert(rc == *res);
}
diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index f0054c5..ec23481 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -176,8 +176,8 @@ openStatTable(Parse * pParse, /* Parsing context */
/* Open the sql_stat[134] tables for writing. */
for (i = 0; aTable[i]; i++) {
int addr = emit_open_cursor(pParse, iStatCur + i, aRoot[i]);
- v->aOp[addr].p4.pKeyInfo = 0;
- v->aOp[addr].p4type = P4_KEYINFO;
+ v->aOp[addr].p4.key_def = NULL;
+ v->aOp[addr].p4type = P4_KEYDEF;
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
VdbeComment((v, aTable[i]));
}
@@ -914,7 +914,7 @@ analyzeOneTable(Parse * pParse, /* Parser context */
(void *) space);
sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum,
space_ptr_reg);
- sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
+ sql_vdbe_set_p4_key_def(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
/* Invoke the stat_init() function. The arguments are:
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 49ac1fa..be40982 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -985,13 +985,13 @@ sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */
pTab->tabFlags |= TF_Autoincrement;
}
if (pList)
- pParse->iPkSortOrder = pList->a[0].sortOrder;
+ pParse->iPkSortOrder = pList->a[0].sort_order;
} else if (autoInc) {
sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
"INTEGER PRIMARY KEY or INT PRIMARY KEY");
} else {
- sqlite3CreateIndex(pParse, 0, 0, pList, onError, 0,
- 0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY);
+ sql_create_index(pParse, 0, 0, pList, onError, 0,
+ 0, sortOrder, false, SQLITE_IDXTYPE_PRIMARYKEY);
pList = 0;
}
@@ -1094,6 +1094,21 @@ sql_column_collation(Table *table, uint32_t column)
return space->format->fields[column].coll;
}
+struct key_def*
+sql_index_key_def(struct Index *idx, bool is_dup)
+{
+ uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->pTable->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);
+ if (is_dup)
+ return key_def_dup(index->def->key_def);
+ else
+ return index->def->key_def;
+}
+
/**
* Return name of given column collation from index.
*
@@ -1119,10 +1134,9 @@ sql_index_collation(Index *idx, uint32_t column)
return idx->coll_array[column];
}
- uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum);
- struct index *index = space_index(space, index_id);
- assert(index != NULL && index->def->key_def->part_count >= column);
- return index->def->key_def->parts[column].coll;
+ struct key_def *key_def = sql_index_key_def(idx, false);
+ assert(key_def != NULL && key_def->part_count >= column);
+ return key_def->parts[column].coll;
}
enum sort_order
@@ -1143,10 +1157,9 @@ sql_index_column_sort_order(Index *idx, uint32_t column)
return idx->sort_order[column];
}
- uint32_t index_id = SQLITE_PAGENO_TO_INDEXID(idx->tnum);
- struct index *index = space_index(space, index_id);
- assert(index != NULL && index->def->key_def->part_count >= column);
- return index->def->key_def->parts[column].sort_order;
+ struct key_def *key_def = sql_index_key_def(idx, false);
+ assert(key_def != NULL && key_def->part_count >= column);
+ return key_def->parts[column].sort_order;
}
/**
@@ -1443,9 +1456,7 @@ hasColumn(const i16 * aiCol, int nCol, int x)
* (2) Set the Index.tnum of the PRIMARY KEY Index object in the
* schema to the rootpage from the main table.
* (3) Add all table columns to the PRIMARY KEY Index object
- * so that the PRIMARY KEY is a covering index. The surplus
- * columns are part of KeyInfo.nXField and are not used for
- * sorting or lookup or uniqueness checks.
+ * so that the PRIMARY KEY is a covering index.
*/
static void
convertToWithoutRowidTable(Parse * pParse, Table * pTab)
@@ -1476,10 +1487,11 @@ convertToWithoutRowidTable(Parse * pParse, Table * pTab)
&ipkToken, 0));
if (pList == 0)
return;
- pList->a[0].sortOrder = pParse->iPkSortOrder;
+ pList->a[0].sort_order = pParse->iPkSortOrder;
assert(pParse->pNewTable == pTab);
- sqlite3CreateIndex(pParse, 0, 0, pList, pTab->keyConf, 0, 0, 0,
- 0, SQLITE_IDXTYPE_PRIMARYKEY);
+ sql_create_index(pParse, 0, 0, pList, pTab->keyConf, 0, 0,
+ SORT_ORDER_ASC, false,
+ SQLITE_IDXTYPE_PRIMARYKEY);
if (db->mallocFailed)
return;
pPk = sqlite3PrimaryKeyIndex(pTab);
@@ -2632,7 +2644,6 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage)
int tnum; /* Root page of index */
int iPartIdxLabel; /* Jump to this label to skip a row */
Vdbe *v; /* Generate code into this virtual machine */
- KeyInfo *pKey; /* KeyInfo for index */
int regRecord; /* Register holding assembled index record */
sqlite3 *db = pParse->db; /* The database connection */
v = sqlite3GetVdbe(pParse);
@@ -2643,14 +2654,13 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage)
} else {
tnum = pIndex->tnum;
}
- pKey = sqlite3KeyInfoOfIndex(pParse, db, pIndex);
- assert(pKey != 0 || db->mallocFailed || pParse->nErr);
+ struct key_def *def = sql_index_key_def(pIndex, false);
+ assert(def != NULL || db->mallocFailed || pParse->nErr);
/* Open the sorter cursor if we are to use one. */
iSorter = pParse->nTab++;
sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nColumn,
- (char *)
- sqlite3KeyInfoRef(pKey), P4_KEYINFO);
+ (char *)def, P4_KEYDEF);
/* Open the table. Loop through all rows of the table, inserting index
* records into the sorter.
@@ -2836,34 +2846,11 @@ index_is_unique(Index *idx)
return tnt_index->def->opts.is_unique;
}
-/*
- * Create a new index for an SQL table. pName1.pName2 is the name of the index
- * and pTblList is the name of the table that is to be indexed. Both will
- * be NULL for a primary key or an index that is created to satisfy a
- * UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable
- * as the table to be indexed. pParse->pNewTable is a table that is
- * currently being constructed by a CREATE TABLE statement.
- *
- * pList is a list of columns to be indexed. pList will be NULL if this
- * is a primary key or unique-constraint on the most recent column added
- * to the table currently under construction.
- */
void
-sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
- Token * pName, /* Index name. May be NULL */
- SrcList * pTblName, /* Table to index. Use pParse->pNewTable if 0 */
- ExprList * pList, /* A list of columns to be indexed */
- int onError, /* ON_CONFLICT_ACTION_ABORT, _IGNORE,
- * _REPLACE, or _NONE.
- */
- Token MAYBE_UNUSED * pStart, /* The CREATE token that begins
- * this statement
- */
- Expr * pPIWhere, /* WHERE clause for partial indices */
- int sortOrder, /* Sort order of primary key when pList==NULL */
- int ifNotExist, /* Omit error if index already exists */
- u8 idxType /* The index type */
- )
+sql_create_index(struct Parse *parse, struct Token *token,
+ struct SrcList *tbl_name, struct ExprList *col_list,
+ int on_error, struct Token *start, struct Expr *pi_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 */
@@ -2871,13 +2858,13 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
int nName; /* Number of characters in zName */
int i, j;
DbFixer sFix; /* For assigning database names to pTable */
- sqlite3 *db = pParse->db;
- struct ExprList_item *pListItem; /* For looping over pList */
+ 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 */
struct session *user_session = current_session();
- if (db->mallocFailed || pParse->nErr > 0) {
+ if (db->mallocFailed || parse->nErr > 0) {
goto exit_create_index;
}
/* Do not account nested operations: the count of such
@@ -2886,8 +2873,8 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
* PRIMARY KEY and UNIQUE constraint - they had been accounted
* in CREATE TABLE already.
*/
- if (!pParse->nested && idxType == SQLITE_IDXTYPE_APPDEF) {
- Vdbe *v = sqlite3GetVdbe(pParse);
+ if (!parse->nested && idx_type == SQLITE_IDXTYPE_APPDEF) {
+ Vdbe *v = sqlite3GetVdbe(parse);
if (v == NULL)
goto exit_create_index;
sqlite3VdbeCountChanges(v);
@@ -2897,39 +2884,39 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
/*
* Find the table that is to be indexed. Return early if not found.
*/
- if (pTblName != 0) {
+ if (tbl_name != 0) {
/* Use the two-part index name to determine the database
* to search for the table. 'Fix' the table name to this db
* before looking up the table.
*/
- assert(pName && pName->z);
+ assert(token && token->z);
- sqlite3FixInit(&sFix, pParse, "index", pName);
- if (sqlite3FixSrcList(&sFix, pTblName)) {
- /* Because the parser constructs pTblName from a single identifier,
+ sqlite3FixInit(&sFix, parse, "index", token);
+ if (sqlite3FixSrcList(&sFix, tbl_name)) {
+ /* Because the parser constructs tbl_name from a single identifier,
* sqlite3FixSrcList can never fail.
*/
assert(0);
}
- pTab = sqlite3LocateTable(pParse, 0, pTblName->a[0].zName);
+ pTab = sqlite3LocateTable(parse, 0, tbl_name->a[0].zName);
assert(db->mallocFailed == 0 || pTab == 0);
if (pTab == 0)
goto exit_create_index;
sqlite3PrimaryKeyIndex(pTab);
} else {
- assert(pName == 0);
- assert(pStart == 0);
- pTab = pParse->pNewTable;
+ assert(token == 0);
+ assert(start == 0);
+ pTab = parse->pNewTable;
if (!pTab)
goto exit_create_index;
}
assert(pTab != 0);
- assert(pParse->nErr == 0);
+ assert(parse->nErr == 0);
#ifndef SQLITE_OMIT_VIEW
if (pTab->pSelect) {
- sqlite3ErrorMsg(pParse, "views may not be indexed");
+ sqlite3ErrorMsg(parse, "views may not be indexed");
goto exit_create_index;
}
#endif
@@ -2942,27 +2929,27 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
* one of the index names collides with the name of a temporary table or
* index, then we will continue to process this index.
*
- * If pName==0 it means that we are
+ * If token==0 it means that we are
* dealing with a primary key or UNIQUE constraint. We have to invent our
* own name.
*/
- if (pName) {
- zName = sqlite3NameFromToken(db, pName);
+ if (token) {
+ zName = sqlite3NameFromToken(db, token);
if (zName == 0)
goto exit_create_index;
- assert(pName->z != 0);
+ assert(token->z != 0);
if (!db->init.busy) {
if (sqlite3HashFind(&db->pSchema->tblHash, zName) !=
NULL) {
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(parse,
"there is already a table named %s",
zName);
goto exit_create_index;
}
}
if (sqlite3HashFind(&pTab->idxHash, zName) != NULL) {
- if (!ifNotExist) {
- sqlite3ErrorMsg(pParse,
+ if (!if_not_exist) {
+ sqlite3ErrorMsg(parse,
"index %s.%s already exists",
pTab->zName, zName);
} else {
@@ -2984,29 +2971,29 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
}
}
- /* If pList==0, it means this routine was called to make a primary
+ /* If col_list==0, it means this routine was called to make a primary
* key out of the last column added to the table under construction.
* So create a fake list to simulate this.
*/
- if (pList == 0) {
+ if (col_list == 0) {
Token prevCol;
sqlite3TokenInit(&prevCol, pTab->aCol[pTab->nCol - 1].zName);
- pList = sqlite3ExprListAppend(pParse, 0,
+ col_list = sqlite3ExprListAppend(parse, 0,
sqlite3ExprAlloc(db, TK_ID,
&prevCol, 0));
- if (pList == 0)
+ if (col_list == 0)
goto exit_create_index;
- assert(pList->nExpr == 1);
- sqlite3ExprListSetSortOrder(pList, sortOrder);
+ assert(col_list->nExpr == 1);
+ sqlite3ExprListSetSortOrder(col_list, sort_order);
} else {
- sqlite3ExprListCheckLength(pParse, pList, "index");
+ 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 < pList->nExpr; i++) {
- Expr *pExpr = pList->a[i].pExpr;
+ 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));
@@ -3017,7 +3004,7 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
* Allocate the index structure.
*/
nName = sqlite3Strlen30(zName);
- pIndex = sqlite3AllocateIndexObject(db, pList->nExpr,
+ pIndex = sqlite3AllocateIndexObject(db, col_list->nExpr,
nName + nExtra + 1, &zExtra);
if (db->mallocFailed) {
goto exit_create_index;
@@ -3028,26 +3015,26 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
zExtra += nName + 1;
memcpy(pIndex->zName, zName, nName + 1);
pIndex->pTable = pTab;
- pIndex->onError = (u8) onError;
+ pIndex->onError = (u8) on_error;
/*
* Don't make difference between UNIQUE indexes made by user
* using CREATE INDEX statement and those created during
* CREATE TABLE processing.
*/
- if (idxType == SQLITE_IDXTYPE_APPDEF &&
- onError != ON_CONFLICT_ACTION_NONE) {
+ if (idx_type == SQLITE_IDXTYPE_APPDEF &&
+ on_error != ON_CONFLICT_ACTION_NONE) {
pIndex->idxType = SQLITE_IDXTYPE_UNIQUE;
} else {
- pIndex->idxType = idxType;
+ pIndex->idxType = idx_type;
}
pIndex->pSchema = db->pSchema;
- pIndex->nColumn = pList->nExpr;
+ pIndex->nColumn = col_list->nExpr;
/* Tarantool have access to each column by any index */
- if (pPIWhere) {
- sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere,
+ if (pi_where) {
+ sqlite3ResolveSelfReference(parse, pTab, NC_PartIdx, pi_where,
0);
- pIndex->pPartIdxWhere = pPIWhere;
- pPIWhere = 0;
+ pIndex->pPartIdxWhere = pi_where;
+ pi_where = 0;
}
/* Analyze the list of expressions that form the terms of the index and
@@ -3059,16 +3046,16 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
* TODO: Issue a warning if the table primary key is used as part of the
* index key.
*/
- for (i = 0, pListItem = pList->a; i < pList->nExpr; i++, pListItem++) {
+ for (i = 0, col_listItem = col_list->a; i < col_list->nExpr; i++, col_listItem++) {
Expr *pCExpr; /* The i-th index expression */
enum sort_order requested_so; /* ASC or DESC on the i-th expression */
- sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr,
- pListItem->pExpr, 0);
- if (pParse->nErr)
+ sqlite3ResolveSelfReference(parse, pTab, NC_IdxExpr,
+ col_listItem->pExpr, 0);
+ if (parse->nErr)
goto exit_create_index;
- pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr);
+ pCExpr = sqlite3ExprSkipCollate(col_listItem->pExpr);
if (pCExpr->op != TK_COLUMN) {
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(parse,
"functional indexes aren't supported "
"in the current version");
goto exit_create_index;
@@ -3081,9 +3068,9 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
pIndex->aiColumn[i] = (i16) j;
}
struct coll *coll;
- if (pListItem->pExpr->op == TK_COLLATE) {
- const char *coll_name = pListItem->pExpr->u.zToken;
- coll = sqlite3GetCollSeq(pParse, 0, coll_name);
+ if (col_listItem->pExpr->op == TK_COLLATE) {
+ const char *coll_name = col_listItem->pExpr->u.zToken;
+ coll = sqlite3GetCollSeq(parse, 0, coll_name);
if (coll == NULL &&
sqlite3StrICmp(coll_name, "binary") != 0) {
@@ -3099,15 +3086,15 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
/* Tarantool: DESC indexes are not supported so far.
* See gh-3016.
*/
- requested_so = pListItem->sortOrder & 0;
+ requested_so = col_listItem->sort_order & 0;
pIndex->sort_order[i] = requested_so;
}
sqlite3DefaultRowEst(pIndex);
- if (pParse->pNewTable == 0)
+ if (parse->pNewTable == 0)
estimateIndexWidth(pIndex);
- if (pTab == pParse->pNewTable) {
+ 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
* a PRIMARY KEY or UNIQUE clause following the column definitions.
@@ -3161,7 +3148,7 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
(pIdx->onError == ON_CONFLICT_ACTION_DEFAULT
|| pIndex->onError ==
ON_CONFLICT_ACTION_DEFAULT)) {
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(parse,
"conflicting ON CONFLICT clauses specified",
0);
}
@@ -3169,8 +3156,8 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
pIdx->onError = pIndex->onError;
}
}
- if (idxType == SQLITE_IDXTYPE_PRIMARYKEY)
- pIdx->idxType = idxType;
+ if (idx_type == SQLITE_IDXTYPE_PRIMARYKEY)
+ pIdx->idxType = idx_type;
goto exit_create_index;
}
}
@@ -3179,7 +3166,7 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
/* Link the new Index structure to its table and to the other
* in-memory database structures.
*/
- assert(pParse->nErr == 0);
+ assert(parse->nErr == 0);
if (db->init.busy) {
Index *p;
p = sqlite3HashInsert(&pTab->idxHash, pIndex->zName, pIndex);
@@ -3198,23 +3185,23 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
* But, do not do this if we are simply parsing the schema, or if this
* index is the PRIMARY KEY index.
*
- * If pTblName==0 it means this index is generated as an implied PRIMARY KEY
+ * If tbl_name==0 it means this index is generated as an implied PRIMARY KEY
* or UNIQUE index in a CREATE TABLE statement. Since the table
* has just been created, it contains no data and the index initialization
* step can be skipped.
*/
- else if (pTblName) {
+ else if (tbl_name) {
Vdbe *v;
char *zStmt;
- int iCursor = pParse->nTab++;
- int index_space_ptr_reg = pParse->nTab++;
+ int iCursor = parse->nTab++;
+ int index_space_ptr_reg = parse->nTab++;
int iSpaceId, iIndexId, iFirstSchemaCol;
- v = sqlite3GetVdbe(pParse);
+ v = sqlite3GetVdbe(parse);
if (v == 0)
goto exit_create_index;
- sql_set_multi_write(pParse, true);
+ sql_set_multi_write(parse, true);
sqlite3VdbeAddOp2(v, OP_SIDtoPtr, BOX_INDEX_ID,
@@ -3226,34 +3213,34 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
/* Gather the complete text of the CREATE INDEX statement into
* the zStmt variable
*/
- assert(pStart); {
+ assert(start); {
int n =
- (int)(pParse->sLastToken.z - pName->z) +
- pParse->sLastToken.n;
- if (pName->z[n - 1] == ';')
+ (int)(parse->sLastToken.z - token->z) +
+ parse->sLastToken.n;
+ if (token->z[n - 1] == ';')
n--;
/* A named index with an explicit CREATE INDEX statement */
zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
- onError ==
+ on_error ==
ON_CONFLICT_ACTION_NONE
? "" : " UNIQUE", n,
- pName->z);
+ token->z);
}
iSpaceId = SQLITE_PAGENO_TO_SPACEID(pTab->tnum);
- iIndexId = getNewIid(pParse, iSpaceId, iCursor);
+ iIndexId = getNewIid(parse, iSpaceId, iCursor);
sqlite3VdbeAddOp1(v, OP_Close, iCursor);
- createIndex(pParse, pIndex, iSpaceId, iIndexId, zStmt);
+ createIndex(parse, pIndex, iSpaceId, iIndexId, zStmt);
/* consumes zStmt */
iFirstSchemaCol =
- makeIndexSchemaRecord(pParse, pIndex, iSpaceId, iIndexId,
+ makeIndexSchemaRecord(parse, pIndex, iSpaceId, iIndexId,
zStmt);
/* Reparse the schema. Code an OP_Expire
* to invalidate all pre-compiled statements.
*/
- sqlite3ChangeCookie(pParse);
+ sqlite3ChangeCookie(parse);
sqlite3VdbeAddParseSchema2Op(v, iFirstSchemaCol, 4);
sqlite3VdbeAddOp0(v, OP_Expire);
}
@@ -3268,7 +3255,7 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
* UPDATE and INSERT statements.
*/
- if (!(db->init.busy || pTblName == 0))
+ if (!(db->init.busy || tbl_name == 0))
goto exit_create_index;
addIndexToTable(pIndex, pTab);
pIndex = 0;
@@ -3277,9 +3264,9 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */
exit_create_index:
if (pIndex)
freeIndex(db, pIndex);
- sql_expr_free(db, pPIWhere, false);
- sqlite3ExprListDelete(db, pList);
- sqlite3SrcListDelete(db, pTblName);
+ sql_expr_free(db, pi_where, false);
+ sqlite3ExprListDelete(db, col_list);
+ sqlite3SrcListDelete(db, tbl_name);
sqlite3DbFree(db, zName);
}
@@ -3374,15 +3361,6 @@ index_is_unique_not_null(const Index *idx)
!index->def->key_def->is_nullable);
}
-/**
- * This routine will drop an existing named index. This routine
- * implements the DROP INDEX statement.
- *
- * @param parse_context Current parsing context.
- * @param index_name_list List containing index name.
- * @param table_token Token representing table name.
- * @param if_exists True, if statement contains 'IF EXISTS' clause.
- */
void
sql_drop_index(struct Parse *parse_context, struct SrcList *index_name_list,
struct Token *table_token, bool if_exists)
@@ -4171,46 +4149,6 @@ sqlite3Reindex(Parse * pParse, Token * pName1, Token * pName2)
}
#endif
-/*
- * Return a KeyInfo structure that is appropriate for the given Index.
- *
- * The caller should invoke sqlite3KeyInfoUnref() on the returned object
- * when it has finished using it.
- */
-KeyInfo *
-sqlite3KeyInfoOfIndex(Parse * pParse, sqlite3 * db, Index * pIdx)
-{
- int i;
- int nCol = pIdx->nColumn;
- int nTableCol = pIdx->pTable->nCol;
- KeyInfo *pKey;
-
- if (pParse && pParse->nErr)
- return 0;
-
- /*
- * KeyInfo describes the index (i.e. the number of key columns,
- * comparator options, and the number of columns beyond the key).
- * Since Tarantool iterator yields the full tuple, we need a KeyInfo
- * as wide as the table itself. Otherwize, not enough slots
- * for row parser cache are allocated in VdbeCursor object.
- */
- pKey = sqlite3KeyInfoAlloc(db, nCol, nTableCol - nCol);
- if (pKey) {
- assert(sqlite3KeyInfoIsWriteable(pKey));
- for (i = 0; i < nCol; i++) {
- pKey->aColl[i] = sql_index_collation(pIdx, i);
- pKey->aSortOrder[i] = sql_index_column_sort_order(pIdx,
- i);
- }
- if (pParse && pParse->nErr) {
- sqlite3KeyInfoUnref(pKey);
- pKey = 0;
- }
- }
- return pKey;
-}
-
#ifndef SQLITE_OMIT_CTE
/*
* This routine is invoked once per CTE by the parser while parsing a
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 3f74b93..e229d45 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -386,10 +386,14 @@ sqlite3DeleteFrom(Parse * pParse, /* The parser context */
iPk = pParse->nMem + 1;
pParse->nMem += nPk;
iEphCur = pParse->nTab++;
- KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nPk, 0);
+ struct key_def *def = key_def_new(nPk);
+ if (def == NULL) {
+ pParse->rc = SQL_TARANTOOL_ERROR;
+ goto delete_from_cleanup;
+ }
addrEphOpen =
sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, iEphCur,
- nPk, 0, (char*) pKeyInfo, P4_KEYINFO);
+ nPk, 0, (char*)def, P4_KEYDEF);
} else {
pPk = sqlite3PrimaryKeyIndex(pTab);
assert(pPk != 0);
@@ -400,7 +404,7 @@ sqlite3DeleteFrom(Parse * pParse, /* The parser context */
addrEphOpen =
sqlite3VdbeAddOp2(v, OP_OpenTEphemeral, iEphCur,
nPk);
- sqlite3VdbeSetP4KeyInfo(pParse, pPk);
+ sql_vdbe_set_p4_key_def(pParse, pPk);
}
/* Construct a query to find the primary key for every row
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index cc969ca..83cbe60 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -1505,7 +1505,7 @@ sqlite3ExprListDup(sqlite3 * db, ExprList * p, int flags)
}
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
- pItem->sortOrder = pOldItem->sortOrder;
+ pItem->sort_order = pOldItem->sort_order;
pItem->done = 0;
pItem->bSpanIsTab = pOldItem->bSpanIsTab;
pItem->u = pOldItem->u;
@@ -1756,20 +1756,17 @@ sqlite3ExprListAppendVector(Parse * pParse, /* Parsing context */
return pList;
}
-/*
- * Set the sort order for the last element on the given ExprList.
- */
void
-sqlite3ExprListSetSortOrder(ExprList * p, int iSortOrder)
+sqlite3ExprListSetSortOrder(struct ExprList *p, enum sort_order sort_order)
{
if (p == 0)
return;
assert(p->nExpr > 0);
- if (iSortOrder == SORT_ORDER_UNDEF) {
- assert(p->a[p->nExpr - 1].sortOrder == SORT_ORDER_ASC);
+ if (sort_order == SORT_ORDER_UNDEF) {
+ assert(p->a[p->nExpr - 1].sort_order == SORT_ORDER_ASC);
return;
}
- p->a[p->nExpr - 1].sortOrder = (u8) iSortOrder;
+ p->a[p->nExpr - 1].sort_order = sort_order;
}
/*
@@ -2522,7 +2519,7 @@ sqlite3FindInIndex(Parse * pParse, /* Parsing context */
P4_DYNAMIC);
emit_open_cursor(pParse, iTab,
pIdx->tnum);
- sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
+ sql_vdbe_set_p4_key_def(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
assert(IN_INDEX_INDEX_DESC ==
IN_INDEX_INDEX_ASC + 1);
@@ -2739,7 +2736,6 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */
case TK_IN:{
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
- KeyInfo *pKeyInfo = 0; /* Key information */
int nVal; /* Size of vector pLeft */
nVal = sqlite3ExprVectorSize(pLeft);
@@ -2761,7 +2757,11 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */
pExpr->is_ephemeral = 1;
addr = sqlite3VdbeAddOp2(v, OP_OpenTEphemeral,
pExpr->iTable, nVal);
- pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
+ struct key_def *key_def = key_def_new(nVal);
+ if (key_def == NULL) {
+ pParse->rc = SQL_TARANTOOL_ERROR;
+ return 0;
+ }
if (ExprHasProperty(pExpr, EP_xIsSelect)) {
/* Case 1: expr IN (SELECT ...)
@@ -2787,29 +2787,33 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */
pSelect->iLimit = 0;
testcase(pSelect->
selFlags & SF_Distinct);
- testcase(pKeyInfo == 0); /* Caused by OOM in sqlite3KeyInfoAlloc() */
if (sqlite3Select
(pParse, pSelect, &dest)) {
sqlite3DbFree(pParse->db,
dest.zAffSdst);
- sqlite3KeyInfoUnref(pKeyInfo);
+ if (key_def != NULL)
+ key_def_delete(key_def);
return 0;
}
sqlite3DbFree(pParse->db,
dest.zAffSdst);
- assert(pKeyInfo != 0); /* OOM will cause exit after sqlite3Select() */
assert(pEList != 0);
assert(pEList->nExpr > 0);
- assert(sqlite3KeyInfoIsWriteable
- (pKeyInfo));
for (i = 0; i < nVal; i++) {
Expr *p =
sqlite3VectorFieldSubexpr
(pLeft, i);
- pKeyInfo->aColl[i] =
- sqlite3BinaryCompareCollSeq
- (pParse, p,
- pEList->a[i].pExpr);
+
+ struct coll *coll;
+ coll = sqlite3BinaryCompareCollSeq
+ (pParse, p,
+ pEList->a[i].pExpr);
+
+ key_def_set_part(key_def, i, i,
+ FIELD_TYPE_SCALAR,
+ ON_CONFLICT_ACTION_ABORT,
+ coll,
+ SORT_ORDER_ASC);
}
}
} else if (ALWAYS(pExpr->x.pList != 0)) {
@@ -2830,14 +2834,18 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */
if (!affinity) {
affinity = SQLITE_AFF_BLOB;
}
- if (pKeyInfo) {
+ if (key_def != NULL) {
bool unused;
- assert(sqlite3KeyInfoIsWriteable
- (pKeyInfo));
- pKeyInfo->aColl[0] =
- sql_expr_coll(pParse,
- pExpr->pLeft,
- &unused);
+ struct coll *coll;
+ coll = sql_expr_coll(pParse,
+ pExpr->pLeft,
+ &unused);
+
+ key_def_set_part(key_def, 0, 0,
+ FIELD_TYPE_SCALAR,
+ ON_CONFLICT_ACTION_ABORT,
+ coll,
+ SORT_ORDER_ASC);
}
/* Loop through each expression in <exprlist>. */
@@ -2868,9 +2876,9 @@ sqlite3CodeSubselect(Parse * pParse, /* Parsing context */
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
- if (pKeyInfo) {
- sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo,
- P4_KEYINFO);
+ if (key_def != NULL) {
+ sqlite3VdbeChangeP4(v, addr, (void *)key_def,
+ P4_KEYDEF);
}
break;
}
@@ -5183,7 +5191,7 @@ sqlite3ExprListCompare(ExprList * pA, ExprList * pB, int iTab)
for (i = 0; i < pA->nExpr; i++) {
Expr *pExprA = pA->a[i].pExpr;
Expr *pExprB = pB->a[i].pExpr;
- if (pA->a[i].sortOrder != pB->a[i].sortOrder)
+ if (pA->a[i].sort_order != pB->a[i].sort_order)
return 1;
if (sqlite3ExprCompare(pExprA, pExprB, iTab))
return 1;
diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c
index 55edf6b..60b4786 100644
--- a/src/box/sql/fkey.c
+++ b/src/box/sql/fkey.c
@@ -437,7 +437,7 @@ fkLookupParent(Parse * pParse, /* Parse context */
int regRec = sqlite3GetTempReg(pParse);
emit_open_cursor(pParse, iCur, pIdx->tnum);
- sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
+ sql_vdbe_set_p4_key_def(pParse, pIdx);
for (i = 0; i < nCol; i++) {
sqlite3VdbeAddOp2(v, OP_Copy,
aiCol[i] + 1 + regData,
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 3ad3fc7..f6a93ce 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -55,7 +55,7 @@ sqlite3OpenTable(Parse * pParse, /* Generate code into this VDBE */
assert(pPk != 0);
assert(pPk->tnum == pTab->tnum);
emit_open_cursor(pParse, iCur, pPk->tnum);
- sqlite3VdbeSetP4KeyInfo(pParse, pPk);
+ sql_vdbe_set_p4_key_def(pParse, pPk);
VdbeComment((v, "%s", pTab->zName));
}
@@ -566,9 +566,13 @@ sqlite3Insert(Parse * pParse, /* Parser context */
regRec = sqlite3GetTempReg(pParse);
regCopy = sqlite3GetTempRange(pParse, nColumn);
regTempId = sqlite3GetTempReg(pParse);
- KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, 1+nColumn, 0);
+ struct key_def *def = key_def_new(nColumn + 1);
+ if (def == NULL) {
+ pParse->rc = SQL_TARANTOOL_ERROR;
+ goto insert_cleanup;
+ }
sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, srcTab, nColumn+1,
- 0, (char*)pKeyInfo, P4_KEYINFO);
+ 0, (char*)def, P4_KEYDEF);
/* Create counter for rowid */
sqlite3VdbeAddOp4Dup8(v, OP_Int64,
0 /* unused */,
@@ -1602,7 +1606,7 @@ sqlite3OpenTableAndIndices(Parse * pParse, /* Parsing context */
if (aToOpen == 0 || aToOpen[i + 1]) {
sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum,
space_ptr_reg);
- sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
+ sql_vdbe_set_p4_key_def(pParse, pIdx);
sqlite3VdbeChangeP5(v, p5);
VdbeComment((v, "%s", pIdx->zName));
}
@@ -1916,10 +1920,10 @@ xferOptimization(Parse * pParse, /* Parser context */
}
assert(pSrcIdx);
emit_open_cursor(pParse, iSrc, pSrcIdx->tnum);
- sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx);
+ sql_vdbe_set_p4_key_def(pParse, pSrcIdx);
VdbeComment((v, "%s", pSrcIdx->zName));
emit_open_cursor(pParse, iDest, pDestIdx->tnum);
- sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx);
+ sql_vdbe_set_p4_key_def(pParse, pDestIdx);
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index f548b4d..a40009d 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -281,8 +281,9 @@ ccons ::= NULL onconf.
ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);}
ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
{sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
-ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,R,0,0,0,0,
- SQLITE_IDXTYPE_UNIQUE);}
+ccons ::= UNIQUE onconf(R). {sql_create_index(pParse,0,0,0,R,0,0,
+ SORT_ORDER_ASC, false,
+ SQLITE_IDXTYPE_UNIQUE);}
ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);}
ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
@@ -331,8 +332,9 @@ tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;}
tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R).
{sqlite3AddPrimaryKey(pParse,X,R,I,0);}
tcons ::= UNIQUE LP sortlist(X) RP onconf(R).
- {sqlite3CreateIndex(pParse,0,0,X,R,0,0,0,0,
- SQLITE_IDXTYPE_UNIQUE);}
+ {sql_create_index(pParse,0,0,X,R,0,0,
+ SORT_ORDER_ASC,false,
+ SQLITE_IDXTYPE_UNIQUE);}
tcons ::= CHECK LP expr(E) RP onconf.
{sqlite3AddCheckConstraint(pParse,E.pExpr);}
tcons ::= FOREIGN KEY LP eidlist(FA) RP
@@ -1239,9 +1241,9 @@ paren_exprlist(A) ::= LP exprlist(X) RP. {A = X;}
//
cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X)
ON nm(Y) LP sortlist(Z) RP where_opt(W). {
- sqlite3CreateIndex(pParse, &X,
- sqlite3SrcListAppend(pParse->db,0,&Y), Z, U,
- &S, W, SORT_ORDER_ASC, NE, SQLITE_IDXTYPE_APPDEF);
+ sql_create_index(pParse, &X,
+ sqlite3SrcListAppend(pParse->db,0,&Y), Z, U,
+ &S, W, SORT_ORDER_ASC, NE, SQLITE_IDXTYPE_APPDEF);
}
%type uniqueflag {int}
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 20a1587..1e4ae81 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -643,8 +643,8 @@ sqlite3Pragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */
pIdx->
tnum,
0);
- sqlite3VdbeSetP4KeyInfo
- (pParse, pIdx);
+ sql_vdbe_set_p4_key_def(pParse,
+ pIdx);
}
} else {
k = 0;
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index a5e6563..e49b90b 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -562,12 +562,31 @@ sqliteProcessJoin(Parse * pParse, Select * p)
return 0;
}
-/* Forward reference */
-static KeyInfo *
-keyInfoFromExprList(Parse * pParse, /* Parsing context */
- ExprList * pList, /* Form the KeyInfo object from this ExprList */
- int iStart, /* Begin with this column of pList */
- int nExtra); /* Add this many extra columns to the end */
+/**
+ * Given an expression list, generate a key_def structure that
+ * records the collating sequence for each expression in that
+ * expression list.
+ *
+ * If the ExprList is an ORDER BY or GROUP BY clause then the
+ * resulting key_def structure is appropriate for initializing
+ * a virtual index to implement that clause. If the ExprList is
+ * the result set of a SELECT then the key_info structure is
+ * appropriate for initializing a virtual index to implement a
+ * DISTINCT test.
+ *
+ * Space to hold the key_info structure is obtained from malloc.
+ * The calling function is responsible for seeing that this
+ * structure is eventually freed.
+ *
+ * @param parse Parsing context.
+ * @param list Expression list.
+ * @param start No of leading parts to skip.
+ *
+ * @retval Allocated key_def, NULL in case of OOM.
+ */
+static struct key_def *
+sql_expr_list_to_key_def(struct Parse *parse, struct ExprList *list, int start);
+
/*
* Generate code that will push the record in registers regData
@@ -623,7 +642,6 @@ pushOntoSorter(Parse * pParse, /* Parser context */
int addrJmp; /* Address of the OP_Jump opcode */
VdbeOp *pOp; /* Opcode that opens the sorter */
int nKey; /* Number of sorting key columns, including OP_Sequence */
- KeyInfo *pKI; /* Original KeyInfo on the sorter table */
regPrevKey = pParse->nMem + 1;
pParse->nMem += pSort->nOBSat;
@@ -643,13 +661,17 @@ pushOntoSorter(Parse * pParse, /* Parser context */
if (pParse->db->mallocFailed)
return;
pOp->p2 = nKey + nData;
- pKI = pOp->p4.pKeyInfo;
- memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
- sqlite3VdbeChangeP4(v, -1, (char *)pKI, P4_KEYINFO);
- testcase(pKI->nXField > 2);
- pOp->p4.pKeyInfo =
- keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
- pKI->nXField - 1);
+ struct key_def *def = key_def_dup(pOp->p4.key_def);
+ if (def == NULL) {
+ pParse->rc = SQL_TARANTOOL_ERROR;
+ return;
+ }
+ for (uint32_t i = 0; i < def->part_count; ++i)
+ pOp->p4.key_def->parts[i].sort_order = SORT_ORDER_ASC;
+ sqlite3VdbeChangeP4(v, -1, (char *)def, P4_KEYDEF);
+ pOp->p4.key_def = sql_expr_list_to_key_def(pParse,
+ pSort->pOrderBy,
+ nOBSat);
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp + 1, 0, addrJmp + 1);
VdbeCoverage(v);
@@ -1193,109 +1215,24 @@ selectInnerLoop(Parse * pParse, /* The parser context */
}
}
-/*
- * Allocate a KeyInfo object sufficient for an index of N key columns and
- * X extra columns.
- */
-KeyInfo *
-sqlite3KeyInfoAlloc(sqlite3 * db, int N, int X)
+static struct key_def *
+sql_expr_list_to_key_def(struct Parse *parse, struct ExprList *list, int start)
{
- int nExtra = (N + X) * (sizeof(struct coll *) + 1);
- KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
- if (p) {
- p->aSortOrder = (u8 *) & p->aColl[N + X];
- p->nField = (u16) N;
- p->nXField = (u16) X;
- p->db = db;
- p->nRef = 1;
- p->aColl[0] = NULL;
- memset(&p[1], 0, nExtra);
- } else {
- sqlite3OomFault(db);
- }
- return p;
-}
-
-/*
- * Deallocate a KeyInfo object
- */
-void
-sqlite3KeyInfoUnref(KeyInfo * p)
-{
- if (p) {
- assert(p->nRef > 0);
- p->nRef--;
- if (p->nRef == 0)
- sqlite3DbFree(p->db, p);
- }
-}
-
-/*
- * Make a new pointer to a KeyInfo object
- */
-KeyInfo *
-sqlite3KeyInfoRef(KeyInfo * p)
-{
- if (p) {
- assert(p->nRef > 0);
- p->nRef++;
+ int expr_count = list->nExpr;
+ struct key_def *def = key_def_new(expr_count);
+ if (def == NULL) {
+ parse->rc = SQL_TARANTOOL_ERROR;
+ return NULL;
}
- return p;
-}
-
-#ifdef SQLITE_DEBUG
-/*
- * Return TRUE if a KeyInfo object can be change. The KeyInfo object
- * can only be changed if this is just a single reference to the object.
- *
- * This routine is used only inside of assert() statements.
- */
-int
-sqlite3KeyInfoIsWriteable(KeyInfo * p)
-{
- return p->nRef == 1;
-}
-#endif /* SQLITE_DEBUG */
-
-/*
- * Given an expression list, generate a KeyInfo structure that records
- * the collating sequence for each expression in that expression list.
- *
- * If the ExprList is an ORDER BY or GROUP BY clause then the resulting
- * KeyInfo structure is appropriate for initializing a virtual index to
- * implement that clause. If the ExprList is the result set of a SELECT
- * then the KeyInfo structure is appropriate for initializing a virtual
- * index to implement a DISTINCT test.
- *
- * Space to hold the KeyInfo structure is obtained from malloc. The calling
- * function is responsible for seeing that this structure is eventually
- * freed.
- */
-static KeyInfo *
-keyInfoFromExprList(Parse * pParse, /* Parsing context */
- ExprList * pList, /* Form the KeyInfo object from this ExprList */
- int iStart, /* Begin with this column of pList */
- int nExtra) /* Add this many extra columns to the end */
-{
- int nExpr;
- KeyInfo *pInfo;
- struct ExprList_item *pItem;
- sqlite3 *db = pParse->db;
- int i;
-
- nExpr = pList->nExpr;
- pInfo = sqlite3KeyInfoAlloc(db, nExpr - iStart, nExtra + 1);
- if (pInfo) {
- assert(sqlite3KeyInfoIsWriteable(pInfo));
- for (i = iStart, pItem = pList->a + iStart; i < nExpr;
- i++, pItem++) {
- bool unused;
- pInfo->aColl[i - iStart] =
- sql_expr_coll(pParse, pItem->pExpr, &unused);
- pInfo->aSortOrder[i - iStart] = pItem->sortOrder;
- }
+ struct ExprList_item *item = list->a + start;
+ for (int i = start; i < expr_count; ++i, ++item) {
+ bool unused;
+ struct coll *coll = sql_expr_coll(parse, item->pExpr, &unused);
+ key_def_set_part(def, i-start, i-start, FIELD_TYPE_SCALAR,
+ ON_CONFLICT_ACTION_ABORT, coll,
+ item->sort_order);
}
- return pInfo;
+ return def;
}
/*
@@ -2123,54 +2060,62 @@ multiSelectCollSeq(Parse * pParse, Select * p, int iCol, bool *is_found)
return coll;
}
-/*
- * The select statement passed as the second parameter is a compound SELECT
- * with an ORDER BY clause. This function allocates and returns a KeyInfo
- * structure suitable for implementing the ORDER BY.
+/**
+ * The select statement passed as the second parameter is a
+ * compound SELECT with an ORDER BY clause. This function
+ * allocates and returns a key_def structure suitable for
+ * implementing the ORDER BY.
+ *
+ * Space to hold the key_def structure is obtained from malloc.
+ * The calling function is responsible for ensuring that this
+ * structure is eventually freed.
*
- * Space to hold the KeyInfo structure is obtained from malloc. The calling
- * function is responsible for ensuring that this structure is eventually
- * freed.
+ * @param parse Parsing context.
+ * @param s Select struct to analyze.
+ * @param extra No of extra slots to allocate.
+ *
+ * @retval Allocated key_def, NULL in case of OOM.
*/
-static KeyInfo *
-multiSelectOrderByKeyInfo(Parse * pParse, Select * p, int nExtra)
+static struct key_def *
+sql_multiselect_orderby_to_key_def(struct Parse *parse, struct Select *s,
+ int extra)
{
- ExprList *pOrderBy = p->pOrderBy;
- int nOrderBy = p->pOrderBy->nExpr;
- sqlite3 *db = pParse->db;
- KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy + nExtra, 1);
- if (pRet) {
- int i;
- for (i = 0; i < nOrderBy; i++) {
- struct ExprList_item *pItem = &pOrderBy->a[i];
- Expr *pTerm = pItem->pExpr;
- struct coll *coll;
- bool is_found = false;
+ int ob_count = s->pOrderBy->nExpr;
+ struct key_def *key_def = key_def_new(ob_count + extra);
+ if (key_def == NULL) {
+ parse->rc = SQL_TARANTOOL_ERROR;
+ return NULL;
+ }
- if (pTerm->flags & EP_Collate) {
- coll = sql_expr_coll(pParse, pTerm, &is_found);
+ ExprList *order_by = s->pOrderBy;
+ for (int i = 0; i < ob_count; i++) {
+ struct ExprList_item *item = &order_by->a[i];
+ struct Expr *term = item->pExpr;
+ struct coll *coll;
+ bool is_found = false;
+
+ if (term->flags & EP_Collate) {
+ coll = sql_expr_coll(parse, term, &is_found);
+ } else {
+ coll = multiSelectCollSeq(parse, s,
+ item->u.x.iOrderByCol - 1,
+ &is_found);
+ if (coll != NULL) {
+ order_by->a[i].pExpr =
+ sqlite3ExprAddCollateString(parse, term,
+ coll->name);
} else {
- coll =
- multiSelectCollSeq(pParse, p,
- pItem->u.x.iOrderByCol - 1,
- &is_found);
- if (coll != NULL) {
- pOrderBy->a[i].pExpr =
- sqlite3ExprAddCollateString(pParse, pTerm,
- coll->name);
- } else {
- pOrderBy->a[i].pExpr =
- sqlite3ExprAddCollateString(pParse, pTerm,
- "BINARY");
- }
+ order_by->a[i].pExpr =
+ sqlite3ExprAddCollateString(parse, term,
+ "BINARY");
}
- assert(sqlite3KeyInfoIsWriteable(pRet));
- pRet->aColl[i] = coll;
- pRet->aSortOrder[i] = pOrderBy->a[i].sortOrder;
}
+ key_def_set_part(key_def, i, i, FIELD_TYPE_SCALAR,
+ ON_CONFLICT_ACTION_ABORT, coll,
+ order_by->a[i].sort_order);
}
- return pRet;
+ return key_def;
}
#ifndef SQLITE_OMIT_CTE
@@ -2270,16 +2215,17 @@ generateWithRecursiveQuery(Parse * pParse, /* Parsing context */
regCurrent = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol);
if (pOrderBy) {
- KeyInfo *pKeyInfo = multiSelectOrderByKeyInfo(pParse, p, 1);
+ struct key_def *def = sql_multiselect_orderby_to_key_def(pParse,
+ p, 1);
sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, iQueue,
- pOrderBy->nExpr + 2, 0, (char *)pKeyInfo,
- P4_KEYINFO);
+ pOrderBy->nExpr + 2, 0, (char *)def,
+ P4_KEYDEF);
VdbeComment((v, "Orderby table"));
destQueue.pOrderBy = pOrderBy;
} else {
- KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nCol + 1, 0);
+ struct key_def *def = key_def_new(nCol + 1);
sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, iQueue, nCol + 1, 0,
- (char*)pKeyInfo, P4_KEYINFO);
+ (char*)def, P4_KEYDEF);
VdbeComment((v, "Queue table"));
}
if (iDistinct) {
@@ -2480,9 +2426,9 @@ multiSelect(Parse * pParse, /* Parsing context */
if (dest.eDest == SRT_EphemTab) {
assert(p->pEList);
int nCols = p->pEList->nExpr;
- KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nCols + 1, 0);
+ struct key_def *def = key_def_new(nCols + 1);
sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, dest.iSDParm, nCols + 1,
- 0, (char*)pKeyInfo, P4_KEYINFO);
+ 0, (char*)def, P4_KEYDEF);
VdbeComment((v, "Destination temp"));
dest.eDest = SRT_Table;
}
@@ -2790,7 +2736,7 @@ multiSelect(Parse * pParse, /* Parsing context */
/* Compute collating sequences used by
* temporary tables needed to implement the compound select.
- * Attach the KeyInfo structure to all temporary tables.
+ * Attach the key_def structure to all temporary tables.
*
* This section is run by the right-most SELECT statement only.
* SELECT statements to the left always skip this part. The right-most
@@ -2798,26 +2744,25 @@ multiSelect(Parse * pParse, /* Parsing context */
* no temp tables are required.
*/
if (p->selFlags & SF_UsesEphemeral) {
- int i; /* Loop counter */
- KeyInfo *pKeyInfo; /* Collating sequence for the result set */
- Select *pLoop; /* For looping through SELECT statements */
- struct coll **apColl; /* For looping through pKeyInfo->aColl[] */
- int nCol; /* Number of columns in result set */
-
- assert(p->pNext == 0);
- nCol = p->pEList->nExpr;
- pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
- if (!pKeyInfo) {
+ assert(p->pNext == NULL);
+ int nCol = p->pEList->nExpr;
+ struct key_def *key_def = key_def_new(nCol);
+ if (key_def == NULL) {
rc = SQLITE_NOMEM_BKPT;
goto multi_select_end;
}
- for (i = 0, apColl = pKeyInfo->aColl; i < nCol; i++, apColl++) {
- bool is_found = false;
- *apColl = multiSelectCollSeq(pParse, p, i, &is_found);
+ for (int i = 0; i < nCol; i++) {
+ bool unused;
+ key_def_set_part(key_def, i, i,
+ FIELD_TYPE_SCALAR,
+ ON_CONFLICT_ACTION_ABORT,
+ multiSelectCollSeq(pParse, p, i,
+ &unused),
+ SORT_ORDER_ASC);
}
- for (pLoop = p; pLoop; pLoop = pLoop->pPrior) {
- for (i = 0; i < 2; i++) {
+ for (struct Select *pLoop = p; pLoop; pLoop = pLoop->pPrior) {
+ for (int i = 0; i < 2; i++) {
int addr = pLoop->addrOpenEphm[i];
if (addr < 0) {
/* If [0] is unused then [1] is also unused. So we can
@@ -2827,14 +2772,19 @@ multiSelect(Parse * pParse, /* Parsing context */
break;
}
sqlite3VdbeChangeP2(v, addr, nCol);
+ struct key_def *dup_def = key_def_dup(key_def);
+ if (dup_def == NULL) {
+ rc = SQLITE_NOMEM_BKPT;
+ goto multi_select_end;
+ }
+
sqlite3VdbeChangeP4(v, addr,
- (char *)
- sqlite3KeyInfoRef(pKeyInfo),
- P4_KEYINFO);
+ (char *)dup_def,
+ P4_KEYDEF);
pLoop->addrOpenEphm[i] = -1;
}
}
- sqlite3KeyInfoUnref(pKeyInfo);
+ free(key_def);
}
multi_select_end:
@@ -2845,54 +2795,57 @@ multiSelect(Parse * pParse, /* Parsing context */
}
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
-/*
- * Error message for when two or more terms of a compound select have different
- * size result sets.
- */
void
-sqlite3SelectWrongNumTermsError(Parse * pParse, Select * p)
+sqlite3SelectWrongNumTermsError(struct Parse *parse, struct Select * p)
{
if (p->selFlags & SF_Values) {
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(parse,
"all VALUES must have the same number of terms");
} else {
- sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
+ sqlite3ErrorMsg(parse, "SELECTs to the left and right of %s"
" do not have the same number of result columns",
selectOpName(p->op));
}
}
-/*
+/**
* Code an output subroutine for a coroutine implementation of a
* SELECT statment.
*
* The data to be output is contained in pIn->iSdst. There are
- * pIn->nSdst columns to be output. pDest is where the output should
- * be sent.
+ * pIn->nSdst columns to be output. pDest is where the output
+ * should be sent.
*
* regReturn is the number of the register holding the subroutine
* return address.
*
* If regPrev>0 then it is the first register in a vector that
- * records the previous output. mem[regPrev] is a flag that is false
- * if there has been no previous output. If regPrev>0 then code is
- * generated to suppress duplicates. pKeyInfo is used for comparing
- * keys.
+ * records the previous output. mem[regPrev] is a flag that is
+ * false if there has been no previous output. If regPrev>0 then
+ * code is generated to suppress duplicates. def is used for
+ * comparing keys.
*
* If the LIMIT found in p->iLimit is reached, jump immediately to
* iBreak.
+ *
+ * @param parse Parsing context.
+ * @param p The SELECT statement.
+ * @param in Coroutine supplying data.
+ * @param dest Where to send the data.
+ * @param reg_ret The return address register.
+ * @param reg_prev Previous result register. No uniqueness if 0.
+ * @param def For comparing with previous entry.
+ * @param break_addr Jump here if we hit the LIMIT.
+ *
+ * @retval Address of generated routine.
*/
static int
-generateOutputSubroutine(Parse * pParse, /* Parsing context */
- Select * p, /* The SELECT statement */
- SelectDest * pIn, /* Coroutine supplying data */
- SelectDest * pDest, /* Where to send the data */
- int regReturn, /* The return address register */
- int regPrev, /* Previous result register. No uniqueness if 0 */
- KeyInfo * pKeyInfo, /* For comparing with previous entry */
- int iBreak) /* Jump here if we hit the LIMIT */
+generateOutputSubroutine(struct Parse *parse, struct Select *p,
+ struct SelectDest *in, struct SelectDest *dest,
+ int reg_ret, int reg_prev, const struct key_def *def,
+ int break_addr)
{
- Vdbe *v = pParse->pVdbe;
+ Vdbe *v = parse->pVdbe;
int iContinue;
int addr;
@@ -2901,63 +2854,68 @@ generateOutputSubroutine(Parse * pParse, /* Parsing context */
/* Suppress duplicates for UNION, EXCEPT, and INTERSECT
*/
- if (regPrev) {
+ if (reg_prev) {
int addr1, addr2;
- addr1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev);
+ addr1 = sqlite3VdbeAddOp1(v, OP_IfNot, reg_prev);
VdbeCoverage(v);
+ struct key_def *dup_def = key_def_dup(def);
+ if (dup_def == NULL) {
+ parse->db->mallocFailed = 1;
+ return 0;
+ }
addr2 =
- sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev + 1,
- pIn->nSdst,
- (char *)sqlite3KeyInfoRef(pKeyInfo),
- P4_KEYINFO);
+ sqlite3VdbeAddOp4(v, OP_Compare, in->iSdst, reg_prev + 1,
+ in->nSdst,
+ (char *)dup_def,
+ P4_KEYDEF);
sqlite3VdbeAddOp3(v, OP_Jump, addr2 + 2, iContinue, addr2 + 2);
VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr1);
- sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev + 1,
- pIn->nSdst - 1);
- sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev);
+ sqlite3VdbeAddOp3(v, OP_Copy, in->iSdst, reg_prev + 1,
+ in->nSdst - 1);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, reg_prev);
}
- if (pParse->db->mallocFailed)
+ if (parse->db->mallocFailed)
return 0;
/* Suppress the first OFFSET entries if there is an OFFSET clause
*/
codeOffset(v, p->iOffset, iContinue);
- assert(pDest->eDest != SRT_Exists);
- assert(pDest->eDest != SRT_Table);
- switch (pDest->eDest) {
+ assert(dest->eDest != SRT_Exists);
+ assert(dest->eDest != SRT_Table);
+ switch (dest->eDest) {
/* Store the result as data using a unique key.
*/
case SRT_EphemTab:{
- int regRec = sqlite3GetTempReg(pParse);
- int regCopy = sqlite3GetTempRange(pParse, pIn->nSdst + 1);
- sqlite3VdbeAddOp3(v, OP_NextIdEphemeral, pDest->iSDParm,
- pIn->nSdst, regCopy + pIn->nSdst);
- sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regCopy,
- pIn->nSdst - 1);
+ int regRec = sqlite3GetTempReg(parse);
+ int regCopy = sqlite3GetTempRange(parse, in->nSdst + 1);
+ sqlite3VdbeAddOp3(v, OP_NextIdEphemeral, dest->iSDParm,
+ in->nSdst, regCopy + in->nSdst);
+ sqlite3VdbeAddOp3(v, OP_Copy, in->iSdst, regCopy,
+ in->nSdst - 1);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regCopy,
- pIn->nSdst + 1, regRec);
+ in->nSdst + 1, regRec);
/* Set flag to save memory allocating one by malloc. */
sqlite3VdbeChangeP5(v, 1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, regRec);
- sqlite3ReleaseTempRange(pParse, regCopy, pIn->nSdst + 1);
- sqlite3ReleaseTempReg(pParse, regRec);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, dest->iSDParm, regRec);
+ sqlite3ReleaseTempRange(parse, regCopy, in->nSdst + 1);
+ sqlite3ReleaseTempReg(parse, regRec);
break;
}
/* If we are creating a set for an "expr IN (SELECT ...)".
*/
case SRT_Set:{
int r1;
- testcase(pIn->nSdst > 1);
- r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst,
- pIn->nSdst, r1, pDest->zAffSdst,
- pIn->nSdst);
- sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst,
- pIn->nSdst);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
- sqlite3ReleaseTempReg(pParse, r1);
+ testcase(in->nSdst > 1);
+ r1 = sqlite3GetTempReg(parse);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, in->iSdst,
+ in->nSdst, r1, dest->zAffSdst,
+ in->nSdst);
+ sqlite3ExprCacheAffinityChange(parse, in->iSdst,
+ in->nSdst);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, dest->iSDParm, r1);
+ sqlite3ReleaseTempReg(parse, r1);
break;
}
@@ -2966,25 +2924,25 @@ generateOutputSubroutine(Parse * pParse, /* Parsing context */
* of the scan loop.
*/
case SRT_Mem:{
- assert(pIn->nSdst == 1 || pParse->nErr > 0);
- testcase(pIn->nSdst != 1);
- sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm,
+ assert(in->nSdst == 1 || parse->nErr > 0);
+ testcase(in->nSdst != 1);
+ sqlite3ExprCodeMove(parse, in->iSdst, dest->iSDParm,
1);
/* The LIMIT clause will jump out of the loop for us */
break;
}
/* The results are stored in a sequence of registers
- * starting at pDest->iSdst. Then the co-routine yields.
+ * starting at dest->iSdst. Then the co-routine yields.
*/
case SRT_Coroutine:{
- if (pDest->iSdst == 0) {
- pDest->iSdst =
- sqlite3GetTempRange(pParse, pIn->nSdst);
- pDest->nSdst = pIn->nSdst;
+ if (dest->iSdst == 0) {
+ dest->iSdst =
+ sqlite3GetTempRange(parse, in->nSdst);
+ dest->nSdst = in->nSdst;
}
- sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSdst,
- pIn->nSdst);
- sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
+ sqlite3ExprCodeMove(parse, in->iSdst, dest->iSdst,
+ in->nSdst);
+ sqlite3VdbeAddOp1(v, OP_Yield, dest->iSDParm);
break;
}
@@ -2997,11 +2955,11 @@ generateOutputSubroutine(Parse * pParse, /* Parsing context */
* return the next row of result.
*/
default:{
- assert(pDest->eDest == SRT_Output);
- sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst,
- pIn->nSdst);
- sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst,
- pIn->nSdst);
+ assert(dest->eDest == SRT_Output);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, in->iSdst,
+ in->nSdst);
+ sqlite3ExprCacheAffinityChange(parse, in->iSdst,
+ in->nSdst);
break;
}
}
@@ -3009,14 +2967,14 @@ generateOutputSubroutine(Parse * pParse, /* Parsing context */
/* Jump to the end of the loop if the LIMIT is reached.
*/
if (p->iLimit) {
- sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, break_addr);
VdbeCoverage(v);
}
/* Generate the subroutine return
*/
sqlite3VdbeResolveLabel(v, iContinue);
- sqlite3VdbeAddOp1(v, OP_Return, regReturn);
+ sqlite3VdbeAddOp1(v, OP_Return, reg_ret);
return addr;
}
@@ -3140,8 +3098,10 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */
int labelEnd; /* Label for the end of the overall SELECT stmt */
int addr1; /* Jump instructions that get retargetted */
int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
- KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
- KeyInfo *pKeyMerge; /* Comparison information for merging rows */
+ /* Comparison information for duplicate removal */
+ struct key_def *def_dup = NULL;
+ /* Comparison information for merging rows */
+ struct key_def *def_merge;
sqlite3 *db; /* Database connection */
ExprList *pOrderBy; /* The ORDER BY clause */
int nOrderBy; /* Number of terms in the ORDER BY clause */
@@ -3150,7 +3110,6 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */
int iSub2; /* EQP id of right-hand query */
assert(p->pOrderBy != 0);
- assert(pKeyDup == 0); /* "Managed" code needs this. Ticket #3382. */
db = pParse->db;
v = pParse->pVdbe;
assert(v != 0); /* Already thrown the error if VDBE alloc failed */
@@ -3195,7 +3154,7 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */
}
}
- /* Compute the comparison permutation and keyinfo that is used with
+ /* Compute the comparison permutation and key_def that is used with
* the permutation used to determine if the next
* row of results comes from selectA or selectB. Also add explicit
* collations to the ORDER BY clause terms so that when the subqueries
@@ -3211,9 +3170,9 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */
assert(pItem->u.x.iOrderByCol <= p->pEList->nExpr);
aPermute[i] = pItem->u.x.iOrderByCol - 1;
}
- pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1);
+ def_merge = sql_multiselect_orderby_to_key_def(pParse, p, 1);
} else {
- pKeyMerge = 0;
+ def_merge = NULL;
}
/* Reattach the ORDER BY clause to the query.
@@ -3221,27 +3180,30 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */
p->pOrderBy = pOrderBy;
pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0);
- /* Allocate a range of temporary registers and the KeyInfo needed
+ /* Allocate a range of temporary registers and the key_def needed
* for the logic that removes duplicate result rows when the
* operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL).
*/
if (op == TK_ALL) {
regPrev = 0;
} else {
- int nExpr = p->pEList->nExpr;
- assert(nOrderBy >= nExpr || db->mallocFailed);
+ int expr_count = p->pEList->nExpr;
+ assert(nOrderBy >= expr_count || db->mallocFailed);
regPrev = pParse->nMem + 1;
- pParse->nMem += nExpr + 1;
+ pParse->nMem += expr_count + 1;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev);
- pKeyDup = sqlite3KeyInfoAlloc(db, nExpr, 1);
- if (pKeyDup) {
- assert(sqlite3KeyInfoIsWriteable(pKeyDup));
- for (i = 0; i < nExpr; i++) {
+ def_dup = key_def_new(expr_count);
+ if (def_dup != NULL) {
+ for (int i = 0; i < expr_count; i++) {
bool is_found = false;
- pKeyDup->aColl[i] =
- multiSelectCollSeq(pParse, p, i,
- &is_found);
- pKeyDup->aSortOrder[i] = 0;
+ struct coll *coll;
+ coll = multiSelectCollSeq(pParse, p, i,
+ &is_found);
+ key_def_set_part(def_dup, i, i,
+ FIELD_TYPE_SCALAR,
+ ON_CONFLICT_ACTION_ABORT,
+ coll,
+ SORT_ORDER_ASC);
}
}
}
@@ -3316,7 +3278,7 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */
VdbeNoopComment((v, "Output routine for A"));
addrOutA = generateOutputSubroutine(pParse,
p, &destA, pDest, regOutA,
- regPrev, pKeyDup, labelEnd);
+ regPrev, def_dup, labelEnd);
/* Generate a subroutine that outputs the current row of the B
* select as the next output row of the compound select.
@@ -3325,9 +3287,10 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */
VdbeNoopComment((v, "Output routine for B"));
addrOutB = generateOutputSubroutine(pParse,
p, &destB, pDest, regOutB,
- regPrev, pKeyDup, labelEnd);
+ regPrev, def_dup, labelEnd);
}
- sqlite3KeyInfoUnref(pKeyDup);
+
+ key_def_delete(def_dup);
/* Generate a subroutine to run when the results from select A
* are exhausted and only data in select B remains.
@@ -3407,7 +3370,7 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */
sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char *)aPermute,
P4_INTARRAY);
sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy,
- (char *)pKeyMerge, P4_KEYINFO);
+ (char *)def_merge, P4_KEYDEF);
sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE);
sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
VdbeCoverage(v);
@@ -5140,12 +5103,13 @@ resetAccumulator(Parse * pParse, AggInfo * pAggInfo)
"argument");
pFunc->iDistinct = -1;
} else {
- KeyInfo *pKeyInfo =
- keyInfoFromExprList(pParse, pE->x.pList, 0,
- 0);
+ struct key_def *def;
+ def = sql_expr_list_to_key_def(pParse,
+ pE->x.pList,
+ 0);
sqlite3VdbeAddOp4(v, OP_OpenTEphemeral,
pFunc->iDistinct, 1, 0,
- (char *)pKeyInfo, P4_KEYINFO);
+ (char *)def, P4_KEYDEF);
}
}
}
@@ -5616,23 +5580,22 @@ sqlite3Select(Parse * pParse, /* The parser context */
* that change.
*/
if (sSort.pOrderBy) {
- KeyInfo *pKeyInfo;
- pKeyInfo =
- keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr);
+ struct key_def *def;
+ def = sql_expr_list_to_key_def(pParse, sSort.pOrderBy, 0);
sSort.iECursor = pParse->nTab++;
/* Number of columns in transient table equals to number of columns in
* SELECT statement plus number of columns in ORDER BY statement
* and plus one column for ID.
*/
int nCols = pEList->nExpr + sSort.pOrderBy->nExpr + 1;
- if (pKeyInfo->aSortOrder[0] == SORT_ORDER_DESC) {
+ if (def->parts[0].sort_order == SORT_ORDER_DESC) {
sSort.sortFlags |= SORTFLAG_DESC;
}
sSort.addrSortIndex =
sqlite3VdbeAddOp4(v, OP_OpenTEphemeral,
sSort.iECursor,
nCols,
- 0, (char *)pKeyInfo, P4_KEYINFO);
+ 0, (char *)def, P4_KEYDEF);
VdbeComment((v, "Sort table"));
} else {
sSort.addrSortIndex = -1;
@@ -5641,10 +5604,10 @@ sqlite3Select(Parse * pParse, /* The parser context */
/* If the output is destined for a temporary table, open that table.
*/
if (pDest->eDest == SRT_EphemTab) {
- KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db,
- pEList->nExpr + 1, 0);
+ struct key_def *def;
+ def = key_def_new(pEList->nExpr + 1);
sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, pDest->iSDParm,
- pEList->nExpr + 1, 0, (char*)pKeyInfo, P4_KEYINFO);
+ pEList->nExpr + 1, 0, (char*)def, P4_KEYDEF);
VdbeComment((v, "Output table"));
}
@@ -5665,12 +5628,12 @@ sqlite3Select(Parse * pParse, /* The parser context */
*/
if (p->selFlags & SF_Distinct) {
sDistinct.tabTnct = pParse->nTab++;
- KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, p->pEList, 0, 0);
+ struct key_def *def = sql_expr_list_to_key_def(pParse, p->pEList, 0);
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenTEphemeral,
sDistinct.tabTnct,
- pKeyInfo->nField,
- 0, (char *)pKeyInfo,
- P4_KEYINFO);
+ def->part_count,
+ 0, (char *)def,
+ P4_KEYDEF);
VdbeComment((v, "Distinct table"));
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
} else {
@@ -5811,7 +5774,6 @@ sqlite3Select(Parse * pParse, /* The parser context */
* much more complex than aggregates without a GROUP BY.
*/
if (pGroupBy) {
- KeyInfo *pKeyInfo; /* Keying information for the group by clause */
int addr1; /* A-vs-B comparision jump */
int addrOutputRow; /* Start of subroutine that outputs a result row */
int regOutputRow; /* Return address register for output subroutine */
@@ -5827,14 +5789,12 @@ sqlite3Select(Parse * pParse, /* The parser context */
* will be converted into a Noop.
*/
sAggInfo.sortingIdx = pParse->nTab++;
- pKeyInfo =
- keyInfoFromExprList(pParse, pGroupBy, 0,
- sAggInfo.nColumn);
+ struct key_def *def = sql_expr_list_to_key_def(pParse, pGroupBy, 0);
addrSortingIdx =
sqlite3VdbeAddOp4(v, OP_SorterOpen,
sAggInfo.sortingIdx,
sAggInfo.nSortingColumn, 0,
- (char *)pKeyInfo, P4_KEYINFO);
+ (char *)def, P4_KEYDEF);
/* Initialize memory locations used by GROUP BY aggregate processing
*/
@@ -5872,7 +5832,7 @@ sqlite3Select(Parse * pParse, /* The parser context */
if (sqlite3WhereIsOrdered(pWInfo) == pGroupBy->nExpr) {
/* The optimizer is able to deliver rows in group by order so
* we do not have to sort. The OP_OpenEphemeral table will be
- * cancelled later because we still need to use the pKeyInfo
+ * cancelled later because we still need to use the key_def
*/
groupBySort = 0;
} else {
@@ -5982,10 +5942,15 @@ sqlite3Select(Parse * pParse, /* The parser context */
iBMem + j);
}
}
+ struct key_def *dup_def = key_def_dup(def);
+ if (dup_def == NULL) {
+ db->mallocFailed = 1;
+ goto select_end;
+ }
sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem,
pGroupBy->nExpr,
- (char *)sqlite3KeyInfoRef(pKeyInfo),
- P4_KEYINFO);
+ (char*)dup_def,
+ P4_KEYDEF);
addr1 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addr1 + 1, 0, addr1 + 1);
VdbeCoverage(v);
@@ -6095,7 +6060,7 @@ sqlite3Select(Parse * pParse, /* The parser context */
*/
const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */
Index *pIdx; /* Iterator variable */
- KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
+ struct key_def *def = NULL;
Index *pBest; /* Best index found so far */
int iRoot = pTab->tnum; /* Root page of scanned b-tree */
@@ -6105,7 +6070,7 @@ sqlite3Select(Parse * pParse, /* The parser context */
*
* (2013-10-03) Do not count the entries in a partial index.
*
- * In practice the KeyInfo structure will not be used. It is only
+ * In practice the key_def structure will not be used. It is only
* passed to keep OP_OpenRead happy.
*/
pBest = sqlite3PrimaryKeyIndex(pTab);
@@ -6121,19 +6086,17 @@ sqlite3Select(Parse * pParse, /* The parser context */
pBest = pIdx;
}
}
- if (pBest) {
+ if (pBest != NULL) {
iRoot = pBest->tnum;
- pKeyInfo =
- sqlite3KeyInfoOfIndex(pParse, db,
- pBest);
+ def = sql_index_key_def(pBest, true);
}
/* Open a read-only cursor, execute the OP_Count, close the cursor. */
emit_open_cursor(pParse, iCsr, iRoot);
- if (pKeyInfo) {
+ if (def != NULL) {
sqlite3VdbeChangeP4(v, -1,
- (char *)pKeyInfo,
- P4_KEYINFO);
+ (char *)def,
+ P4_KEYDEF);
}
sqlite3VdbeAddOp2(v, OP_Count, iCsr,
sAggInfo.aFunc[0].iMem);
@@ -6186,7 +6149,7 @@ sqlite3Select(Parse * pParse, /* The parser context */
assert(db->mallocFailed
|| pMinMax != 0);
if (!db->mallocFailed) {
- pMinMax->a[0].sortOrder =
+ pMinMax->a[0].sort_order =
flag !=
WHERE_ORDERBY_MIN ? 1 : 0;
pMinMax->a[0].pExpr->op =
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 2a801a4..7fa8d6f 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -1462,7 +1462,6 @@ typedef struct IdList IdList;
typedef struct Index Index;
typedef struct IndexSample IndexSample;
typedef struct KeyClass KeyClass;
-typedef struct KeyInfo KeyInfo;
typedef struct Lookaside Lookaside;
typedef struct LookasideSlot LookasideSlot;
typedef struct NameContext NameContext;
@@ -2025,24 +2024,6 @@ struct FKey {
#define OE_SetDflt 8 /* Set the foreign key value to its default */
#define OE_Cascade 9 /* Cascade the changes */
-/*
- * An instance of the following structure is passed as the first
- * argument to sqlite3VdbeKeyCompare and is used to control the
- * comparison of the two index keys.
- *
- * Note that aSortOrder[] and aColl[] have nField+1 slots. There
- * are nField slots for the columns of an index.
- */
-struct KeyInfo {
- u32 nRef; /* Number of references to this KeyInfo object */
- u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
- u16 nField; /* Number of key columns in the index */
- u16 nXField; /* Number of columns beyond the key columns */
- sqlite3 *db; /* The database connection */
- u8 *aSortOrder; /* Sort order for each column. */
- struct coll *aColl[1]; /* Collating sequence for each term of the key */
-};
-
/*
* This object holds a record which has been parsed out into individual
* fields, for the purposes of doing a comparison.
@@ -2057,7 +2038,7 @@ struct KeyInfo {
* an index b+tree. The goal of the search is to find the entry that
* is closed to the key described by this object. This object might hold
* just a prefix of the key. The number of fields is given by
- * pKeyInfo->nField.
+ * key_def->part_count.
*
* The r1 and r2 fields are the values to return if this key is less than
* or greater than a key in the btree, respectively. These are normally
@@ -2067,7 +2048,7 @@ struct KeyInfo {
* The key comparison functions actually return default_rc when they find
* an equals comparison. default_rc can be -1, 0, or +1. If there are
* multiple entries in the b-tree with the same key (when only looking
- * at the first pKeyInfo->nFields,) then default_rc can be set to -1 to
+ * at the first key_def->part_count) then default_rc can be set to -1 to
* cause the search to find the last match, or +1 to cause the search to
* find the first match.
*
@@ -2079,7 +2060,8 @@ struct KeyInfo {
* b-tree.
*/
struct UnpackedRecord {
- KeyInfo *pKeyInfo; /* Collation and sort-order information */
+ /** Collation and sort-order information. */
+ struct key_def* key_def;
Mem *aMem; /* Values */
u16 nField; /* Number of entries in apMem[] */
i8 default_rc; /* Comparison result if keys are equal */
@@ -2456,7 +2438,7 @@ struct ExprList {
Expr *pExpr; /* The list of expressions */
char *zName; /* Token associated with this expression */
char *zSpan; /* Original text of the expression */
- u8 sortOrder; /* 1 for DESC or 0 for ASC */
+ enum sort_order sort_order;
unsigned done:1; /* A flag to indicate when processing is finished */
unsigned bSpanIsTab:1; /* zSpan holds DB.TABLE.COLUMN */
unsigned reusable:1; /* Constant expression is reusable */
@@ -2688,12 +2670,12 @@ struct NameContext {
*
* addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes.
* These addresses must be stored so that we can go back and fill in
- * the P4_KEYINFO and P2 parameters later. Neither the KeyInfo nor
+ * the P4_KEYDEF and P2 parameters later. Neither the key_def nor
* the number of columns in P2 can be computed at the same time
* as the OP_OpenEphm instruction is coded because not
* enough information about the compound query is known at that point.
- * The KeyInfo for addrOpenTran[0] and [1] contains collating sequences
- * for the result set. The KeyInfo for addrOpenEphm[2] contains collating
+ * The key_def for addrOpenTran[0] and [1] contains collating sequences
+ * for the result set. The key_def for addrOpenEphm[2] contains collating
* sequences for the ORDER BY clause.
*/
struct Select {
@@ -3495,7 +3477,15 @@ Expr *sqlite3ExprFunction(Parse *, ExprList *, Token *);
void sqlite3ExprAssignVarNumber(Parse *, Expr *, u32);
ExprList *sqlite3ExprListAppend(Parse *, ExprList *, Expr *);
ExprList *sqlite3ExprListAppendVector(Parse *, ExprList *, IdList *, Expr *);
-void sqlite3ExprListSetSortOrder(ExprList *, int);
+
+/**
+ * Set the sort order for the last element on the given ExprList.
+ *
+ * @param p Expression list.
+ * @param sort_order Sort order to set.
+ */
+void sqlite3ExprListSetSortOrder(ExprList *, enum sort_order sort_order);
+
void sqlite3ExprListSetName(Parse *, ExprList *, Token *, int);
void sqlite3ExprListSetSpan(Parse *, ExprList *, ExprSpan *);
void sqlite3ExprListDelete(sqlite3 *, ExprList *);
@@ -3527,11 +3517,22 @@ const char *
index_collation_name(Index *, uint32_t);
struct coll *
sql_index_collation(Index *idx, uint32_t column);
-struct coll *
-sql_default_coll();
bool
space_is_view(Table *);
+/**
+ * Return key_def of provided struct Index. This routine
+ * actually performs key duplication.
+ *
+ * @param idx Pointer to `struct Index` object.
+ * @param is_dup Flag which is set if key_def should be
+ * duplicated.
+ *
+ * @retval Pointer to `struct key_def`.
+ */
+struct key_def*
+sql_index_key_def(struct Index *idx, bool is_dup);
+
/**
* Return sort order of given column from index.
*
@@ -3586,10 +3587,50 @@ void sqlite3SrcListDelete(sqlite3 *, SrcList *);
Index *sqlite3AllocateIndexObject(sqlite3 *, i16, int, char **);
bool
index_is_unique(Index *);
-void sqlite3CreateIndex(Parse *, Token *, SrcList *, ExprList *, int, Token *,
- Expr *, int, int, u8);
+
+/**
+ * Create a new index for an SQL table. name is the name of the
+ * index and tbl_name is the name of the table that is to be
+ * indexed. Both will be NULL for a primary key or an index that
+ * is created to satisfy a UNIQUE constraint. If tbl_name and
+ * name are NULL, use parse->pNewTable as the table to be indexed.
+ * parse->pNewTable is a table that is currently being
+ * constructed by a CREATE TABLE statement.
+ *
+ * col_list is a list of columns to be indexed. col_list will be
+ * NULL if this is a primary key or unique-constraint on the most
+ * recent column added to the table currently under construction.
+ *
+ * @param parse All information about this parse.
+ * @param name Index name. May be NULL.
+ * @param tbl_name Table to index. Use pParse->pNewTable ifNULL.
+ * @param col_list A list of columns to be indexed.
+ * @param on_error One of ON_CONFLICT_ACTION_ABORT, _IGNORE,
+ * _REPLACE, or _NONE.
+ * @param start The CREATE token that begins this statement.
+ * @param pi_where WHERE clause for partial indices.
+ * @param sort_order Sort order of primary key when pList==NULL.
+ * @param if_not_exist Omit error if index already exists.
+ * @param idx_type The index type.
+ */
+void
+sql_create_index(struct Parse *parse, struct Token *token,
+ struct SrcList *tbl_name, struct ExprList *col_list,
+ int on_error, struct Token *start, struct Expr *pi_where,
+ enum sort_order sort_order, bool if_not_exist, u8 idx_type);
+
+/**
+ * This routine will drop an existing named index. This routine
+ * implements the DROP INDEX statement.
+ *
+ * @param parse_context Current parsing context.
+ * @param index_name_list List containing index name.
+ * @param table_token Token representing table name.
+ * @param if_exists True, if statement contains 'IF EXISTS' clause.
+ */
void
sql_drop_index(struct Parse *, struct SrcList *, struct Token *, bool);
+
int sqlite3Select(Parse *, Select *, SelectDest *);
Select *sqlite3SelectNew(Parse *, ExprList *, SrcList *, Expr *, ExprList *,
Expr *, ExprList *, u32, Expr *, Expr *);
@@ -3920,7 +3961,17 @@ void sqlite3NestedParse(Parse *, const char *, ...);
void sqlite3ExpirePreparedStatements(sqlite3 *);
int sqlite3CodeSubselect(Parse *, Expr *, int);
void sqlite3SelectPrep(Parse *, Select *, NameContext *);
-void sqlite3SelectWrongNumTermsError(Parse * pParse, Select * p);
+
+/**
+ * Error message for when two or more terms of a compound select
+ * have different size result sets.
+ *
+ * @param parse Parsing context.
+ * @param p Select struct to analyze.
+ */
+void
+sqlite3SelectWrongNumTermsError(struct Parse *parse, struct Select *p);
+
int sqlite3MatchSpanName(const char *, const char *, const char *);
int sqlite3ResolveExprNames(NameContext *, Expr *);
int sqlite3ResolveExprListNames(NameContext *, ExprList *);
@@ -3949,13 +4000,6 @@ void sqlite3RegisterLikeFunctions(sqlite3 *, int);
int sqlite3IsLikeFunction(sqlite3 *, Expr *, int *, char *);
void sqlite3SchemaClear(sqlite3 *);
Schema *sqlite3SchemaCreate(sqlite3 *);
-KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *, int, int);
-void sqlite3KeyInfoUnref(KeyInfo *);
-KeyInfo *sqlite3KeyInfoRef(KeyInfo *);
-KeyInfo *sqlite3KeyInfoOfIndex(Parse *, sqlite3 *, Index *);
-#ifdef SQLITE_DEBUG
-int sqlite3KeyInfoIsWriteable(KeyInfo *);
-#endif
int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
void (*)(sqlite3_context *, int, sqlite3_value **),
void (*)(sqlite3_context *, int, sqlite3_value **),
diff --git a/src/box/sql/tarantoolInt.h b/src/box/sql/tarantoolInt.h
index 57fc4a1..8fc9dd6 100644
--- a/src/box/sql/tarantoolInt.h
+++ b/src/box/sql/tarantoolInt.h
@@ -98,7 +98,7 @@ int tarantoolSqlite3RenameParentTable(int iTab, const char *zOldParentName,
/* Interface for ephemeral tables. */
int tarantoolSqlite3EphemeralCreate(BtCursor * pCur, uint32_t filed_count,
- struct coll *aColl);
+ struct key_def *def);
/**
* Insert tuple into ephemeral space.
* In contrast to ordinary spaces, there is no need to create and
@@ -119,12 +119,19 @@ int tarantoolSqlite3EphemeralClearTable(BtCursor * pCur);
int tarantoolSqlite3EphemeralGetMaxId(BtCursor * pCur, uint32_t fieldno,
uint64_t * max_id);
-/* Compare against the index key under a cursor -
- * the key may span non-adjacent fields in a random order,
- * ex: [4]-[1]-[2]
+/**
+ * Performs exactly as extract_key + sqlite3VdbeCompareMsgpack,
+ * only faster.
+ *
+ * @param pCur cursor which point to tuple to compare.
+ * @param pUnpacked Unpacked record to compare with.
+ * @param[out] res Comparison result.
+ *
+ * @retval Error code.
*/
-int tarantoolSqlite3IdxKeyCompare(BtCursor * pCur, UnpackedRecord * pUnpacked,
- int *res);
+int
+tarantoolSqlite3IdxKeyCompare(struct BtCursor *cursor,
+ struct UnpackedRecord *unpacked, int *res);
/**
* The function assumes the cursor is open on _schema.
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index f3bd0b7..31d07d5 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -358,12 +358,16 @@ sqlite3Update(Parse * pParse, /* The parser context */
sqlite3VdbeAddOp2(v, OP_Null, 0, iPk);
if (isView) {
- KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nKey, 0);
+ struct key_def *def = key_def_new(nKey);
+ if (def == NULL) {
+ pParse->db->mallocFailed = 1;
+ goto update_cleanup;
+ }
addrOpen = sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, iEph,
- nKey, 0, (char*)pKeyInfo, P4_KEYINFO);
+ nKey, 0, (char*)def, P4_KEYDEF);
} else {
addrOpen = sqlite3VdbeAddOp2(v, OP_OpenTEphemeral, iEph, nPk);
- sqlite3VdbeSetP4KeyInfo(pParse, pPk);
+ sql_vdbe_set_p4_key_def(pParse, pPk);
}
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index f405ac0..127f320 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2242,35 +2242,36 @@ case OP_Permutation: {
* OPFLAG_PERMUTE bit is clear, then register are compared in sequential
* order.
*
- * P4 is a KeyInfo structure that defines collating sequences and sort
+ * P4 is a key_def structure that defines collating sequences and sort
* orders for the comparison. The permutation applies to registers
- * only. The KeyInfo elements are used sequentially.
+ * only. The key_def elements are used sequentially.
*
* The comparison is a sort comparison, so NULLs compare equal,
* NULLs are less than numbers, numbers are less than strings,
* and strings are less than blobs.
*/
case OP_Compare: {
- int n;
- int i;
int p1;
int p2;
- const KeyInfo *pKeyInfo;
int idx;
- struct coll *pColl; /* Collating sequence to use on this term */
- int bRev; /* True for DESCENDING sort order */
- if ((pOp->p5 & OPFLAG_PERMUTE)==0) aPermute = 0;
- n = pOp->p3;
- pKeyInfo = pOp->p4.pKeyInfo;
+ if ((pOp->p5 & OPFLAG_PERMUTE) == 0)
+ aPermute = 0;
+
+ int n = pOp->p3;
+
+ assert(pOp->p4type == P4_KEYDEF);
assert(n>0);
- assert(pKeyInfo!=0);
p1 = pOp->p1;
p2 = pOp->p2;
+
+ struct key_def *def = pOp->p4.key_def;
#if SQLITE_DEBUG
if (aPermute) {
- int k, mx = 0;
- for(k=0; k<n; k++) if (aPermute[k]>mx) mx = aPermute[k];
+ int mx = 0;
+ for(uint32_t k = 0; k < (uint32_t)n; k++)
+ if (aPermute[k] > mx)
+ mx = aPermute[k];
assert(p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1);
assert(p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1);
} else {
@@ -2278,18 +2279,19 @@ case OP_Compare: {
assert(p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1);
}
#endif /* SQLITE_DEBUG */
- for(i=0; i<n; i++) {
+ for(int i = 0; i < n; i++) {
idx = aPermute ? aPermute[i] : i;
assert(memIsValid(&aMem[p1+idx]));
assert(memIsValid(&aMem[p2+idx]));
REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
- assert(i<pKeyInfo->nField);
- pColl = pKeyInfo->aColl[i];
- bRev = pKeyInfo->aSortOrder[i];
- iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
+ assert(i < (int)def->part_count);
+ struct coll *coll = def->parts[i].coll;
+ bool is_rev = def->parts[i].sort_order == SORT_ORDER_DESC;
+ iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], coll);
if (iCompare) {
- if (bRev) iCompare = -iCompare;
+ if (is_rev)
+ iCompare = -iCompare;
break;
}
}
@@ -3118,8 +3120,8 @@ case OP_SetCookie: {
* values need not be contiguous but all P1 values should be
* small integers. It is an error for P1 to be negative.
*
- * The P4 value may be a pointer to a KeyInfo structure.
- * If it is a pointer to a KeyInfo structure, then said structure
+ * The P4 value may be a pointer to a key_def structure.
+ * If it is a pointer to a key_def structure, then said structure
* defines the content and collatining sequence of the index
* being opened. Otherwise, P4 is NULL.
*
@@ -3207,7 +3209,7 @@ case OP_OpenWrite:
pBtCur->index = index;
pBtCur->eState = CURSOR_INVALID;
/* Key info still contains sorter order and collation. */
- pCur->pKeyInfo = pOp->p4.pKeyInfo;
+ pCur->key_def = index->def->key_def;
open_cursor_set_hints:
assert(OPFLAG_BULKCSR==BTREE_BULKLOAD);
@@ -3222,8 +3224,12 @@ open_cursor_set_hints:
break;
}
-/* Opcode: OpenTEphemeral P1 P2 * * *
- * Synopsis: nColumn = P2
+/**
+ * Opcode: OpenTEphemeral P1 P2 * P4 *
+ * Synopsis:
+ * @param P1 index of new cursor to be created
+ * @param P2 number of columns in a new table
+ * @param P4 key def for new table
*
* This opcode creates Tarantool's ephemeral table and sets cursor P1 to it.
*/
@@ -3232,21 +3238,21 @@ case OP_OpenTEphemeral: {
BtCursor *pBtCur;
assert(pOp->p1 >= 0);
assert(pOp->p2 > 0);
- assert(pOp->p4.pKeyInfo != 0);
- assert(pOp->p4type == P4_KEYINFO);
+ assert(pOp->p4.key_def != NULL);
+ assert(pOp->p4type == P4_KEYDEF);
pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_TARANTOOL);
if (pCx == 0) goto no_mem;
pCx->nullRow = 1;
- pCx->pKeyInfo = pOp->p4.pKeyInfo;
+ pCx->key_def = pOp->p4.key_def;
pBtCur = pCx->uc.pCursor;
/* Ephemeral spaces don't have space_id */
pBtCur->eState = CURSOR_INVALID;
pBtCur->curFlags = BTCF_TEphemCursor;
rc = tarantoolSqlite3EphemeralCreate(pCx->uc.pCursor, pOp->p2,
- pOp->p4.pKeyInfo->aColl[0]);
+ pCx->key_def);
if (rc) goto abort_due_to_error;
break;
}
@@ -3268,9 +3274,8 @@ case OP_SorterOpen: {
assert(pOp->p2>=0);
pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_SORTER);
if (pCx==0) goto no_mem;
- pCx->pKeyInfo = pOp->p4.pKeyInfo;
- assert(pCx->pKeyInfo->db==db);
- rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx);
+ pCx->key_def = pOp->p4.key_def;
+ rc = sqlite3VdbeSorterInit(db, pCx);
if (rc) goto abort_due_to_error;
break;
}
@@ -3546,7 +3551,7 @@ case OP_SeekGT: { /* jump, in3 */
nField = pOp->p4.i;
assert(pOp->p4type==P4_INT32);
assert(nField>0);
- r.pKeyInfo = pC->pKeyInfo;
+ r.key_def = pC->key_def;
r.nField = (u16)nField;
if (reg_ipk > 0) {
@@ -3698,7 +3703,7 @@ case OP_Found: { /* jump, in3 */
assert(pC->eCurType==CURTYPE_TARANTOOL);
assert(pC->uc.pCursor!=0);
if (pOp->p4.i>0) {
- r.pKeyInfo = pC->pKeyInfo;
+ r.key_def = pC->key_def;
r.nField = (u16)pOp->p4.i;
r.aMem = pIn3;
#ifdef SQLITE_DEBUG
@@ -3711,11 +3716,12 @@ case OP_Found: { /* jump, in3 */
pIdxKey = &r;
pFree = 0;
} else {
- pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
+ pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(db, pC->key_def);
if (pIdxKey==0) goto no_mem;
assert(pIn3->flags & MEM_Blob );
(void)ExpandBlob(pIn3);
- sqlite3VdbeRecordUnpackMsgpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
+ sqlite3VdbeRecordUnpackMsgpack(pC->key_def,
+ pIn3->z, pIdxKey);
}
pIdxKey->default_rc = 0;
pIdxKey->opcode = pOp->opcode;
@@ -4491,7 +4497,7 @@ case OP_IdxDelete: {
pCrsr = pC->uc.pCursor;
assert(pCrsr!=0);
assert(pOp->p5==0);
- r.pKeyInfo = pC->pKeyInfo;
+ r.key_def = pC->key_def;
r.nField = (u16)pOp->p3;
r.default_rc = 0;
r.aMem = &aMem[pOp->p2];
@@ -4575,7 +4581,7 @@ case OP_IdxGE: { /* jump */
assert(pC->deferredMoveto==0);
assert(pOp->p5==0 || pOp->p5==1);
assert(pOp->p4type==P4_INT32);
- r.pKeyInfo = pC->pKeyInfo;
+ r.key_def = pC->key_def;
r.nField = (u16)pOp->p4.i;
if (pOp->opcode<OP_IdxLT) {
assert(pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxGT);
@@ -4589,7 +4595,7 @@ case OP_IdxGE: { /* jump */
{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
#endif
res = 0; /* Not needed. Only used to silence a warning. */
- rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
+ rc = sqlite3VdbeIdxKeyCompare(pC, &r, &res);
assert((OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1));
if ((pOp->opcode&1)==(OP_IdxLT&1)) {
assert(pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT);
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index d1f416b..e9ef693 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -77,7 +77,6 @@ struct VdbeOp {
struct coll *pColl; /* Used when p4type is P4_COLLSEQ */
Mem *pMem; /* Used when p4type is P4_MEM */
bool b; /* Used when p4type is P4_BOOL */
- KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
int *ai; /* Used when p4type is P4_INTARRAY */
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
Index *pIndex; /* Used when p4type is P4_INDEX */
@@ -85,6 +84,8 @@ struct VdbeOp {
Expr *pExpr; /* Used when p4type is P4_EXPR */
#endif
int (*xAdvance) (BtCursor *, int *);
+ /* Used when p4type is P4_KEYDEF. */
+ struct key_def *key_def;
} p4;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
char *zComment; /* Comment to improve readability */
@@ -131,7 +132,6 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_STATIC (-2) /* Pointer to a static string */
#define P4_COLLSEQ (-3) /* P4 is a pointer to a CollSeq structure */
#define P4_FUNCDEF (-4) /* P4 is a pointer to a FuncDef structure */
-#define P4_KEYINFO (-5) /* P4 is a pointer to a KeyInfo structure */
#define P4_EXPR (-6) /* P4 is a pointer to an Expr tree */
#define P4_MEM (-7) /* P4 is a pointer to a Mem* structure */
#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */
@@ -147,7 +147,6 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_PTR (-18) /* P4 is a generic pointer */
#define P4_KEYDEF (-19) /* P4 is a pointer to key_def structure. */
-
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
#define P5_ConstraintUnique 2
@@ -249,7 +248,16 @@ int sqlite3VdbeChangeToNoop(Vdbe *, int addr);
int sqlite3VdbeDeletePriorOpcode(Vdbe *, u8 op);
void sqlite3VdbeChangeP4(Vdbe *, int addr, const char *zP4, int N);
void sqlite3VdbeAppendP4(Vdbe *, void *pP4, int p4type);
-void sqlite3VdbeSetP4KeyInfo(Parse *, Index *);
+
+/**
+ * Set the P4 on the most recently added opcode to the key_def for the
+ * index given.
+ * @param Parse context, for error reporting.
+ * @param Index to get key_def from.
+ */
+void
+sql_vdbe_set_p4_key_def(struct Parse *parse, struct Index *index);
+
VdbeOp *sqlite3VdbeGetOp(Vdbe *, int);
int sqlite3VdbeMakeLabel(Vdbe *);
void sqlite3VdbeRunOnlyOnce(Vdbe *);
@@ -280,14 +288,27 @@ char *sqlite3VdbeExpandSql(Vdbe *, const char *);
#endif
int sqlite3MemCompare(const Mem *, const Mem *, const struct coll *);
-void sqlite3VdbeRecordUnpackMsgpack(KeyInfo *, int, const void *,
- UnpackedRecord *);
-int sqlite3VdbeRecordCompare(int, const void *, UnpackedRecord *);
-int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int);
-UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *);
+/**
+ * Perform unpacking of provided message pack.
+ *
+ * @param key_def Information about the record format
+ * @param key The binary record
+ * @param dest Populate this structure before returning.
+ */
+void sqlite3VdbeRecordUnpackMsgpack(struct key_def *key_def,
+ const void *msgpack,
+ struct UnpackedRecord *dest);
+
+int sqlite3VdbeRecordCompare(struct sqlite3 *db, int key_count,
+ const void *key1, UnpackedRecord *key2);
+int sqlite3VdbeRecordCompareWithSkip(struct sqlite3 *db,
+ int key_count, const void *key1,
+ struct UnpackedRecord *key2, bool is_skip);
+UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(struct sqlite3 *,
+ struct key_def *);
int sql_vdbe_mem_alloc_region(Mem *, uint32_t);
-typedef int (*RecordCompare) (int, const void *, UnpackedRecord *);
+typedef int (*RecordCompare) (const void *, UnpackedRecord *);
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *);
#ifndef SQLITE_OMIT_TRIGGER
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 3a907cd..9779654 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -110,7 +110,8 @@ struct VdbeCursor {
int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */
VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
} uc;
- KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
+ /* Info about keys needed by index cursors. */
+ struct key_def *key_def;
i16 nField; /* Number of fields in the header */
u16 nHdrParsed; /* Number of header fields parsed so far */
const u8 *aRow; /* Data for the current row, if all on one page */
@@ -430,7 +431,6 @@ struct PreUpdate {
VdbeCursor *pCsr; /* Cursor to read old values from */
int op; /* One of SQLITE_INSERT, UPDATE, DELETE */
u8 *aRecord; /* old.* database record */
- KeyInfo keyinfo;
UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */
UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
int iNewReg; /* Register for new.* values */
@@ -458,7 +458,24 @@ u32 sqlite3VdbeSerialPut(unsigned char *, Mem *, u32);
u32 sqlite3VdbeSerialGet(const unsigned char *, u32, Mem *);
void sqlite3VdbeDeleteAuxData(sqlite3 *, AuxData **, int, int);
-int sqlite3VdbeIdxKeyCompare(sqlite3 *, VdbeCursor *, UnpackedRecord *, int *);
+/**
+ * Compare the key of the index entry that cursor vdbe_cursor is
+ * pointing to against the key string in unpacked. Write into
+ * *res a number that is negative, zero, or positive if
+ * vdbe_cursor is less than, equal to, or greater than unpacked.
+ * Return SQLITE_OK on success.
+ *
+ * @param vdbe_cursor Cursor, which points to tuple to compare.
+ * @param unpacked Unpacked version of key.
+ * @param[out] Write the comparison result here.
+ *
+ * @retval Error status code.
+ */
+int
+sqlite3VdbeIdxKeyCompare(struct VdbeCursor *vdbe_cursor,
+ struct UnpackedRecord *unpacked,
+ int * res);
+
int sqlite3VdbeExec(Vdbe *);
int sqlite3VdbeList(Vdbe *);
int
@@ -500,13 +517,9 @@ int sqlite3VdbeMemClearAndResize(Mem * pMem, int n);
int sqlite3VdbeCloseStatement(Vdbe *, int);
void sqlite3VdbeFrameDelete(VdbeFrame *);
int sqlite3VdbeFrameRestore(VdbeFrame *);
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-void sqlite3VdbePreUpdateHook(Vdbe *, VdbeCursor *, int, const char *, Table *,
- i64, int);
-#endif
int sqlite3VdbeTransferError(Vdbe * p);
-int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
+int sqlite3VdbeSorterInit(struct sqlite3 *db, struct VdbeCursor *cursor);
void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
@@ -543,10 +556,28 @@ int sqlite3VdbeMemExpandBlob(Mem *);
i64 sqlite3VdbeMsgpackRecordLen(Mem * pMem, u32 n);
u32 sqlite3VdbeMsgpackRecordPut(u8 * pBuf, Mem * pMem, u32 n);
-int sqlite3VdbeCompareMsgpack(const char **pKey1,
- UnpackedRecord * pUnpacked, int iKey2);
-int sqlite3VdbeRecordCompareMsgpack(int nKey1, const void *pKey1,
- UnpackedRecord * pPKey2);
+/**
+ * Perform comparison of two keys: one is packed and one is not.
+ *
+ * @param key1 Pointer to pointer to first key.
+ * @param unpacked Pointer to unpacked tuple.
+ * @param key2_idx index of key in umpacked record to compare.
+ *
+ * @retval +1 if key1 > pUnpacked[iKey2], -1 ptherwise.
+ */
+int sqlite3VdbeCompareMsgpack(const char **key1,
+ struct UnpackedRecord *unpacked, int key2_idx);
+
+/**
+ * Perform comparison of two tuples: unpacked (key1) and packed (key2)
+ *
+ * @param key1 Packed key.
+ * @param unpacked Unpacked key.
+ *
+ * @retval +1 if key1 > unpacked, -1 otherwise.
+ */
+int sqlite3VdbeRecordCompareMsgpack(const void *key1,
+ struct UnpackedRecord *key2);
u32 sqlite3VdbeMsgpackGet(const unsigned char *buf, Mem * pMem);
#endif /* !defined(SQLITE_VDBEINT_H) */
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index 32af463..d35338a 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -1577,103 +1577,6 @@ sqlite3_expanded_sql(sqlite3_stmt * pStmt)
#endif
}
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-/*
- * Allocate and populate an UnpackedRecord structure based on the serialized
- * record in nKey/pKey. Return a pointer to the new UnpackedRecord structure
- * if successful, or a NULL pointer if an OOM error is encountered.
- */
-static UnpackedRecord *
-vdbeUnpackRecord(KeyInfo * pKeyInfo, int nKey, const void *pKey)
-{
- UnpackedRecord *pRet; /* Return value */
-
- pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
- if (pRet) {
- memset(pRet->aMem, 0, sizeof(Mem) * (pKeyInfo->nField + 1));
- sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
- }
- return pRet;
-}
-
-/*
- * This function is called from within a pre-update callback to retrieve
- * a field of the row currently being updated or deleted.
- */
-int
-sqlite3_preupdate_old(sqlite3 * db, int iIdx, sqlite3_value ** ppValue)
-{
- PreUpdate *p = db->pPreUpdate;
- int rc = SQLITE_OK;
-
- /* Test that this call is being made from within an SQLITE_DELETE or
- * SQLITE_UPDATE pre-update callback, and that iIdx is within range.
- */
- if (!p || p->op == SQLITE_INSERT) {
- rc = SQLITE_MISUSE_BKPT;
- goto preupdate_old_out;
- }
- if (iIdx >= p->pCsr->nField || iIdx < 0) {
- rc = SQLITE_RANGE;
- goto preupdate_old_out;
- }
-
- /* If the old.* record has not yet been loaded into memory, do so now. */
- if (p->pUnpacked == 0) {
- u32 nRec;
- u8 *aRec;
-
- nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
- aRec = sqlite3DbMallocRaw(db, nRec);
- if (!aRec)
- goto preupdate_old_out;
- rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
- if (rc == SQLITE_OK) {
- p->pUnpacked =
- vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
- if (!p->pUnpacked)
- rc = SQLITE_NOMEM;
- }
- if (rc != SQLITE_OK) {
- sqlite3DbFree(db, aRec);
- goto preupdate_old_out;
- }
- p->aRecord = aRec;
- }
-
- if (iIdx >= p->pUnpacked->nField) {
- *ppValue = (sqlite3_value *) columnNullValue();
- } else {
- Mem *pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
- *ppValue = &p->pUnpacked->aMem[iIdx];
- if (iIdx == p->pTab->iPKey) {
- sqlite3VdbeMemSetInt64(pMem, p->iKey1);
- } else if (p->pTab->aCol[iIdx].affinity == SQLITE_AFF_REAL) {
- if (pMem->flags & MEM_Int) {
- sqlite3VdbeMemRealify(pMem);
- }
- }
- }
-
- preupdate_old_out:
- sqlite3Error(db, rc);
- return sqlite3ApiExit(db, rc);
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-/*
- * This function is called from within a pre-update callback to retrieve
- * the number of columns in the row being updated, deleted or inserted.
- */
-int
-sqlite3_preupdate_count(sqlite3 * db)
-{
- PreUpdate *p = db->pPreUpdate;
- return (p ? p->keyinfo.nField : 0);
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
/*
* This function is designed to be called from within a pre-update callback
@@ -1694,92 +1597,6 @@ sqlite3_preupdate_depth(sqlite3 * db)
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-/*
- * This function is called from within a pre-update callback to retrieve
- * a field of the row currently being updated or inserted.
- */
-int
-sqlite3_preupdate_new(sqlite3 * db, int iIdx, sqlite3_value ** ppValue)
-{
- PreUpdate *p = db->pPreUpdate;
- int rc = SQLITE_OK;
- Mem *pMem;
-
- if (!p || p->op == SQLITE_DELETE) {
- rc = SQLITE_MISUSE_BKPT;
- goto preupdate_new_out;
- }
- if (iIdx >= p->pCsr->nField || iIdx < 0) {
- rc = SQLITE_RANGE;
- goto preupdate_new_out;
- }
-
- if (p->op == SQLITE_INSERT) {
- /* For an INSERT, memory cell p->iNewReg contains the serialized record
- * that is being inserted. Deserialize it.
- */
- UnpackedRecord *pUnpack = p->pNewUnpacked;
- if (!pUnpack) {
- Mem *pData = &p->v->aMem[p->iNewReg];
- rc = ExpandBlob(pData);
- if (rc != SQLITE_OK)
- goto preupdate_new_out;
- pUnpack =
- vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z);
- if (!pUnpack) {
- rc = SQLITE_NOMEM;
- goto preupdate_new_out;
- }
- p->pNewUnpacked = pUnpack;
- }
- if (iIdx >= pUnpack->nField) {
- pMem = (sqlite3_value *) columnNullValue();
- } else {
- pMem = &pUnpack->aMem[iIdx];
- if (iIdx == p->pTab->iPKey) {
- sqlite3VdbeMemSetInt64(pMem, p->iKey2);
- }
- }
- } else {
- /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
- * value. Make a copy of the cell contents and return a pointer to it.
- * It is not safe to return a pointer to the memory cell itself as the
- * caller may modify the value text encoding.
- */
- assert(p->op == SQLITE_UPDATE);
- if (!p->aNew) {
- p->aNew =
- (Mem *) sqlite3DbMallocZero(db,
- sizeof(Mem) *
- p->pCsr->nField);
- if (!p->aNew) {
- rc = SQLITE_NOMEM;
- goto preupdate_new_out;
- }
- }
- assert(iIdx >= 0 && iIdx < p->pCsr->nField);
- pMem = &p->aNew[iIdx];
- if (pMem->flags == 0) {
- if (iIdx == p->pTab->iPKey) {
- sqlite3VdbeMemSetInt64(pMem, p->iKey2);
- } else {
- rc = sqlite3VdbeMemCopy(pMem,
- &p->v->aMem[p->iNewReg +
- 1 + iIdx]);
- if (rc != SQLITE_OK)
- goto preupdate_new_out;
- }
- }
- }
- *ppValue = pMem;
-
- preupdate_new_out:
- sqlite3Error(db, rc);
- return sqlite3ApiExit(db, rc);
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
/*
* Return status data for a single loop within query pStmt.
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index ead9659..1fb609b 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -978,11 +978,9 @@ freeP4(sqlite3 * db, int p4type, void *p4)
sqlite3DbFree(db, p4);
break;
}
- case P4_KEYINFO:{
- if (db->pnBytesFreed == 0)
- sqlite3KeyInfoUnref((KeyInfo *) p4);
- break;
- }
+ case P4_KEYDEF:
+ key_def_delete(p4);
+ break;
#ifdef SQLITE_ENABLE_CURSOR_HINTS
case P4_EXPR:{
sqlite3ExprDelete(db, (Expr *) p4);
@@ -1170,20 +1168,19 @@ sqlite3VdbeAppendP4(Vdbe * p, void *pP4, int n)
}
}
-/*
- * Set the P4 on the most recently added opcode to the KeyInfo for the
- * index given.
- */
void
-sqlite3VdbeSetP4KeyInfo(Parse * pParse, Index * pIdx)
-{
- Vdbe *v = pParse->pVdbe;
- KeyInfo *pKeyInfo;
- assert(v != 0);
- assert(pIdx != 0);
- pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pParse->db, pIdx);
- if (pKeyInfo)
- sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
+sql_vdbe_set_p4_key_def(struct Parse *parse, struct Index *idx)
+{
+ struct Vdbe *v = parse->pVdbe;
+ assert(v != NULL);
+ 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 *index = index_find(space, index_id);
+ assert(index != NULL);
+ sqlite3VdbeAppendP4(v, key_def_dup(index->def->key_def), P4_KEYDEF);
}
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
@@ -1542,26 +1539,28 @@ displayP4(Op * pOp, char *zTemp, int nTemp)
assert(nTemp >= 20);
sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
switch (pOp->p4type) {
- case P4_KEYINFO:{
- int j;
- KeyInfo *pKeyInfo;
+ case P4_KEYDEF:{
+ struct key_def *def;
- if (pOp->p4.pKeyInfo == NULL) {
+ if (pOp->p4.key_def == NULL) {
sqlite3XPrintf(&x, "k[NULL]");
} else {
- pKeyInfo = pOp->p4.pKeyInfo;
- assert(pKeyInfo->aSortOrder != 0);
- sqlite3XPrintf(&x, "k(%d", pKeyInfo->nField);
- for (j = 0; j < pKeyInfo->nField; j++) {
- struct coll *pColl = pKeyInfo->aColl[j];
- const char *zColl =
- pColl ? pColl->name : "";
- if (strcmp(zColl, "BINARY") == 0)
- zColl = "B";
+ def = pOp->p4.key_def;
+ sqlite3XPrintf(&x, "k(%d", def->part_count);
+ for (int j = 0; j < (int)def->part_count; j++) {
+ struct coll *coll = def->parts[j].coll;
+ const char *coll_str =
+ coll != NULL ? coll->name : "";
+ if (strcmp(coll_str, "BINARY") == 0)
+ coll_str = "B";
+ const char *sort_order = "";
+ if (def->parts[j].sort_order ==
+ SORT_ORDER_DESC) {
+ sort_order = "-";
+ }
sqlite3XPrintf(&x, ",%s%s",
- pKeyInfo->
- aSortOrder[j] ? "-" : "",
- zColl);
+ sort_order,
+ coll_str);
}
sqlite3StrAccumAppend(&x, ")", 1);
}
@@ -3506,7 +3505,7 @@ sqlite3VdbeSerialGet(const unsigned char *buf, /* Buffer to deserialize from */
/*
* This routine is used to allocate sufficient space for an UnpackedRecord
* structure large enough to be used with sqlite3VdbeRecordUnpack() if
- * the first argument is a pointer to KeyInfo structure pKeyInfo.
+ * the first argument is a pointer to key_def structure.
*
* The space is either allocated using sqlite3DbMallocRaw() or from within
* the unaligned buffer passed via the second and third arguments (presumably
@@ -3518,20 +3517,19 @@ sqlite3VdbeSerialGet(const unsigned char *buf, /* Buffer to deserialize from */
* If an OOM error occurs, NULL is returned.
*/
UnpackedRecord *
-sqlite3VdbeAllocUnpackedRecord(KeyInfo * pKeyInfo)
+sqlite3VdbeAllocUnpackedRecord(struct sqlite3 *db, struct key_def *key_def)
{
UnpackedRecord *p; /* Unpacked record to return */
int nByte; /* Number of bytes required for *p */
nByte =
- ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem) * (pKeyInfo->nField +
+ ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem) * (key_def->part_count +
1);
- p = (UnpackedRecord *) sqlite3DbMallocRaw(pKeyInfo->db, nByte);
+ p = (UnpackedRecord *) sqlite3DbMallocRaw(db, nByte);
if (!p)
return 0;
p->aMem = (Mem *) & ((char *)p)[ROUND8(sizeof(UnpackedRecord))];
- assert(pKeyInfo->aSortOrder != 0);
- p->pKeyInfo = pKeyInfo;
- p->nField = pKeyInfo->nField + 1;
+ p->key_def = key_def;
+ p->nField = key_def->part_count + 1;
return p;
}
@@ -3560,7 +3558,8 @@ sql_vdbe_mem_alloc_region(Mem *vdbe_mem, uint32_t size)
* Return false if there is a disagreement.
*/
static int
-vdbeRecordCompareDebug(int nKey1, const void *pKey1, /* Left key */
+vdbeRecordCompareDebug(struct sqlite3 *db,
+ int nKey1, const void *pKey1, /* Left key */
const UnpackedRecord * pPKey2, /* Right key */
int desiredResult) /* Correct answer */
{
@@ -3570,13 +3569,11 @@ vdbeRecordCompareDebug(int nKey1, const void *pKey1, /* Left key */
int i = 0;
int rc = 0;
const unsigned char *aKey1 = (const unsigned char *)pKey1;
- KeyInfo *pKeyInfo;
+ struct key_def *key_def;
Mem mem1;
- pKeyInfo = pPKey2->pKeyInfo;
- if (pKeyInfo->db == 0)
- return 1;
- mem1.db = pKeyInfo->db;
+ key_def = pPKey2->key_def;
+ mem1.db = db;
/* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */
VVA_ONLY(mem1.szMalloc = 0;
)
@@ -3594,10 +3591,7 @@ vdbeRecordCompareDebug(int nKey1, const void *pKey1, /* Left key */
if (szHdr1 > 98307)
return SQLITE_CORRUPT;
d1 = szHdr1;
- assert(pKeyInfo->nField + pKeyInfo->nXField >= pPKey2->nField
- || CORRUPT_DB);
- assert(pKeyInfo->aSortOrder != 0);
- assert(pKeyInfo->nField > 0);
+ assert(key_def->part_count > 0);
assert(idx1 <= szHdr1 || CORRUPT_DB);
do {
u32 serial_type1;
@@ -3624,10 +3618,10 @@ vdbeRecordCompareDebug(int nKey1, const void *pKey1, /* Left key */
/* Do the comparison
*/
rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i],
- pKeyInfo->aColl[i]);
+ key_def->parts[i].coll);
if (rc != 0) {
assert(mem1.szMalloc == 0); /* See comment below */
- if (pKeyInfo->aSortOrder[i]) {
+ if (key_def->parts[i].sort_order != SORT_ORDER_ASC) {
rc = -rc; /* Invert the result for DESC sort order. */
}
goto debugCompareEnd;
@@ -3656,7 +3650,7 @@ vdbeRecordCompareDebug(int nKey1, const void *pKey1, /* Left key */
return 1;
if (CORRUPT_DB)
return 1;
- if (pKeyInfo->db->mallocFailed)
+ if (db->mallocFailed)
return 1;
return 0;
}
@@ -3932,12 +3926,13 @@ vdbeRecordDecodeInt(u32 serial_type, const u8 * aKey)
* If database corruption is discovered, set pPKey2->errCode to
* SQLITE_CORRUPT and return 0. If an OOM error is encountered,
* pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
- * malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
+ * malloc-failed flag set on database handle.
*/
int
-sqlite3VdbeRecordCompareWithSkip(int nKey1, const void *pKey1, /* Left key */
+sqlite3VdbeRecordCompareWithSkip(struct sqlite3 *db,
+ int nKey1, const void *pKey1, /* Left key */
UnpackedRecord * pPKey2, /* Right key */
- int bSkip) /* If true, skip the first field */
+ bool bSkip) /* If true, skip the first field */
{
u32 d1; /* Offset into aKey[] of next data element */
int i; /* Index of next field to compare */
@@ -3945,7 +3940,7 @@ sqlite3VdbeRecordCompareWithSkip(int nKey1, const void *pKey1, /* Left key */
u32 idx1; /* Offset of first type in header */
int rc = 0; /* Return value */
Mem *pRhs = pPKey2->aMem; /* Next field of pPKey2 to compare */
- KeyInfo *pKeyInfo = pPKey2->pKeyInfo;
+ struct key_def *key_def = pPKey2->key_def;
const unsigned char *aKey1 = (const unsigned char *)pKey1;
Mem mem1;
@@ -3972,10 +3967,7 @@ sqlite3VdbeRecordCompareWithSkip(int nKey1, const void *pKey1, /* Left key */
VVA_ONLY(mem1.szMalloc = 0;
) /* Only needed by assert() statements */
- assert(pPKey2->pKeyInfo->nField + pPKey2->pKeyInfo->nXField >=
- pPKey2->nField || CORRUPT_DB);
- assert(pPKey2->pKeyInfo->aSortOrder != 0);
- assert(pPKey2->pKeyInfo->nField > 0);
+ assert(pPKey2->key_def->part_count > 0);
assert(idx1 <= szHdr1 || CORRUPT_DB);
do {
u32 serial_type;
@@ -4050,13 +4042,14 @@ sqlite3VdbeRecordCompareWithSkip(int nKey1, const void *pKey1, /* Left key */
pPKey2->errCode =
(u8) SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
- } else if (pKeyInfo->aColl[i]) {
- mem1.db = pKeyInfo->db;
+ } else if (key_def->parts[i].coll !=NULL) {
+ mem1.db = db;
mem1.flags = MEM_Str;
mem1.z = (char *)&aKey1[d1];
+ struct coll* coll;
+ coll = key_def->parts[i].coll;
rc = vdbeCompareMemString(&mem1, pRhs,
- pKeyInfo->
- aColl[i],
+ coll,
&pPKey2->
errCode);
} else {
@@ -4106,11 +4099,10 @@ sqlite3VdbeRecordCompareWithSkip(int nKey1, const void *pKey1, /* Left key */
}
if (rc != 0) {
- if (pKeyInfo->aSortOrder[i]) {
+ if (key_def->parts[i].sort_order != SORT_ORDER_ASC)
rc = -rc;
- }
assert(vdbeRecordCompareDebug
- (nKey1, pKey1, pPKey2, rc));
+ (db, nKey1, pKey1, pPKey2, rc));
assert(mem1.szMalloc == 0); /* See comment below */
return rc;
}
@@ -4133,18 +4125,19 @@ sqlite3VdbeRecordCompareWithSkip(int nKey1, const void *pKey1, /* Left key */
* value.
*/
assert(CORRUPT_DB
- || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2,
+ || vdbeRecordCompareDebug(db, nKey1, pKey1, pPKey2,
pPKey2->default_rc)
- || pKeyInfo->db->mallocFailed);
+ || db->mallocFailed);
pPKey2->eqSeen = 1;
return pPKey2->default_rc;
}
int
-sqlite3VdbeRecordCompare(int nKey1, const void *pKey1, /* Left key */
- UnpackedRecord * pPKey2) /* Right key */
+sqlite3VdbeRecordCompare(struct sqlite3 *db,
+ int key_count, const void *key1, /* Left key */
+ UnpackedRecord *key2) /* Right key */
{
- return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0);
+ return sqlite3VdbeRecordCompareWithSkip(db, key_count, key1, key2, false);
}
/*
@@ -4159,27 +4152,19 @@ sqlite3VdbeFindCompare(UnpackedRecord * p)
return sqlite3VdbeRecordCompareMsgpack;
}
-/*
- * Compare the key of the index entry that cursor pC is pointing to against
- * the key string in pUnpacked. Write into *pRes a number
- * that is negative, zero, or positive if pC is less than, equal to,
- * or greater than pUnpacked. Return SQLITE_OK on success.
- */
int
-sqlite3VdbeIdxKeyCompare(sqlite3 * db, /* Database connection */
- VdbeCursor * pC, /* The cursor to compare against */
- UnpackedRecord * pUnpacked, /* Unpacked version of key */
- int *res) /* Write the comparison result here */
-{
- (void)db;
- BtCursor *pCur;
-
- assert(pC->eCurType == CURTYPE_TARANTOOL);
- pCur = pC->uc.pCursor;
- assert(sqlite3CursorIsValid(pCur));
- if (pCur->curFlags & BTCF_TaCursor ||
- pCur->curFlags & BTCF_TEphemCursor) {
- return tarantoolSqlite3IdxKeyCompare(pCur, pUnpacked, res);
+sqlite3VdbeIdxKeyCompare(struct VdbeCursor *vdbe_cursor,
+ struct UnpackedRecord *unpacked,
+ int *res)
+{
+ struct BtCursor *cursor;
+
+ assert(vdbe_cursor->eCurType == CURTYPE_TARANTOOL);
+ cursor = vdbe_cursor->uc.pCursor;
+ assert(sqlite3CursorIsValid(cursor));
+ if (cursor->curFlags & BTCF_TaCursor ||
+ cursor->curFlags & BTCF_TEphemCursor) {
+ return tarantoolSqlite3IdxKeyCompare(cursor, unpacked, res);
}
unreachable();
return SQLITE_OK;
@@ -4301,68 +4286,6 @@ vdbeFreeUnpacked(sqlite3 * db, UnpackedRecord * p)
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-/*
- * Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call,
- * then cursor passed as the second argument should point to the row about
- * to be update or deleted. If the application calls sqlite3_preupdate_old(),
- * the required value will be read from the row the cursor points to.
- */
-void
-sqlite3VdbePreUpdateHook(Vdbe * v, /* Vdbe pre-update hook is invoked by */
- VdbeCursor * pCsr, /* Cursor to grab old.* values from */
- int op, /* SQLITE_INSERT, UPDATE or DELETE */
- Table * pTab, /* Modified table */
- i64 iKey1, /* Initial key value */
- int iReg) /* Register for new.* record */
-{
- sqlite3 *db = v->db;
- i64 iKey2;
- PreUpdate preupdate;
- const char *zTbl = pTab->zName;
- static const u8 fakeSortOrder = 0;
-
- assert(db->pPreUpdate == 0);
- memset(&preupdate, 0, sizeof(PreUpdate));
- if (op == SQLITE_UPDATE) {
- iKey2 = v->aMem[iReg].u.i;
- } else {
- iKey2 = iKey1;
- }
-
- assert(pCsr->nField == pTab->nCol
- || (pCsr->nField == pTab->nCol + 1 && op == SQLITE_DELETE
- && iReg == -1)
- );
-
- preupdate.v = v;
- preupdate.pCsr = pCsr;
- preupdate.op = op;
- preupdate.iNewReg = iReg;
- preupdate.keyinfo.db = db;
- preupdate.keyinfo.nField = pTab->nCol;
- preupdate.keyinfo.aSortOrder = (u8 *) & fakeSortOrder;
- preupdate.iKey1 = iKey1;
- preupdate.iKey2 = iKey2;
- preupdate.pTab = pTab;
-
- db->pPreUpdate = &preupdate;
- db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zTbl, iKey1,
- iKey2);
- db->pPreUpdate = 0;
- sqlite3DbFree(db, preupdate.aRecord);
- vdbeFreeUnpacked(db, preupdate.pUnpacked);
- vdbeFreeUnpacked(db, preupdate.pNewUnpacked);
- if (preupdate.aNew) {
- int i;
- for (i = 0; i < pCsr->nField; i++) {
- sqlite3VdbeMemRelease(&preupdate.aNew[i]);
- }
- sqlite3DbFree(db, preupdate.aNew);
- }
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
i64
sqlite3VdbeMsgpackRecordLen(Mem * pRec, u32 n)
{
@@ -4435,11 +4358,11 @@ sqlite3VdbeMsgpackRecordPut(u8 * pBuf, Mem * pRec, u32 n)
}
int
-sqlite3VdbeCompareMsgpack(const char **pKey1,
- UnpackedRecord * pUnpacked, int iKey2)
+sqlite3VdbeCompareMsgpack(const char **key1,
+ struct UnpackedRecord *unpacked, int key2_idx)
{
- const char *aKey1 = *pKey1;
- Mem *pKey2 = pUnpacked->aMem + iKey2;
+ const char *aKey1 = *key1;
+ Mem *pKey2 = unpacked->aMem + key2_idx;
Mem mem1;
int rc = 0;
switch (mp_typeof(*aKey1)) {
@@ -4508,17 +4431,17 @@ sqlite3VdbeCompareMsgpack(const char **pKey1,
}
case MP_STR:{
if (pKey2->flags & MEM_Str) {
- KeyInfo *pKeyInfo = pUnpacked->pKeyInfo;
+ struct key_def *key_def = unpacked->key_def;
mem1.n = mp_decode_strl(&aKey1);
mem1.z = (char *)aKey1;
aKey1 += mem1.n;
- if (pKeyInfo->aColl[iKey2]) {
- mem1.db = pKeyInfo->db;
+ struct coll *coll;
+ coll = key_def->parts[key2_idx].coll;
+ if (coll != NULL) {
mem1.flags = MEM_Str;
rc = vdbeCompareMemString(&mem1, pKey2,
- pKeyInfo->
- aColl[iKey2],
- &pUnpacked->
+ coll,
+ &unpacked->
errCode);
} else {
goto do_bin_cmp;
@@ -4563,34 +4486,32 @@ sqlite3VdbeCompareMsgpack(const char **pKey1,
goto do_blob;
}
}
- *pKey1 = aKey1;
+ *key1 = aKey1;
return rc;
}
int
-sqlite3VdbeRecordCompareMsgpack(int nKey1, const void *pKey1, /* Left key */
- UnpackedRecord * pPKey2) /* Right key */
+sqlite3VdbeRecordCompareMsgpack(const void *key1,
+ struct UnpackedRecord *key2)
{
- (void)nKey1; /* assume valid data */
-
- int rc = 0; /* Return value */
- const char *aKey1 = (const char *)pKey1;
- u32 i, n = mp_decode_array(&aKey1);
+ int rc = 0;
+ u32 i, n = mp_decode_array((const char**)&key1);
- n = MIN(n, pPKey2->nField);
+ n = MIN(n, key2->nField);
for (i = 0; i != n; i++) {
- rc = sqlite3VdbeCompareMsgpack(&aKey1, pPKey2, i);
+ rc = sqlite3VdbeCompareMsgpack((const char**)&key1, key2, i);
if (rc != 0) {
- if (pPKey2->pKeyInfo->aSortOrder[i]) {
+ if (key2->key_def->parts[i].sort_order !=
+ SORT_ORDER_ASC) {
rc = -rc;
}
return rc;
}
}
- pPKey2->eqSeen = 1;
- return pPKey2->default_rc;
+ key2->eqSeen = 1;
+ return key2->default_rc;
}
u32
@@ -4669,21 +4590,18 @@ sqlite3VdbeMsgpackGet(const unsigned char *buf, /* Buffer to deserialize from */
}
void
-sqlite3VdbeRecordUnpackMsgpack(KeyInfo * pKeyInfo, /* Information about the record format */
- int nKey, /* Size of the binary record */
+sqlite3VdbeRecordUnpackMsgpack(struct key_def *key_def, /* Information about the record format */
const void *pKey, /* The binary record */
UnpackedRecord * p) /* Populate this structure before returning. */
{
uint32_t n;
const char *zParse = pKey;
- (void)nKey;
Mem *pMem = p->aMem;
n = mp_decode_array(&zParse);
- n = p->nField = MIN(n, pKeyInfo->nField);
+ n = p->nField = MIN(n, key_def->part_count);
p->default_rc = 0;
+ p->key_def = key_def;
while (n--) {
- pMem->db = pKeyInfo->db;
- /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
pMem->szMalloc = 0;
pMem->z = 0;
u32 sz = sqlite3VdbeMsgpackGet((u8 *) zParse, pMem);
diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c
index 9dd254f..3c23991 100644
--- a/src/box/sql/vdbemem.c
+++ b/src/box/sql/vdbemem.c
@@ -1089,14 +1089,13 @@ valueNew(sqlite3 * db, struct ValueNewStat4Ctx *p)
int i; /* Counter variable */
int nCol = index_column_count(pIdx);
- nByte =
- sizeof(Mem) * nCol + ROUND8(sizeof(UnpackedRecord));
+ nByte = sizeof(Mem) * nCol +
+ ROUND8(sizeof(UnpackedRecord));
pRec =
(UnpackedRecord *) sqlite3DbMallocZero(db, nByte);
- if (pRec) {
- pRec->pKeyInfo =
- sqlite3KeyInfoOfIndex(p->pParse, db, pIdx);
- if (pRec->pKeyInfo) {
+ if (pRec != NULL) {
+ pRec->key_def = sql_index_key_def(pIdx, true);
+ if (pRec->key_def != NULL) {
pRec->aMem =
(Mem *) ((u8 *) pRec +
ROUND8(sizeof
@@ -1655,13 +1654,12 @@ sqlite3Stat4ProbeFree(UnpackedRecord * pRec)
{
if (pRec) {
int i;
- int nCol = pRec->pKeyInfo->nField;
+ int nCol = pRec->key_def->part_count;
Mem *aMem = pRec->aMem;
sqlite3 *db = aMem[0].db;
for (i = 0; i < nCol; i++) {
sqlite3VdbeMemRelease(&aMem[i]);
}
- sqlite3KeyInfoUnref(pRec->pKeyInfo);
sqlite3DbFree(db, pRec);
}
}
diff --git a/src/box/sql/vdbesort.c b/src/box/sql/vdbesort.c
index be3cc4c..7c45553 100644
--- a/src/box/sql/vdbesort.c
+++ b/src/box/sql/vdbesort.c
@@ -312,8 +312,8 @@ struct MergeEngine {
* after the thread has finished are not dire. So we don't worry about
* memory barriers and such here.
*/
-typedef int (*SorterCompare) (SortSubtask *, int *, const void *, int,
- const void *, int);
+typedef int (*SorterCompare) (SortSubtask *, bool *, const void *,
+ const void *);
struct SortSubtask {
SQLiteThread *pThread; /* Background thread, if any */
int bDone; /* Set if thread is finished but not joined */
@@ -343,7 +343,7 @@ struct VdbeSorter {
PmaReader *pReader; /* Readr data from here after Rewind() */
MergeEngine *pMerger; /* Or here, if bUseThreads==0 */
sqlite3 *db; /* Database connection */
- KeyInfo *pKeyInfo; /* How to compare records */
+ struct key_def *key_def;
UnpackedRecord *pUnpacked; /* Used by VdbeSorterCompare() */
SorterList list; /* List of in-memory records */
int iMemory; /* Offset of free space in list.aMemory */
@@ -794,10 +794,10 @@ vdbePmaReaderInit(SortSubtask * pTask, /* Task context */
return rc;
}
-/*
- * Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2,
- * size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences
- * used by the comparison. Return the result of the comparison.
+/**
+ * Compare key1 with key2. Use (pTask->key_def) for the collation
+ * sequences used by the comparison. Return the result of the
+ * comparison.
*
* If IN/OUT parameter *pbKey2Cached is true when this function is called,
* it is assumed that (pTask->pUnpacked) contains the unpacked version
@@ -806,27 +806,31 @@ vdbePmaReaderInit(SortSubtask * pTask, /* Task context */
*
* If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set
* to SQLITE_NOMEM.
+ *
+ * @param task Subtask context (for key_def).
+ * @param key2_cached True if pTask->pUnpacked is key2.
+ * @param key1 Left side of comparison.
+ * @param key2 Right side of comparison.
+ *
+ * @retval +1 if key1 > key2, -1 otherwise.
*/
static int
-vdbeSorterCompare(SortSubtask * pTask, /* Subtask context (for pKeyInfo) */
- int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
- const void *pKey1, int nKey1, /* Left side of comparison */
- const void *pKey2, int nKey2 /* Right side of comparison */
- )
+vdbeSorterCompare(struct SortSubtask *task, bool *key2_cached,
+ const void *key1, const void *key2)
{
- UnpackedRecord *r2 = pTask->pUnpacked;
- if (!*pbKey2Cached) {
- sqlite3VdbeRecordUnpackMsgpack(pTask->pSorter->pKeyInfo, nKey2,
- pKey2, r2);
- *pbKey2Cached = 1;
+ struct UnpackedRecord *r2 = task->pUnpacked;
+ if (!*key2_cached) {
+ sqlite3VdbeRecordUnpackMsgpack(task->pSorter->key_def,
+ key2, r2);
+ *key2_cached = 1;
}
- return sqlite3VdbeRecordCompareMsgpack(nKey1, pKey1, r2);
+ return sqlite3VdbeRecordCompareMsgpack(key1, r2);
}
/*
* Initialize the temporary index cursor just opened as a sorter cursor.
*
- * Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField)
+ * Usually, the sorter module uses the value of (pCsr->key_def->part_count)
* to determine the number of fields that should be compared from the
* records being sorted. However, if the value passed as argument nField
* is non-zero and the sorter is able to guarantee a stable sort, nField
@@ -844,16 +848,12 @@ vdbeSorterCompare(SortSubtask * pTask, /* Subtask context (for pKeyInfo) */
*/
int
sqlite3VdbeSorterInit(sqlite3 * db, /* Database connection (for malloc()) */
- int nField, /* Number of key fields in each record */
VdbeCursor * pCsr /* Cursor that holds the new sorter */
)
{
int pgsz; /* Page size of main database */
int i; /* Used to iterate through aTask[] */
VdbeSorter *pSorter; /* The new sorter */
- KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */
- int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */
- int sz; /* Size of pSorter in bytes */
int rc = SQLITE_OK;
#if SQLITE_MAX_WORKER_THREADS==0
#define nWorker 0
@@ -875,25 +875,15 @@ sqlite3VdbeSorterInit(sqlite3 * db, /* Database connection (for malloc()) */
}
#endif
- assert(pCsr->pKeyInfo);
+ assert(pCsr->key_def != NULL);
assert(pCsr->eCurType == CURTYPE_SORTER);
- szKeyInfo =
- sizeof(KeyInfo) + (pCsr->pKeyInfo->nField - 1) * sizeof(struct coll *);
- sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
- pSorter = (VdbeSorter *) sqlite3DbMallocZero(db, sz + szKeyInfo);
+ pSorter = (VdbeSorter *) sqlite3DbMallocZero(db, sizeof(VdbeSorter));
pCsr->uc.pSorter = pSorter;
if (pSorter == 0) {
rc = SQLITE_NOMEM_BKPT;
} else {
- pSorter->pKeyInfo = pKeyInfo =
- (KeyInfo *) ((u8 *) pSorter + sz);
- memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
- pKeyInfo->db = 0;
- if (nField && nWorker == 0) {
- pKeyInfo->nXField += (pKeyInfo->nField - nField);
- pKeyInfo->nField = nField;
- }
+ pSorter->key_def = pCsr->key_def;
pSorter->pgsz = pgsz = 1024;
pSorter->nTask = nWorker + 1;
pSorter->iPrev = (u8) (nWorker - 1);
@@ -929,8 +919,8 @@ sqlite3VdbeSorterInit(sqlite3 * db, /* Database connection (for malloc()) */
}
}
- if ((pKeyInfo->nField + pKeyInfo->nXField) < 13
- && (pKeyInfo->aColl[0] == NULL)) {
+ if (pCsr->key_def->part_count < 13
+ && (pCsr->key_def->parts[0].coll == NULL)) {
pSorter->typeMask =
SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
}
@@ -1280,10 +1270,11 @@ vdbeSortAllocUnpacked(SortSubtask * pTask)
{
if (pTask->pUnpacked == 0) {
pTask->pUnpacked =
- sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo);
+ sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->db,
+ pTask->pSorter->key_def);
if (pTask->pUnpacked == 0)
return SQLITE_NOMEM_BKPT;
- pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
+ pTask->pUnpacked->nField = pTask->pSorter->key_def->part_count;
pTask->pUnpacked->errCode = 0;
}
return SQLITE_OK;
@@ -1300,14 +1291,14 @@ vdbeSorterMerge(SortSubtask * pTask, /* Calling thread context */
{
SorterRecord *pFinal = 0;
SorterRecord **pp = &pFinal;
- int bCached = 0;
+ bool bCached = false;
assert(p1 != 0 && p2 != 0);
for (;;) {
int res;
res =
- pTask->xCompare(pTask, &bCached, SRVAL(p1), p1->nVal,
- SRVAL(p2), p2->nVal);
+ pTask->xCompare(pTask, &bCached, SRVAL(p1),
+ SRVAL(p2));
if (res <= 0) {
*pp = p1;
@@ -1599,7 +1590,7 @@ vdbeMergeEngineStep(MergeEngine * pMerger, /* The merge engine to advance to the
int i; /* Index of aTree[] to recalculate */
PmaReader *pReadr1; /* First PmaReader to compare */
PmaReader *pReadr2; /* Second PmaReader to compare */
- int bCached = 0;
+ bool bCached = false;
/* Find the first two PmaReaders to compare. The one that was just
* advanced (iPrev) and the one next to it in the array.
@@ -1617,9 +1608,7 @@ vdbeMergeEngineStep(MergeEngine * pMerger, /* The merge engine to advance to the
} else {
iRes = pTask->xCompare(pTask, &bCached,
pReadr1->aKey,
- pReadr1->nKey,
- pReadr2->aKey,
- pReadr2->nKey);
+ pReadr2->aKey);
}
/* If pReadr1 contained the smaller value, set aTree[i] to its index.
@@ -2075,12 +2064,11 @@ vdbeMergeEngineCompare(MergeEngine * pMerger, /* Merge engine containing PmaRead
iRes = i1;
} else {
SortSubtask *pTask = pMerger->pTask;
- int bCached = 0;
+ bool cached = false;
int res;
assert(pTask->pUnpacked != 0); /* from vdbeSortSubtaskMain() */
res =
- pTask->xCompare(pTask, &bCached, p1->aKey, p1->nKey,
- p2->aKey, p2->nKey);
+ pTask->xCompare(pTask, &cached, p1->aKey, p2->aKey);
if (res <= 0) {
iRes = i1;
} else {
@@ -2824,7 +2812,6 @@ sqlite3VdbeSorterCompare(const VdbeCursor * pCsr, /* Sorter cursor */
{
VdbeSorter *pSorter;
UnpackedRecord *r2;
- KeyInfo *pKeyInfo;
int i;
void *pKey;
int nKey; /* Sorter key to compare pVal with */
@@ -2832,10 +2819,9 @@ sqlite3VdbeSorterCompare(const VdbeCursor * pCsr, /* Sorter cursor */
assert(pCsr->eCurType == CURTYPE_SORTER);
pSorter = pCsr->uc.pSorter;
r2 = pSorter->pUnpacked;
- pKeyInfo = pCsr->pKeyInfo;
if (r2 == 0) {
r2 = pSorter->pUnpacked =
- sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
+ sqlite3VdbeAllocUnpackedRecord(pSorter->db, pCsr->key_def);
if (r2 == 0)
return SQLITE_NOMEM_BKPT;
r2->nField = nKeyCol;
@@ -2843,7 +2829,7 @@ sqlite3VdbeSorterCompare(const VdbeCursor * pCsr, /* Sorter cursor */
assert(r2->nField == nKeyCol);
pKey = vdbeSorterRowkey(pSorter, &nKey);
- sqlite3VdbeRecordUnpackMsgpack(pKeyInfo, nKey, pKey, r2);
+ sqlite3VdbeRecordUnpackMsgpack(pCsr->key_def, pKey, r2);
for (i = 0; i < nKeyCol; i++) {
if (r2->aMem[i].flags & MEM_Null) {
*pRes = -1;
@@ -2851,6 +2837,6 @@ sqlite3VdbeSorterCompare(const VdbeCursor * pCsr, /* Sorter cursor */
}
}
- *pRes = sqlite3VdbeRecordCompareMsgpack(pVal->n, pVal->z, r2);
+ *pRes = sqlite3VdbeRecordCompareMsgpack(pVal->z, r2);
return SQLITE_OK;
}
diff --git a/src/box/sql/where.c b/src/box/sql/where.c
index bad964a..cde3815 100644
--- a/src/box/sql/where.c
+++ b/src/box/sql/where.c
@@ -812,7 +812,7 @@ constructAutomaticIndex(Parse * pParse, /* The parsing context */
assert(pLevel->iIdxCur >= 0);
pLevel->iIdxCur = pParse->nTab++;
sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol + 1);
- sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
+ sql_vdbe_set_p4_key_def(pParse, pIdx);
VdbeComment((v, "for %s", pTable->zName));
/* Fill the automatic index with content */
@@ -971,9 +971,7 @@ whereKeyStats(Parse * pParse, /* Database connection */
}
pRec->nField = n;
- res =
- sqlite3VdbeRecordCompareMsgpack(aSample[iSamp].n,
- aSample[iSamp].p, pRec);
+ res = sqlite3VdbeRecordCompareMsgpack(aSample[iSamp].p, pRec);
if (res < 0) {
iLower =
aSample[iSamp].anLt[n - 1] + aSample[iSamp].anEq[n -
@@ -1002,8 +1000,7 @@ whereKeyStats(Parse * pParse, /* Database connection */
assert(iCol == nField - 1);
pRec->nField = nField;
assert(0 ==
- sqlite3VdbeRecordCompareMsgpack(aSample[i].n,
- aSample[i].p,
+ sqlite3VdbeRecordCompareMsgpack(aSample[i].p,
pRec)
|| pParse->db->mallocFailed);
} else {
@@ -1014,8 +1011,7 @@ whereKeyStats(Parse * pParse, /* Database connection */
assert(i <= pIdx->nSample && i >= 0);
pRec->nField = iCol + 1;
assert(i == pIdx->nSample
- || sqlite3VdbeRecordCompareMsgpack(aSample[i].n,
- aSample[i].p,
+ || sqlite3VdbeRecordCompareMsgpack(aSample[i].p,
pRec) > 0
|| pParse->db->mallocFailed);
@@ -1027,14 +1023,14 @@ whereKeyStats(Parse * pParse, /* Database connection */
if (iCol > 0) {
pRec->nField = iCol;
assert(sqlite3VdbeRecordCompareMsgpack
- (aSample[i].n, aSample[i].p, pRec) <= 0
+ (aSample[i].p, pRec) <= 0
|| pParse->db->mallocFailed);
}
if (i > 0) {
pRec->nField = nField;
assert(sqlite3VdbeRecordCompareMsgpack
- (aSample[i - 1].n, aSample[i - 1].p,
- pRec) < 0 || pParse->db->mallocFailed);
+ (aSample[i - 1].p, pRec) < 0 ||
+ pParse->db->mallocFailed);
}
}
}
@@ -3385,12 +3381,12 @@ wherePathSatisfiesOrderBy(WhereInfo * pWInfo, /* The WHERE clause */
*/
if (revSet) {
if ((rev ^ revIdx) !=
- pOrderBy->a[i].sortOrder)
+ pOrderBy->a[i].sort_order)
isMatch = 0;
} else {
rev =
revIdx ^ pOrderBy->a[i].
- sortOrder;
+ sort_order;
if (rev)
*pRevMask |=
MASKBIT(iLoop);
@@ -4571,7 +4567,7 @@ sqlite3WhereBegin(Parse * pParse, /* The parser context */
assert(iIndexCur >= 0);
if (op) {
emit_open_cursor(pParse, iIndexCur, pIx->tnum);
- sqlite3VdbeSetP4KeyInfo(pParse, pIx);
+ sql_vdbe_set_p4_key_def(pParse, pIx);
if ((pLoop->wsFlags & WHERE_CONSTRAINT) != 0
&& (pLoop->
wsFlags & (WHERE_COLUMN_RANGE |
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index b467bbe..878425c 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -1618,7 +1618,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo, /* Complete information about t
regRowset = pParse->nTab++;
sqlite3VdbeAddOp2(v, OP_OpenTEphemeral,
regRowset, nPkCol);
- sqlite3VdbeSetP4KeyInfo(pParse, pPk);
+ sql_vdbe_set_p4_key_def(pParse, pPk);
regPk = ++pParse->nMem;
}
iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn);
diff --git a/src/box/tuple.c b/src/box/tuple.c
index df2686e..7bcd9f8 100644
--- a/src/box/tuple.c
+++ b/src/box/tuple.c
@@ -474,3 +474,12 @@ tuple_str(const struct tuple *tuple)
return "<failed to format tuple>";
return buf;
}
+
+const char *
+mp_str(const char *data)
+{
+ char *buf = tt_static_buf();
+ if (mp_snprint(buf, TT_STATIC_BUF_LEN, data) < 0)
+ return "<failed to format message pack>";
+ return buf;
+}
diff --git a/src/box/tuple.h b/src/box/tuple.h
index 97b81cf..9a459d9 100644
--- a/src/box/tuple.h
+++ b/src/box/tuple.h
@@ -395,6 +395,15 @@ tuple_snprint(char *buf, int size, const struct tuple *tuple);
const char *
tuple_str(const struct tuple *tuple);
+/**
+ * Format msgpack into string using a static buffer.
+ * Useful for debugger. Example: [1, 2, "string"]
+ * @param msgpack to format
+ * @return formatted null-terminated string
+ */
+const char *
+mp_str(const char *data);
+
/**
* Get the format of the tuple.
* @param tuple Tuple.
More information about the Tarantool-patches
mailing list