diff --git a/src/box/sql/CMakeLists.txt b/src/box/sql/CMakeLists.txt index 9488ee717d75a2ecff5bbc68cb32c0ece4fb06a9..47f8e4ed313edc2952dea36c756627c9c0529402 100644 --- a/src/box/sql/CMakeLists.txt +++ b/src/box/sql/CMakeLists.txt @@ -17,6 +17,7 @@ add_definitions(-DSQLITE_OMIT_AUTHORIZATION=1) add_definitions(-DSQLITE_MAX_WORKER_THREADS=0) add_definitions(-DTHREADSAFE=0) add_definitions(-DSQLITE_DEFAULT_FOREIGN_KEYS=1) +add_definitions(-DSQLITE_OMIT_AUTOMATIC_INDEX) set(TEST_DEFINITIONS SQLITE_NO_SYNC=1 diff --git a/src/box/sql/opcodes.c b/src/box/sql/opcodes.c index b91784db3008db1bd956247b3c829302801627d7..e021a986b027a35f4abdfdcec26a963fb992e18d 100644 --- a/src/box/sql/opcodes.c +++ b/src/box/sql/opcodes.c @@ -126,8 +126,8 @@ const char *sqlite3OpcodeName(int i){ /* 112 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), /* 113 */ "NextId" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"), /* 114 */ "NextIdEphemeral" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"), - /* 115 */ "FCopy" OpHelp("reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)]"), - /* 116 */ "Real" OpHelp("r[P2]=P4"), + /* 115 */ "Real" OpHelp("r[P2]=P4"), + /* 116 */ "FCopy" OpHelp("reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)]"), /* 117 */ "NewRowid" OpHelp("r[P2]=rowid"), /* 118 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), /* 119 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), diff --git a/src/box/sql/opcodes.h b/src/box/sql/opcodes.h index 7c331c7880312f222ba996a712ceb80917039af4..a0883b09713055f5d09cdaa72528cc067ad16516 100644 --- a/src/box/sql/opcodes.h +++ b/src/box/sql/opcodes.h @@ -115,8 +115,8 @@ #define OP_Sequence 112 /* synopsis: r[P2]=cursor[P1].ctr++ */ #define OP_NextId 113 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */ #define OP_NextIdEphemeral 114 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */ -#define OP_FCopy 115 /* synopsis: reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)] */ -#define OP_Real 116 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_Real 115 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_FCopy 116 /* synopsis: reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)] */ #define OP_NewRowid 117 /* synopsis: r[P2]=rowid */ #define OP_Insert 118 /* synopsis: intkey=r[P3] data=r[P2] */ #define OP_InsertInt 119 /* synopsis: intkey=P3 data=r[P2] */ diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 26a986248cbf3bcdcff94b2fde4cc94b9c1432a8..d882c6e9cdd14d7b3c5f8842390d8f048f43ed6f 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -848,7 +848,15 @@ selectInnerLoop(Parse * pParse, /* The parser context */ * saving space and CPU cycles. */ ecelFlags |= (SQLITE_ECEL_OMITREF | SQLITE_ECEL_REF); - for (i = pSort->nOBSat; i < pSort->pOrderBy->nExpr; i++) { + /* This optimization is temporary disabled. It seems + * that it was possible to create table with n columns and + * insert tuple with m columns, where m < n. Contrary, Tarantool + * doesn't allow to alter the number of fields in tuple + * to be inserted. This may be uncommented by delaying the + * creation of table until insertion of first tuple, + * so that the number of fields in tuple can be precisely calculated. + */ + /*for (i = pSort->nOBSat; i < pSort->pOrderBy->nExpr; i++) { int j; if ((j = pSort->pOrderBy->a[i].u.x.iOrderByCol) > @@ -856,7 +864,7 @@ selectInnerLoop(Parse * pParse, /* The parser context */ pEList->a[j - 1].u.x.iOrderByCol = (u16) (i + 1 - pSort->nOBSat); } - } + }*/ regOrig = 0; assert(eDest == SRT_Set || eDest == SRT_Mem || eDest == SRT_Coroutine @@ -991,7 +999,7 @@ selectInnerLoop(Parse * pParse, /* The parser context */ * current row to the index and proceed with writing it to the * output table as well. */ - int addr = sqlite3VdbeCurrentAddr(v) + 4; + int addr = sqlite3VdbeCurrentAddr(v) + 6; sqlite3VdbeAddOp4Int(v, OP_Found, iParm + 1, addr, r1, 0); VdbeCoverage(v); @@ -1005,11 +1013,22 @@ selectInnerLoop(Parse * pParse, /* The parser context */ r1 + nPrefixReg, regResult, 1, nPrefixReg); } else { - int r2 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); - sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); - sqlite3VdbeChangeP5(v, OPFLAG_APPEND); - sqlite3ReleaseTempReg(pParse, r2); + int regRec = sqlite3GetTempReg(pParse); + /* Last column is required for ID. */ + int regCopy = sqlite3GetTempRange(pParse, nResultCol + 1); + sqlite3VdbeAddOp3(v, OP_NextIdEphemeral, iParm, + 0, regCopy + nResultCol); + /* Positioning ID column to be last in inserted tuple. + * NextId -> regCopy + n + 1 + * Copy [regResult, regResult + n] -> [regCopy, regCopy + n] + * MakeRecord -> [regCopy, regCopy + n + 1] -> regRec + * IdxInsert -> regRec + */ + sqlite3VdbeAddOp3(v, OP_Copy, regResult, regCopy, nResultCol - 1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regCopy, nResultCol + 1, regRec); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRec); + sqlite3ReleaseTempReg(pParse, regRec); + sqlite3ReleaseTempRange(pParse, regCopy, nResultCol + 1); } sqlite3ReleaseTempRange(pParse, r1, nPrefixReg + 1); break; @@ -1184,6 +1203,7 @@ sqlite3KeyInfoAlloc(sqlite3 * db, int N, int X) p->nXField = (u16) X; p->db = db; p->nRef = 1; + p->aColl[0] = NULL; memset(&p[1], 0, nExtra); } else { sqlite3OomFault(db); @@ -1469,10 +1489,12 @@ generateSortTail(Parse * pParse, /* Parsing context */ switch (eDest) { case SRT_Table: case SRT_EphemTab: { - sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, - regRowid); - sqlite3VdbeChangeP5(v, OPFLAG_APPEND); + int regCopy = sqlite3GetTempRange(pParse, nColumn); + sqlite3VdbeAddOp3(v, OP_NextIdEphemeral, iParm, 0, regRowid); + sqlite3VdbeAddOp3(v, OP_Copy, regRow, regCopy, nSortData - 1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regCopy, nColumn + 1, regRow); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRow); + sqlite3ReleaseTempReg(pParse, regCopy); break; } #ifndef SQLITE_OMIT_SUBQUERY @@ -2338,15 +2360,19 @@ generateWithRecursiveQuery(Parse * pParse, /* Parsing context */ sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, iQueue, pOrderBy->nExpr + 2, 0, (char *)pKeyInfo, P4_KEYINFO); + VdbeComment((v, "Orderby table")); destQueue.pOrderBy = pOrderBy; } else { - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iQueue, nCol); + KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nCol + 1, 0); + sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, iQueue, nCol + 1, 0, + (char*)pKeyInfo, P4_KEYINFO); + VdbeComment((v, "Queue table")); } - VdbeComment((v, "Queue table")); if (iDistinct) { p->addrOpenEphm[0] = - sqlite3VdbeAddOp2(v, OP_OpenTEphemeral, iDistinct, 0); + sqlite3VdbeAddOp2(v, OP_OpenTEphemeral, iDistinct, 1); p->selFlags |= SF_UsesEphemeral; + VdbeComment((v, "Distinct table")); } /* Detach the ORDER BY clause from the compound SELECT */ @@ -2541,8 +2567,11 @@ multiSelect(Parse * pParse, /* Parsing context */ */ if (dest.eDest == SRT_EphemTab) { assert(p->pEList); - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, - p->pEList->nExpr); + int nCols = p->pEList->nExpr; + KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nCols + 1, 0); + sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, dest.iSDParm, nCols + 1, + 0, (char*)pKeyInfo, P4_KEYINFO); + VdbeComment((v, "Destination temp")); dest.eDest = SRT_Table; } @@ -5238,8 +5267,8 @@ resetAccumulator(Parse * pParse, AggInfo * pAggInfo) KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0); - sqlite3VdbeAddOp4(v, OP_OpenEphemeral, - pFunc->iDistinct, 0, 0, + sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, + pFunc->iDistinct, 1, 0, (char *)pKeyInfo, P4_KEYINFO); } } @@ -5731,14 +5760,19 @@ sqlite3Select(Parse * pParse, /* The parser context */ if (sSort.pOrderBy) { KeyInfo *pKeyInfo; pKeyInfo = - keyInfoFromExprList(pParse, sSort.pOrderBy, 0, - pEList->nExpr); + keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr); 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; sSort.addrSortIndex = - sqlite3VdbeAddOp4(v, OP_OpenEphemeral, + sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, sSort.iECursor, - sSort.pOrderBy->nExpr + 1 + pEList->nExpr, + nCols, 0, (char *)pKeyInfo, P4_KEYINFO); + VdbeComment((v, "Sort table")); } else { sSort.addrSortIndex = -1; } @@ -5746,8 +5780,12 @@ sqlite3Select(Parse * pParse, /* The parser context */ /* If the output is destined for a temporary table, open that table. */ if (pDest->eDest == SRT_EphemTab) { - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, - pEList->nExpr); + KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, + pEList->nExpr + 1, 0); + sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, pDest->iSDParm, + pEList->nExpr + 1, 0, (char*)pKeyInfo, P4_KEYINFO); + + VdbeComment((v, "Output table")); } /* Set the limiter. @@ -5766,13 +5804,14 @@ sqlite3Select(Parse * pParse, /* The parser context */ */ if (p->selFlags & SF_Distinct) { sDistinct.tabTnct = pParse->nTab++; - sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, - sDistinct.tabTnct, 0, 0, - (char *) - keyInfoFromExprList - (pParse, p->pEList, 0, - 0), P4_KEYINFO); + KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, p->pEList, 0, 0); + sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, + sDistinct.tabTnct, + pKeyInfo->nField, + 0, (char *)pKeyInfo, + P4_KEYINFO); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); + VdbeComment((v, "Distinct table")); sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; } else { sDistinct.eTnctType = WHERE_DISTINCT_NOOP; diff --git a/src/box/sql/where.c b/src/box/sql/where.c index c4a98d1628cc30571a0f03c24d9f419da139f6eb..0b5b0979c489cb3149f24c247faee08019283876 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -2785,10 +2785,8 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ int iSortIdx = 1; /* Index number */ int b; /* A boolean value */ LogEst rSize; /* number of rows in the table */ - LogEst rLogSize; /* Logarithm of the number of rows in the table */ WhereClause *pWC; /* The parsed WHERE clause */ Table *pTab; /* Table being queried */ - struct session *user_session = current_session(); pNew = pBuilder->pNew; pWInfo = pBuilder->pWInfo; @@ -2828,11 +2826,12 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /* WHERE clause information */ } pProbe = &sPk; } - rSize = pTab->nRowLogEst; - rLogSize = estLog(rSize); #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ + LogEst rSize = pTab->nRowLogEst; + LogEst rLogSize = estLog(rSize); + struct session *user_session = current_session(); if (!pBuilder->pOrSet /* Not part of an OR optimization */ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) == 0 && (user_session->sql_flags & SQLITE_AutoIndex) != 0 && pSrc->pIBIndex == 0 /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ diff --git a/test/sql-tap/distinct.test.lua b/test/sql-tap/distinct.test.lua index e932394d3f0ac004479a1c0148bdd1af39fe2bf4..203afab5d669c3aceb770f5e50e252d5fcef582c 100755 --- a/test/sql-tap/distinct.test.lua +++ b/test/sql-tap/distinct.test.lua @@ -67,7 +67,7 @@ local function do_temptables_test(tn, sql, temptables) for _, val in ipairs(r) do local opcode = val[2] local p5 = val[7] - if opcode == "OpenEphemeral" or opcode == "SorterOpen" then + if opcode == "OpenTEphemeral" or opcode == "SorterOpen" then if p5 ~= "08" and p5 ~= "00" then error()--p5 = $p5) end