Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Size KeyInfo objects so that IdxInserts always compare the correct number of fields. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | omit-rowid |
Files: | files | file ages | folders |
SHA1: |
302a81390f039fc23eeb8510e95b9d9f |
User & Date: | drh 2013-11-01 22:02:56.824 |
Context
2013-11-02
| ||
11:43 | Import the sqlite3_analyzer fixes from trunk. (check-in: ac711459ff user: drh tags: omit-rowid) | |
2013-11-01
| ||
22:02 | Size KeyInfo objects so that IdxInserts always compare the correct number of fields. (check-in: 302a81390f user: drh tags: omit-rowid) | |
20:30 | Fix sqlite3_analyzer so that it works with WITHOUT ROWID tables. Fix index generation for secondary indices that include fields from the PRIMARY KEY. (check-in: f9769d701c user: drh tags: omit-rowid) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
2640 2641 2642 2643 2644 2645 2646 | sqlite3VdbeJumpHere(v, addr1); if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, (char *)pKey, P4_KEYINFO_HANDOFF); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); | > | | > | 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 | sqlite3VdbeJumpHere(v, addr1); if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, (char *)pKey, P4_KEYINFO_HANDOFF); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); assert( pKey!=0 || db->mallocFailed || pParse->nErr ); if( pIndex->onError!=OE_None && pKey!=0 ){ int j2 = sqlite3VdbeCurrentAddr(v) + 3; sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, pKey->nField - pIndex->nKeyCol); sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE, OE_Abort, "indexed columns are not unique", P4_STATIC ); }else{ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord); |
︙ | ︙ | |||
4068 4069 4070 4071 4072 4073 4074 | */ KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){ int i; int nCol = pIdx->nColumn; int nKey = pIdx->nKeyCol; KeyInfo *pKey; | > | > > > | 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 | */ KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){ int i; int nCol = pIdx->nColumn; int nKey = pIdx->nKeyCol; KeyInfo *pKey; if( pIdx->uniqNotNull ){ pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey); }else{ pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); } if( pKey ){ for(i=0; i<nCol; i++){ char *zColl = pIdx->azColl[i]; if( zColl==0 ) zColl = "BINARY"; pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl); pKey->aSortOrder[i] = pIdx->aSortOrder[i]; } |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
3354 3355 3356 3357 3358 3359 3360 | } } pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); pCx->isIndex = !pCx->isTable; break; } | | < | 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 | } } pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); pCx->isIndex = !pCx->isTable; break; } /* Opcode: SorterOpen P1 * * P4 * ** ** This opcode works like OP_OpenEphemeral except that it opens ** a transient index that is specifically designed to sort large ** tables using an external merge-sort algorithm. */ case OP_SorterOpen: { VdbeCursor *pCx; |
︙ | ︙ | |||
4190 4191 4192 4193 4194 4195 4196 | */ case OP_ResetCount: { sqlite3VdbeSetChanges(db, p->nChange); p->nChange = 0; break; } | | | | > | > > > | > > | > > > > | | 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 | */ case OP_ResetCount: { sqlite3VdbeSetChanges(db, p->nChange); p->nChange = 0; break; } /* Opcode: SorterCompare P1 P2 P3 P4 ** Synopsis: if key(P1)!=rtrim(r[P3],P4) goto P2 ** ** P1 is a sorter cursor. This instruction compares a prefix of the ** the record blob in register P3 against a prefix of the entry that ** the sorter cursor currently points to. The final P4 fields of both ** the P3 and sorter record are ignored. ** ** If either P3 or the sorter contains a NULL in one of their significant ** fields (not counting the P4 fields at the end which are ignored) then ** the comparison is assumed to be equal. ** ** Fall through to next instruction if the two records compare equal to ** each other. Jump to P2 if they are different. */ case OP_SorterCompare: { VdbeCursor *pC; int res; int nIgnore; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); assert( pOp->p4type==P4_INT32 ); pIn3 = &aMem[pOp->p3]; nIgnore = pOp->p4.i; rc = sqlite3VdbeSorterCompare(pC, pIn3, nIgnore, &res); if( res ){ pc = pOp->p2-1; } break; }; /* Opcode: SorterData P1 P2 * * * |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
443 444 445 446 447 448 449 | int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *); int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *); | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *); int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *); int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 void sqlite3VdbeEnter(Vdbe*); void sqlite3VdbeLeave(Vdbe*); #else # define sqlite3VdbeEnter(X) # define sqlite3VdbeLeave(X) |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 | int nCol = pIdx->nKeyCol+1; /* Number of index columns including rowid */ nByte = sizeof(Mem) * nCol + sizeof(UnpackedRecord); pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte); if( pRec ){ pRec->pKeyInfo = sqlite3IndexKeyinfo(p->pParse, pIdx); if( pRec->pKeyInfo ){ | | | 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 | int nCol = pIdx->nKeyCol+1; /* Number of index columns including rowid */ nByte = sizeof(Mem) * nCol + sizeof(UnpackedRecord); pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte); if( pRec ){ pRec->pKeyInfo = sqlite3IndexKeyinfo(p->pParse, pIdx); if( pRec->pKeyInfo ){ assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol ); pRec->pKeyInfo->enc = ENC(db); pRec->flags = UNPACKED_PREFIX_MATCH; pRec->aMem = (Mem *)&pRec[1]; for(i=0; i<nCol; i++){ pRec->aMem[i].flags = MEM_Null; pRec->aMem[i].type = SQLITE_NULL; pRec->aMem[i].db = db; |
︙ | ︙ | |||
1358 1359 1360 1361 1362 1363 1364 | ** Unless it is NULL, the argument must be an UnpackedRecord object returned ** by an earlier call to sqlite3Stat4ProbeSetValue(). This call deletes ** the object. */ void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){ if( pRec ){ int i; | | | 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 | ** Unless it is NULL, the argument must be an UnpackedRecord object returned ** by an earlier call to sqlite3Stat4ProbeSetValue(). This call deletes ** the object. */ void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){ if( pRec ){ int i; int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField; Mem *aMem = pRec->aMem; sqlite3 *db = aMem[0].db; for(i=0; i<nCol; i++){ sqlite3DbFree(db, aMem[i].zMalloc); } sqlite3DbFree(db, pRec->pKeyInfo); sqlite3DbFree(db, pRec); |
︙ | ︙ |
Changes to src/vdbesort.c.
︙ | ︙ | |||
382 383 384 385 386 387 388 | ** be less than key2. Even if key2 also contains NULL values. ** ** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace ** has been allocated and contains an unpacked record that is used as key2. */ static void vdbeSorterCompare( const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */ | | | | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | ** be less than key2. Even if key2 also contains NULL values. ** ** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace ** has been allocated and contains an unpacked record that is used as key2. */ static void vdbeSorterCompare( const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */ int nIgnore, /* Ignore the last nIgnore fields */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2, /* Right side of comparison */ int *pRes /* OUT: Result of comparison */ ){ KeyInfo *pKeyInfo = pCsr->pKeyInfo; VdbeSorter *pSorter = pCsr->pSorter; UnpackedRecord *r2 = pSorter->pUnpacked; int i; if( pKey2 ){ sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2); } if( nIgnore ){ r2->nField = pKeyInfo->nField - nIgnore; assert( r2->nField>0 ); for(i=0; i<r2->nField; i++){ if( r2->aMem[i].flags & MEM_Null ){ *pRes = -1; return; } } |
︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 | ** Otherwise, set *pRes to a negative, zero or positive value if the ** key in pVal is smaller than, equal to or larger than the current sorter ** key. */ int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ int *pRes /* OUT: Result of comparison */ ){ VdbeSorter *pSorter = pCsr->pSorter; void *pKey; int nKey; /* Sorter key to compare pVal with */ pKey = vdbeSorterRowkey(pSorter, &nKey); | > | | 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 | ** Otherwise, set *pRes to a negative, zero or positive value if the ** key in pVal is smaller than, equal to or larger than the current sorter ** key. */ int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ int nIgnore, /* Ignore this many fields at the end */ int *pRes /* OUT: Result of comparison */ ){ VdbeSorter *pSorter = pCsr->pSorter; void *pKey; int nKey; /* Sorter key to compare pVal with */ pKey = vdbeSorterRowkey(pSorter, &nKey); vdbeSorterCompare(pCsr, nIgnore, pVal->z, pVal->n, pKey, nKey, pRes); return SQLITE_OK; } |