Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge recent trunk changes, and especially the fix for the CREATE UNIQUE INDEX problem of ticket [9a6daf340df99ba9]. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | threads |
Files: | files | file ages | folders |
SHA1: |
5b50a8380b2b678c1646ff303e3696ef |
User & Date: | drh 2014-07-30 14:44:24.940 |
Context
2014-07-30
| ||
17:21 | Mark some invariants in the vdbesort.c logic when SQLITE_MAX_WORKER_THREADS==0. (check-in: 721cd96585 user: drh tags: threads) | |
14:44 | Merge recent trunk changes, and especially the fix for the CREATE UNIQUE INDEX problem of ticket [9a6daf340df99ba9]. (check-in: 5b50a8380b user: drh tags: threads) | |
13:56 | Ensure that the correct number of columns in a UNIQUE index are checked for uniqueness, regardless of whether or not the original table has a ROWID or if the columns are NOT NULL, etc. Ticket [9a6daf340df99ba93c]. (check-in: 6b785e92f2 user: drh tags: trunk) | |
2014-07-29
| ||
21:44 | Disable an assert that is sometimes generated spuriously. (check-in: bd9ee0ea69 user: mistachkin tags: threads) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
2708 2709 2710 2711 2712 2713 2714 | addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); 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, | | | 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 | addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); 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, pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); }else{ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord); sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
1061 1062 1063 1064 1065 1066 1067 | } } /* ** Return a static string containing the name corresponding to the error code ** specified in the argument. */ | | | 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 | } } /* ** Return a static string containing the name corresponding to the error code ** specified in the argument. */ #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) const char *sqlite3ErrName(int rc){ const char *zName = 0; int i, origRc = rc; for(i=0; i<2 && zName==0; i++, rc &= 0xff){ switch( rc ){ case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; |
︙ | ︙ |
Changes to src/os_win.c.
︙ | ︙ | |||
1297 1298 1299 1300 1301 1302 1303 | #if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX # define osIsNT() (1) #elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI) # define osIsNT() (1) #elif !defined(SQLITE_WIN32_HAS_WIDE) # define osIsNT() (0) #else | > > | > > > > > | | | | | | | | | | | < | 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 | #if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX # define osIsNT() (1) #elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI) # define osIsNT() (1) #elif !defined(SQLITE_WIN32_HAS_WIDE) # define osIsNT() (0) #else # define osIsNT() (sqlite3_win32_is_nt()) #endif /* ** This function determines if the machine is running a version of Windows ** based on the NT kernel. */ int sqlite3_win32_is_nt(void){ if( sqlite3_os_type==0 ){ #if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8 OSVERSIONINFOW sInfo; sInfo.dwOSVersionInfoSize = sizeof(sInfo); osGetVersionExW(&sInfo); #else OSVERSIONINFOA sInfo; sInfo.dwOSVersionInfoSize = sizeof(sInfo); osGetVersionExA(&sInfo); #endif sqlite3_os_type = (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1; } return (sqlite3_os_type == 2); } #ifdef SQLITE_WIN32_MALLOC /* ** Allocate nBytes of memory. */ static void *winMemMalloc(int nBytes){ HANDLE hHeap; |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
4289 4290 4291 4292 4293 4294 4295 | case OP_ResetCount: { sqlite3VdbeSetChanges(db, p->nChange); p->nChange = 0; break; } /* Opcode: SorterCompare P1 P2 P3 P4 | | | | | | | | 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 | case OP_ResetCount: { sqlite3VdbeSetChanges(db, p->nChange); p->nChange = 0; break; } /* Opcode: SorterCompare P1 P2 P3 P4 ** Synopsis: if key(P1)!=trim(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. Only the first P4 fields ** of r[P3] and the sorter record are compared. ** ** 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 nKeyCol; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); assert( pOp->p4type==P4_INT32 ); pIn3 = &aMem[pOp->p3]; nKeyCol = pOp->p4.i; res = 0; rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2-1; } break; }; |
︙ | ︙ |
Changes to src/vdbesort.c.
︙ | ︙ | |||
2451 2452 2453 2454 2455 2456 2457 | ** ** This routine forms the core of the OP_SorterCompare opcode, which in ** turn is used to verify uniqueness when constructing a UNIQUE INDEX. */ int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ | | | | | | 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 | ** ** This routine forms the core of the OP_SorterCompare opcode, which in ** turn is used to verify uniqueness when constructing a UNIQUE INDEX. */ int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ int nKeyCol, /* Compare this many columns */ int *pRes /* OUT: Result of comparison */ ){ VdbeSorter *pSorter = pCsr->pSorter; UnpackedRecord *r2 = pSorter->pUnpacked; KeyInfo *pKeyInfo = pCsr->pKeyInfo; int i; void *pKey; int nKey; /* Sorter key to compare pVal with */ if( r2==0 ){ char *p; r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p); assert( pSorter->pUnpacked==(UnpackedRecord*)p ); if( r2==0 ) return SQLITE_NOMEM; r2->nField = nKeyCol; } assert( r2->nField==nKeyCol ); pKey = vdbeSorterRowkey(pSorter, &nKey); sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2); for(i=0; i<nKeyCol; i++){ if( r2->aMem[i].flags & MEM_Null ){ *pRes = -1; return SQLITE_OK; } } *pRes = sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2, 0); |
︙ | ︙ |
Added test/unique2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | # 2014-07-30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE UNIQUE INDEX statement # to verify that ticket 9a6daf340df99ba93c53bcf8fa83d9f28040d2a8 # has been fixed: # # drh added on 2014-07-30 12:33:04: # # The CREATE UNIQUE INDEX on the third line below does not fail even # though the x column values are not all unique. # # CREATE TABLE t1(x NOT NULL); # INSERT INTO t1 VALUES(1),(2),(2),(3); # CREATE UNIQUE INDEX t1x ON t1(x); # # If the index is created before the INSERT, then uniqueness is enforced # at the point of the INSERT. Note that the NOT NULL on the indexed column # seems to be required in order to exhibit this bug. # # "PRAGMA integrity_check" does not detect the resulting malformed database. # That might be considered a separate issue. # # Bisecting shows that this problem was introduced by the addition of # WITHOUT ROWID support in version 3.8.2, specifically in check-in # [c80e229dd9c1230] on 2013-11-07. This problem was reported on the mailing # list by Pavel Pimenov. and primary keys, and the UNIQUE constraint # on table columns # set testdir [file dirname $argv0] source $testdir/tester.tcl foreach {id sql} { 1 {CREATE TABLE t1(x TEXT PRIMARY KEY, y NOT NULL) WITHOUT ROWID} 2 {CREATE TABLE t1(x TEXT PRIMARY KEY, y NOT NULL)} 3 {CREATE TABLE t1(x TEXT PRIMARY KEY, y) WITHOUT ROWID} 4 {CREATE TABLE t1(x TEXT PRIMARY KEY, y)} } { do_test $id.1 { db eval {DROP TABLE IF EXISTS t1} db eval $sql db eval {INSERT INTO t1(x,y) VALUES(1,1),(2,2),(3,2),(4,3)} } {} do_test $id.2 { catchsql {CREATE UNIQUE INDEX t1y ON t1(y)} } {1 {UNIQUE constraint failed: t1.y}} } foreach {id sql} { 5 {CREATE TABLE t1(w,x,y NOT NULL,z NOT NULL,PRIMARY KEY(w,x)) WITHOUT ROWID} 6 {CREATE TABLE t1(w,x,y NOT NULL,z NOT NULL,PRIMARY KEY(w,x))} 7 {CREATE TABLE t1(w,x,y NOT NULL,z,PRIMARY KEY(w,x)) WITHOUT ROWID} 8 {CREATE TABLE t1(w,x,y NOT NULL,z,PRIMARY KEY(w,x))} 9 {CREATE TABLE t1(w,x,y,z NOT NULL,PRIMARY KEY(w,x)) WITHOUT ROWID} 10 {CREATE TABLE t1(w,x,y,z NOT NULL,PRIMARY KEY(w,x))} 11 {CREATE TABLE t1(w,x,y,z,PRIMARY KEY(w,x)) WITHOUT ROWID} 12 {CREATE TABLE t1(w,x,y,z,PRIMARY KEY(w,x))} } { do_test $id.1 { db eval {DROP TABLE IF EXISTS t1} db eval $sql db eval {INSERT INTO t1(w,x,y,z) VALUES(1,2,3,4),(2,3,3,4)} } {} do_test $id.2 { catchsql {CREATE UNIQUE INDEX t1yz ON t1(y,z)} } {1 {UNIQUE constraint failed: t1.y, t1.z}} } finish_test |