From: Kirill Yukhin <kyukhin@tarantool.org> To: v.shpilevoy@tarantool.org Cc: tarantool-patches@freelists.org, Kirill Yukhin <kyukhin@tarantool.org> Subject: [tarantool-patches] [PATCH 2/2] sql: replace KeyInfo with key_def Date: Tue, 8 May 2018 10:56:08 +0300 [thread overview] Message-ID: <877b5a2f7886137cda487933b7de9b1774a88421.1525765048.git.kyukhin@tarantool.org> (raw) In-Reply-To: <cover.1525765048.git.kyukhin@tarantool.org> In-Reply-To: <cover.1525765048.git.kyukhin@tarantool.org> 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 prt of data dictionary intagration 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 --- src/box/sql.c | 19 ++- src/box/sql/analyze.c | 6 +- src/box/sql/build.c | 79 +++------ src/box/sql/delete.c | 6 +- src/box/sql/expr.c | 52 +++--- src/box/sql/fkey.c | 2 +- src/box/sql/insert.c | 12 +- src/box/sql/pragma.c | 4 +- src/box/sql/select.c | 381 ++++++++++++++++++------------------------ src/box/sql/sqliteInt.h | 50 ++---- src/box/sql/tarantoolInt.h | 5 +- src/box/sql/update.c | 6 +- src/box/sql/vdbe.c | 80 +++++---- src/box/sql/vdbe.h | 34 ++-- src/box/sql/vdbeInt.h | 13 +- src/box/sql/vdbeapi.c | 183 -------------------- src/box/sql/vdbeaux.c | 247 ++++++++++----------------- src/box/sql/vdbemem.c | 14 +- src/box/sql/vdbesort.c | 54 +++--- src/box/sql/where.c | 21 ++- src/box/sql/wherecode.c | 2 +- src/box/tuple.c | 9 + src/box/tuple.h | 9 + test/sql-tap/index1.test.lua | 2 + test/sql-tap/index4.test.lua | 1 + test/sql-tap/selectA.test.lua | 1 + 26 files changed, 496 insertions(+), 796 deletions(-) diff --git a/src/box/sql.c b/src/box/sql.c index 838fcf6..42372ea 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -371,7 +371,7 @@ int tarantoolSqlite3Count(BtCursor *pCur, i64 *pnEntry) * @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,11 +380,16 @@ 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) { + 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 no */, part /* filed no */, FIELD_TYPE_SCALAR, ON_CONFLICT_ACTION_NONE /* nullable_action */, - aColl /* coll */, + coll /* coll */, SORT_ORDER_ASC); } @@ -933,7 +938,8 @@ rename_fail: * Performs exactly as extract_key + sqlite3VdbeCompareMsgpack, * only faster. */ -int tarantoolSqlite3IdxKeyCompare(BtCursor *pCur, UnpackedRecord *pUnpacked, +int tarantoolSqlite3IdxKeyCompare(struct sqlite3 *db, + BtCursor *pCur, UnpackedRecord *pUnpacked, int *res) { assert(pCur->curFlags & BTCF_TaCursor); @@ -995,9 +1001,10 @@ int tarantoolSqlite3IdxKeyCompare(BtCursor *pCur, UnpackedRecord *pUnpacked, } } next_fieldno = fieldno + 1; - rc = sqlite3VdbeCompareMsgpack(&p, pUnpacked, i); + rc = sqlite3VdbeCompareMsgpack(db, &p, pUnpacked, i); if (rc != 0) { - if (pUnpacked->pKeyInfo->aSortOrder[i]) { + if (pUnpacked->key_def->parts[i].sort_order != + SORT_ORDER_ASC) { rc = -rc; } *res = rc; @@ -1011,7 +1018,7 @@ out: original_size = region_used(&fiber()->gc); key = tuple_extract_key(tuple, key_def, &key_size); if (key != NULL) { - rc = sqlite3VdbeRecordCompareMsgpack((int)key_size, key, + rc = sqlite3VdbeRecordCompareMsgpack(db, (int)key_size, key, pUnpacked); 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 ae662fb..f9b54ef 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -1094,6 +1094,18 @@ sql_column_collation(Table *table, uint32_t column) return space->format->fields[column].coll; } +struct key_def* +sql_index_key_def(struct Index *idx) +{ + uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(idx->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); + return key_def_dup(index->def->key_def); +} + /** * Return name of given column collation from index. * @@ -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); + assert(key_def != NULL && key_def->part_count >= column); + return key_def->parts[column].coll; } enum sort_order @@ -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; } /** @@ -1443,9 +1453,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) @@ -2632,7 +2640,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 +2650,14 @@ 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); /* 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); + assert(0); /* Open the table. Loop through all rows of the table, inserting index * records into the sorter. @@ -4194,46 +4201,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..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); 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 +400,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..e5405dd 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -2522,7 +2522,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 +2739,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 +2760,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); if (ExprHasProperty(pExpr, EP_xIsSelect)) { /* Case 1: expr IN (SELECT ...) @@ -2787,29 +2786,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); 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; } diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c index fb9a310..4b9d3ed 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 1a34f71..95a2610 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)); } @@ -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); sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, srcTab, nColumn+1, - 0, (char*)pKeyInfo, P4_KEYINFO); + 0, (char*)def, P4_KEYDEF); addrL = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_NextIdEphemeral, srcTab, 2, regTempId); @@ -1594,7 +1594,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)); } @@ -1908,10 +1908,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/pragma.c b/src/box/sql/pragma.c index 738c254..0f1c64d 100644 --- a/src/box/sql/pragma.c +++ b/src/box/sql/pragma.c @@ -646,8 +646,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 aff534d3..6729eef 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -562,12 +562,11 @@ 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 */ +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 +622,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 +641,13 @@ 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); + 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 +1191,51 @@ 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) -{ - 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++; - } - 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 +/** + * Given an expression list, generate a key_defd 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 + * 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 KeyInfo structure is appropriate for initializing a virtual + * then the key_info 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. + * 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 Parsing context. + * @param Expression list. + * @param No of leading parts to skip. + * + * @retval Allocated key_def, NULL in case of OOM. */ -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 */ +static struct key_def * +sql_expr_list_to_key_def(struct Parse *parse, + struct ExprList *list, + int start) { - 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++) { + struct key_def *def; + int expr_count = list->nExpr; + def = key_def_new(expr_count); + if (def != NULL) { + int i; + struct ExprList_item *item; + for (i = start, item = list->a + start; i < expr_count; + ++i, ++item) { bool unused; - pInfo->aColl[i - iStart] = - sql_expr_coll(pParse, pItem->pExpr, &unused); - pInfo->aSortOrder[i - iStart] = pItem->sortOrder; + struct coll *coll = sql_expr_coll(parse, item->pExpr, + &unused); + enum sort_order sort_order = item->sortOrder; + key_def_set_part(def, i-start, i-start, + FIELD_TYPE_SCALAR, + ON_CONFLICT_ACTION_ABORT, + coll, sort_order); } } - return pInfo; + + return def; } /* @@ -2118,54 +2058,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 + * with an ORDER BY clause. This function allocates and returns a key_def * structure suitable for implementing the ORDER BY. * - * Space to hold the KeyInfo structure is obtained from malloc. The calling + * Space to hold the key_def structure is obtained from malloc. The calling * function is responsible for ensuring that this structure is eventually * freed. + * + * @param Parsing context. + * @param Select struct to analyze. + * @param 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; + int ob_count = s->pOrderBy->nExpr; + struct key_def *key_def = key_def_new(ob_count + extra); + if (key_def != NULL) { + 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 (pTerm->flags & EP_Collate) { - coll = sql_expr_coll(pParse, pTerm, &is_found); + if (term->flags & EP_Collate) { + coll = sql_expr_coll(parse, term, &is_found); } else { coll = - multiSelectCollSeq(pParse, p, - pItem->u.x.iOrderByCol - 1, + multiSelectCollSeq(parse, s, + item->u.x.iOrderByCol - 1, &is_found); if (coll != NULL) { - pOrderBy->a[i].pExpr = - sqlite3ExprAddCollateString(pParse, pTerm, + order_by->a[i].pExpr = + sqlite3ExprAddCollateString(parse, term, coll->name); } else { - pOrderBy->a[i].pExpr = - sqlite3ExprAddCollateString(pParse, pTerm, + 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].sortOrder); } } - return pRet; + return key_def; } #ifndef SQLITE_OMIT_CTE @@ -2265,16 +2213,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) { @@ -2475,9 +2424,10 @@ 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; + 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; } @@ -2785,7 +2735,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 @@ -2793,26 +2743,28 @@ 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 */ + int nCol; + struct key_def *key_def; assert(p->pNext == 0); nCol = p->pEList->nExpr; - pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); - if (!pKeyInfo) { + 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 @@ -2823,13 +2775,12 @@ multiSelect(Parse * pParse, /* Parsing context */ } sqlite3VdbeChangeP2(v, addr, nCol); sqlite3VdbeChangeP4(v, addr, - (char *) - sqlite3KeyInfoRef(pKeyInfo), - P4_KEYINFO); + (char *)key_def_dup(key_def), + P4_KEYDEF); pLoop->addrOpenEphm[i] = -1; } } - sqlite3KeyInfoUnref(pKeyInfo); + free(key_def); } multi_select_end: @@ -2871,7 +2822,7 @@ sqlite3SelectWrongNumTermsError(Parse * pParse, Select * p) * 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 + * generated to suppress duplicates. def is used for comparing * keys. * * If the LIMIT found in p->iLimit is reached, jump immediately to @@ -2884,7 +2835,7 @@ generateOutputSubroutine(Parse * pParse, /* Parsing context */ 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 */ + struct key_def *def, /* For comparing with previous entry */ int iBreak) /* Jump here if we hit the LIMIT */ { Vdbe *v = pParse->pVdbe; @@ -2903,8 +2854,8 @@ generateOutputSubroutine(Parse * pParse, /* Parsing context */ addr2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev + 1, pIn->nSdst, - (char *)sqlite3KeyInfoRef(pKeyInfo), - P4_KEYINFO); + (char *)key_def_dup(def), + P4_KEYDEF); sqlite3VdbeAddOp3(v, OP_Jump, addr2 + 2, iContinue, addr2 + 2); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); @@ -3135,8 +3086,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 */ @@ -3145,7 +3098,8 @@ 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. */ + /* "Managed" code needs this. Ticket #3382. */ + assert(def_dup == NULL); db = pParse->db; v = pParse->pVdbe; assert(v != 0); /* Already thrown the error if VDBE alloc failed */ @@ -3190,7 +3144,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 @@ -3206,9 +3160,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. @@ -3216,27 +3170,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); } } } @@ -3311,7 +3268,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. @@ -3320,9 +3277,8 @@ 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); /* Generate a subroutine to run when the results from select A * are exhausted and only data in select B remains. @@ -3402,7 +3358,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); @@ -5135,12 +5091,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); } } } @@ -5611,23 +5568,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; @@ -5636,10 +5592,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")); } @@ -5660,12 +5616,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 { @@ -5806,7 +5762,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 */ @@ -5822,14 +5777,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 */ @@ -5867,7 +5820,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 { @@ -5979,8 +5932,8 @@ sqlite3Select(Parse * pParse, /* The parser context */ } sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr, - (char *)sqlite3KeyInfoRef(pKeyInfo), - P4_KEYINFO); + (char*) key_def_dup(def), + P4_KEYDEF); addr1 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addr1 + 1, 0, addr1 + 1); VdbeCoverage(v); @@ -6090,7 +6043,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 */ @@ -6100,7 +6053,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); @@ -6116,19 +6069,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); } /* 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); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index a811932..7d32556 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; @@ -2027,24 +2026,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. @@ -2059,7 +2040,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 @@ -2069,7 +2050,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. * @@ -2081,7 +2062,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 */ @@ -2690,12 +2672,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 { @@ -3529,11 +3511,18 @@ 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. + * + * @param idx pointer to `struct Index` object + * @retval pointer to `struct key_def` + */ +struct key_def* +sql_index_key_def(struct Index *idx); + /** * Return name of given column collation from index. * @@ -3926,13 +3915,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..af774fc 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 @@ -123,7 +123,8 @@ int tarantoolSqlite3EphemeralGetMaxId(BtCursor * pCur, uint32_t fieldno, * the key may span non-adjacent fields in a random order, * ex: [4]-[1]-[2] */ -int tarantoolSqlite3IdxKeyCompare(BtCursor * pCur, UnpackedRecord * pUnpacked, +int tarantoolSqlite3IdxKeyCompare(struct sqlite3 *db, + BtCursor * pCur, UnpackedRecord * pUnpacked, int *res); /** diff --git a/src/box/sql/update.c b/src/box/sql/update.c index f3bd0b7..d380b8c 100644 --- a/src/box/sql/update.c +++ b/src/box/sql/update.c @@ -358,12 +358,12 @@ 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); 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 013460f..7f82c3c 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -2243,35 +2243,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 { @@ -2279,18 +2280,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; } } @@ -3119,8 +3121,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. * @@ -3208,7 +3210,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); @@ -3223,8 +3225,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. */ @@ -3233,21 +3239,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; } @@ -3269,9 +3275,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; } @@ -3547,7 +3552,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) { @@ -3699,7 +3704,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 @@ -3712,11 +3717,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(db, pC->key_def, + pIn3->n, pIn3->z, pIdxKey); } pIdxKey->default_rc = 0; pIdxKey->opcode = pOp->opcode; @@ -4492,7 +4498,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]; @@ -4576,7 +4582,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); diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h index e244606..4bd48d5 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 @@ -226,7 +225,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 *); @@ -257,14 +265,20 @@ 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 *); +void sqlite3VdbeRecordUnpackMsgpack(struct sqlite3 *db, + struct key_def *key_def, + int key_count, const void * msgpack, + 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) (struct sqlite3 *db, int, 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 ab9147c..044df10 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 */ @@ -451,7 +452,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 */ @@ -527,7 +527,7 @@ void sqlite3VdbePreUpdateHook(Vdbe *, VdbeCursor *, int, const char *, Table *, #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 *); @@ -564,9 +564,10 @@ 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, +int sqlite3VdbeCompareMsgpack(struct sqlite3 *db, + const char **key1, + UnpackedRecord *pUnpacked, int iKey2); +int sqlite3VdbeRecordCompareMsgpack(struct sqlite3 *db, int nKey1, const void *pKey1, UnpackedRecord * pPKey2); u32 sqlite3VdbeMsgpackGet(const unsigned char *buf, Mem * pMem); diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c index 6e41859..c781fd4 100644 --- a/src/box/sql/vdbeapi.c +++ b/src/box/sql/vdbeapi.c @@ -1581,103 +1581,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 @@ -1698,92 +1601,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 b3998ea..c2352e7 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -948,11 +948,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: + free(p4); + break; #ifdef SQLITE_ENABLE_CURSOR_HINTS case P4_EXPR:{ sqlite3ExprDelete(db, (Expr *) p4); @@ -1140,20 +1138,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 @@ -1512,26 +1509,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); } @@ -3491,7 +3490,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 @@ -3503,20 +3502,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; } @@ -3545,7 +3543,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 */ { @@ -3555,13 +3554,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; ) @@ -3579,10 +3576,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; @@ -3609,10 +3603,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; @@ -3641,7 +3635,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; } @@ -3917,12 +3911,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 */ @@ -3930,7 +3925,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; @@ -3957,10 +3952,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; @@ -4035,13 +4027,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 { @@ -4091,11 +4084,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; } @@ -4118,18 +4110,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); } /* @@ -4164,7 +4157,7 @@ sqlite3VdbeIdxKeyCompare(sqlite3 * db, /* Database connection */ assert(sqlite3CursorIsValid(pCur)); if (pCur->curFlags & BTCF_TaCursor || pCur->curFlags & BTCF_TEphemCursor) { - return tarantoolSqlite3IdxKeyCompare(pCur, pUnpacked, res); + return tarantoolSqlite3IdxKeyCompare(db, pCur, pUnpacked, res); } unreachable(); return SQLITE_OK; @@ -4286,68 +4279,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) { @@ -4420,7 +4351,7 @@ sqlite3VdbeMsgpackRecordPut(u8 * pBuf, Mem * pRec, u32 n) } int -sqlite3VdbeCompareMsgpack(const char **pKey1, +sqlite3VdbeCompareMsgpack(struct sqlite3 *db, const char **pKey1, UnpackedRecord * pUnpacked, int iKey2) { const char *aKey1 = *pKey1; @@ -4493,16 +4424,17 @@ sqlite3VdbeCompareMsgpack(const char **pKey1, } case MP_STR:{ if (pKey2->flags & MEM_Str) { - KeyInfo *pKeyInfo = pUnpacked->pKeyInfo; + struct key_def *key_def = pUnpacked->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[iKey2].coll; + if (coll != NULL) { + mem1.db = db; mem1.flags = MEM_Str; rc = vdbeCompareMemString(&mem1, pKey2, - pKeyInfo-> - aColl[iKey2], + coll, &pUnpacked-> errCode); } else { @@ -4553,29 +4485,30 @@ sqlite3VdbeCompareMsgpack(const char **pKey1, } int -sqlite3VdbeRecordCompareMsgpack(int nKey1, const void *pKey1, /* Left key */ - UnpackedRecord * pPKey2) /* Right key */ +sqlite3VdbeRecordCompareMsgpack(struct sqlite3 *db, + int key_count, const void *key1, /* Left key */ + UnpackedRecord * key2) /* Right key */ { - (void)nKey1; /* assume valid data */ + (void)key_count; /* assume valid data */ int rc = 0; /* Return value */ - const char *aKey1 = (const char *)pKey1; - u32 i, n = mp_decode_array(&aKey1); + 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(db, (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 @@ -4654,7 +4587,8 @@ sqlite3VdbeMsgpackGet(const unsigned char *buf, /* Buffer to deserialize from */ } void -sqlite3VdbeRecordUnpackMsgpack(KeyInfo * pKeyInfo, /* Information about the record format */ +sqlite3VdbeRecordUnpackMsgpack(struct sqlite3 *db, + struct key_def *key_def, /* Information about the record format */ int nKey, /* Size of the binary record */ const void *pKey, /* The binary record */ UnpackedRecord * p) /* Populate this structure before returning. */ @@ -4664,10 +4598,11 @@ sqlite3VdbeRecordUnpackMsgpack(KeyInfo * pKeyInfo, /* Information about the reco (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->db = db; /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */ pMem->szMalloc = 0; pMem->z = 0; diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c index 9dd254f..93f451d 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); + 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..9651fae 100644 --- a/src/box/sql/vdbesort.c +++ b/src/box/sql/vdbesort.c @@ -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 */ @@ -796,7 +796,7 @@ vdbePmaReaderInit(SortSubtask * pTask, /* Task context */ /* * Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, - * size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences + * size nKey2 bytes). 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, @@ -808,7 +808,7 @@ vdbePmaReaderInit(SortSubtask * pTask, /* Task context */ * to SQLITE_NOMEM. */ static int -vdbeSorterCompare(SortSubtask * pTask, /* Subtask context (for pKeyInfo) */ +vdbeSorterCompare(SortSubtask * pTask, /* Subtask context (for key_def) */ 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 */ @@ -816,17 +816,19 @@ vdbeSorterCompare(SortSubtask * pTask, /* Subtask context (for pKeyInfo) */ { UnpackedRecord *r2 = pTask->pUnpacked; if (!*pbKey2Cached) { - sqlite3VdbeRecordUnpackMsgpack(pTask->pSorter->pKeyInfo, nKey2, - pKey2, r2); + sqlite3VdbeRecordUnpackMsgpack(pTask->pSorter->db, + pTask->pSorter->key_def, + nKey2, pKey2, r2); *pbKey2Cached = 1; } - return sqlite3VdbeRecordCompareMsgpack(nKey1, pKey1, r2); + return sqlite3VdbeRecordCompareMsgpack(pTask->pSorter->db, + nKey1, pKey1, 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 +846,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 +873,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 +917,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 +1268,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; @@ -2824,7 +2813,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 +2820,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 +2830,8 @@ sqlite3VdbeSorterCompare(const VdbeCursor * pCsr, /* Sorter cursor */ assert(r2->nField == nKeyCol); pKey = vdbeSorterRowkey(pSorter, &nKey); - sqlite3VdbeRecordUnpackMsgpack(pKeyInfo, nKey, pKey, r2); + sqlite3VdbeRecordUnpackMsgpack(pSorter->db, pCsr->key_def, + nKey, pKey, r2); for (i = 0; i < nKeyCol; i++) { if (r2->aMem[i].flags & MEM_Null) { *pRes = -1; @@ -2851,6 +2839,6 @@ sqlite3VdbeSorterCompare(const VdbeCursor * pCsr, /* Sorter cursor */ } } - *pRes = sqlite3VdbeRecordCompareMsgpack(pVal->n, pVal->z, r2); + *pRes = sqlite3VdbeRecordCompareMsgpack(pSorter->db, pVal->n, pVal->z, r2); return SQLITE_OK; } diff --git a/src/box/sql/where.c b/src/box/sql/where.c index bad964a..fb40f76 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,9 @@ whereKeyStats(Parse * pParse, /* Database connection */ } pRec->nField = n; - res = - sqlite3VdbeRecordCompareMsgpack(aSample[iSamp].n, - aSample[iSamp].p, pRec); + res = sqlite3VdbeRecordCompareMsgpack(pParse->db, + aSample[iSamp].n, + aSample[iSamp].p, pRec); if (res < 0) { iLower = aSample[iSamp].anLt[n - 1] + aSample[iSamp].anEq[n - @@ -1002,7 +1002,8 @@ whereKeyStats(Parse * pParse, /* Database connection */ assert(iCol == nField - 1); pRec->nField = nField; assert(0 == - sqlite3VdbeRecordCompareMsgpack(aSample[i].n, + sqlite3VdbeRecordCompareMsgpack(pParse->db, + aSample[i].n, aSample[i].p, pRec) || pParse->db->mallocFailed); @@ -1014,7 +1015,8 @@ whereKeyStats(Parse * pParse, /* Database connection */ assert(i <= pIdx->nSample && i >= 0); pRec->nField = iCol + 1; assert(i == pIdx->nSample - || sqlite3VdbeRecordCompareMsgpack(aSample[i].n, + || sqlite3VdbeRecordCompareMsgpack(pParse->db, + aSample[i].n, aSample[i].p, pRec) > 0 || pParse->db->mallocFailed); @@ -1027,13 +1029,14 @@ whereKeyStats(Parse * pParse, /* Database connection */ if (iCol > 0) { pRec->nField = iCol; assert(sqlite3VdbeRecordCompareMsgpack - (aSample[i].n, aSample[i].p, pRec) <= 0 + (pParse->db, aSample[i].n, aSample[i].p, + pRec) <= 0 || pParse->db->mallocFailed); } if (i > 0) { pRec->nField = nField; assert(sqlite3VdbeRecordCompareMsgpack - (aSample[i - 1].n, aSample[i - 1].p, + (pParse->db, aSample[i - 1].n, aSample[i - 1].p, pRec) < 0 || pParse->db->mallocFailed); } } @@ -4571,7 +4574,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 9610f76..a295578 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. diff --git a/test/sql-tap/index1.test.lua b/test/sql-tap/index1.test.lua index 201838d..c0177c8 100755 --- a/test/sql-tap/index1.test.lua +++ b/test/sql-tap/index1.test.lua @@ -528,7 +528,9 @@ test:do_execsql_test( INSERT INTO t1 VALUES(2, 2,4); INSERT INTO t1 VALUES(3, 3,8); INSERT INTO t1 VALUES(4, 1,12); + pragma vdbe_debug=1; SELECT b FROM t1 WHERE a=1 ORDER BY b; + pragma vdbe_debug=0; ]], { -- <index-10.0> 2, 12 diff --git a/test/sql-tap/index4.test.lua b/test/sql-tap/index4.test.lua index 22e5066..85d3b3c 100755 --- a/test/sql-tap/index4.test.lua +++ b/test/sql-tap/index4.test.lua @@ -22,6 +22,7 @@ testprefix = "index4" test:do_execsql_test( 1.1, [[ + pragma vdbe_debug=1; CREATE TABLE t1(x primary key); BEGIN; INSERT INTO t1 VALUES(randomblob(102)); diff --git a/test/sql-tap/selectA.test.lua b/test/sql-tap/selectA.test.lua index fc482e9..fa3a025 100755 --- a/test/sql-tap/selectA.test.lua +++ b/test/sql-tap/selectA.test.lua @@ -1155,6 +1155,7 @@ test:do_execsql_test( test:do_execsql_test( "selectA-2.94", [[ + pragma vdbe_debug=1; SELECT lower((SELECT c FROM t1 UNION ALL SELECT z FROM t2 ORDER BY 1)); ]], { -- <selectA-2.94> -- 2.16.2
next prev parent reply other threads:[~2018-05-08 7:56 UTC|newest] Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-05-08 7:56 [tarantool-patches] [PATCH 0/2] sql: replace KeyInfo w/ key_def in SQL front-end Kirill Yukhin 2018-05-08 7:56 ` [tarantool-patches] [PATCH 1/2] sql: introduce sort order to key_part/key_part_def Kirill Yukhin 2018-05-08 16:02 ` [tarantool-patches] " Vladislav Shpilevoy 2018-05-10 13:01 ` Kirill Yukhin 2018-05-08 7:56 ` [tarantool-patches] [PATCH] sql: use collation pointers instead of names Kirill Yukhin 2018-04-17 18:06 ` [tarantool-patches] " Vladislav Shpilevoy 2018-04-18 5:42 ` Kirill Yukhin 2018-05-08 7:59 ` Kirill Yukhin 2018-05-08 7:56 ` Kirill Yukhin [this message] 2018-05-08 16:02 ` [tarantool-patches] Re: [PATCH 2/2] sql: replace KeyInfo with key_def Vladislav Shpilevoy 2018-05-10 12:59 ` Kirill Yukhin 2018-05-11 11:22 ` Vladislav Shpilevoy 2018-05-11 12:56 ` Kirill Yukhin 2018-05-11 19:05 ` Vladislav Shpilevoy 2018-05-14 11:40 ` Kirill Yukhin -- strict thread matches above, loose matches on Subject: below -- 2018-04-13 8:05 [tarantool-patches] [PATCH] sql: use collation pointers instead of names Kirill Yukhin 2018-04-16 13:43 ` [tarantool-patches] " Vladislav Shpilevoy
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=877b5a2f7886137cda487933b7de9b1774a88421.1525765048.git.kyukhin@tarantool.org \ --to=kyukhin@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [tarantool-patches] [PATCH 2/2] sql: replace KeyInfo with key_def' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox