diff options
author | drh <drh@noemail.net> | 2005-06-24 03:53:06 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2005-06-24 03:53:06 +0000 |
commit | 7f057c9166a1c8e13bda74b3db7ee488659ae7fb (patch) | |
tree | 956b9811b110b14adac869c6de43ced5ec19d84d /src | |
parent | 2f471496913a58a9d8f2c5852275a0666dc169df (diff) | |
download | sqlite-7f057c9166a1c8e13bda74b3db7ee488659ae7fb.tar.gz sqlite-7f057c9166a1c8e13bda74b3db7ee488659ae7fb.zip |
NULL values in a row of a unique index cause the row to be distinct.
Ticket #1301. More testing and optimization needs to be done on this
before closing the ticket. (CVS 2526)
FossilOrigin-Name: 06a71b162b032fc5b56d18919a784d4ee94dde7c
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 20 | ||||
-rw-r--r-- | src/delete.c | 4 | ||||
-rw-r--r-- | src/insert.c | 7 | ||||
-rw-r--r-- | src/vdbe.c | 63 |
4 files changed, 39 insertions, 55 deletions
diff --git a/src/build.c b/src/build.c index 27f2adcf0..e0a6e5953 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.327 2005/06/14 02:12:46 drh Exp $ +** $Id: build.c,v 1.328 2005/06/24 03:53:06 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1973,7 +1973,6 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ int addr1; /* Address of top of loop */ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ - int isUnique; /* True for a unique index */ #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, @@ -2007,11 +2006,18 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3VdbeAddOp(v, OP_SetNumColumns, iTab, pTab->nCol); addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0); sqlite3GenerateIndexKey(v, pIndex, iTab); - isUnique = pIndex->onError!=OE_None; - sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, isUnique); - if( isUnique ){ - sqlite3VdbeChangeP3(v, -1, "indexed columns are not unique", P3_STATIC); - } + if( pIndex->onError!=OE_None ){ + int curaddr = sqlite3VdbeCurrentAddr(v); + int addr2 = curaddr+4; + sqlite3VdbeChangeP2(v, curaddr-1, addr2); + sqlite3VdbeAddOp(v, OP_Rowid, iTab, 0); + sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); + sqlite3VdbeAddOp(v, OP_IsUnique, iIdx, addr2); + sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort, + "indexed columns are not unique", P3_STATIC); + assert( addr2==sqlite3VdbeCurrentAddr(v) ); + } + sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0); sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1); sqlite3VdbeChangeP2(v, addr1, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp(v, OP_Close, iTab, 0); diff --git a/src/delete.c b/src/delete.c index bf66c755d..cd8498807 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.106 2005/06/12 21:35:52 drh Exp $ +** $Id: delete.c,v 1.107 2005/06/24 03:53:06 drh Exp $ */ #include "sqliteInt.h" @@ -442,6 +442,6 @@ void sqlite3GenerateIndexKey( sqlite3ColumnDefault(v, pTab, idx); } } - sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24)); + sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0); sqlite3IndexAffinityStr(v, pIdx); } diff --git a/src/insert.c b/src/insert.c index 36a024451..e336f6cf9 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.139 2005/06/12 21:35:52 drh Exp $ +** $Id: insert.c,v 1.140 2005/06/24 03:53:06 drh Exp $ */ #include "sqliteInt.h" @@ -949,7 +949,7 @@ void sqlite3GenerateConstraintChecks( sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1); } } - jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24)); + jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0); sqlite3IndexAffinityStr(v, pIdx); /* Find out what action to take in case there is an indexing conflict */ @@ -1019,9 +1019,8 @@ void sqlite3GenerateConstraintChecks( } } contAddr = sqlite3VdbeCurrentAddr(v); - assert( contAddr<(1<<24) ); #if NULL_DISTINCT_FOR_UNIQUE - sqlite3VdbeChangeP2(v, jumpInst1, contAddr | (1<<24)); + sqlite3VdbeChangeP2(v, jumpInst1, contAddr); #endif sqlite3VdbeChangeP2(v, jumpInst2, contAddr); } diff --git a/src/vdbe.c b/src/vdbe.c index 34928fec5..4d0124153 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.470 2005/06/22 02:36:37 drh Exp $ +** $Id: vdbe.c,v 1.471 2005/06/24 03:53:06 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -633,7 +633,7 @@ case OP_Return: { /* no-push */ break; } -/* Opcode: Halt P1 P2 * +/* Opcode: Halt P1 P2 P3 ** ** Exit immediately. All open cursors, Lists, Sorts, etc are closed ** automatically. @@ -646,6 +646,8 @@ case OP_Return: { /* no-push */ ** then back out all changes that have occurred during this execution of the ** VDBE, but do not rollback the transaction. ** +** If P3 is not null then it is an error message string. +** ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. @@ -2000,12 +2002,9 @@ op_column_out: ** The original stack entries are popped from the stack if P1>0 but ** remain on the stack if P1<0. ** -** The P2 argument is divided into two 16-bit words before it is processed. -** If the hi-word is non-zero, then an extra integer is read from the stack -** and appended to the record as a varint. If the low-word of P2 is not -** zero and one or more of the entries are NULL, then jump to the value of -** the low-word of P2. This feature can be used to skip a uniqueness test -** on indices. +** If P2 is not zero and one or more of the entries are NULL, then jump +** to the address given by P2. This feature can be used to skip a +** uniqueness test on indices. ** ** P3 may be a string that is P1 characters long. The nth character of the ** string indicates the column affinity that should be used for the nth @@ -2019,7 +2018,17 @@ op_column_out: ** 'o' = NONE. ** ** If P3 is NULL then all index fields have the affinity NONE. +** +** See also OP_MakeIdxRec +*/ +/* Opcode: MakeRecordI P1 P2 P3 +** +** This opcode works just OP_MakeRecord except that it reads an extra +** integer from the stack (thus reading a total of abs(P1+1) entries) +** and appends that extra integer to the end of the record as a varint. +** This results in an index key. */ +case OP_MakeIdxRec: case OP_MakeRecord: { /* Assuming the record contains N fields, the record format looks ** like this: @@ -2057,8 +2066,8 @@ case OP_MakeRecord: { leaveOnStack = ((pOp->p1<0)?1:0); nField = pOp->p1 * (leaveOnStack?-1:1); - jumpIfNull = (pOp->p2 & 0x00FFFFFF); - addRowid = ((pOp->p2>>24) & 0x0000FFFF)?1:0; + jumpIfNull = pOp->p2; + addRowid = pOp->opcode==OP_MakeIdxRec; zAffinity = pOp->p3; pData0 = &pTos[1-nField]; @@ -3444,17 +3453,12 @@ case OP_Next: { /* no-push */ break; } -/* Opcode: IdxInsert P1 P2 P3 +/* Opcode: IdxInsert P1 * * ** ** The top of the stack holds a SQL index key made using the ** MakeIdxKey instruction. This opcode writes that key into the ** index P1. Data for the entry is nil. ** -** If P2==1, then the key must be unique. If the key is not unique, -** the program aborts with a SQLITE_CONSTRAINT error and the database -** is rolled back. If P3 is not null, then it becomes part of the -** error message returned with the SQLITE_CONSTRAINT. -** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ @@ -3466,35 +3470,10 @@ case OP_IdxInsert: { /* no-push */ assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); assert( pTos->flags & MEM_Blob ); + assert( pOp->p2==0 ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int nKey = pTos->n; const char *zKey = pTos->z; - if( pOp->p2 ){ - int res; - int len; - - /* 'len' is the length of the key minus the rowid at the end */ - len = nKey - sqlite3VdbeIdxRowidLen(nKey, zKey); - - rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res); - if( rc!=SQLITE_OK ) goto abort_due_to_error; - while( res!=0 && !sqlite3BtreeEof(pCrsr) ){ - int c; - if( sqlite3VdbeIdxKeyCompare(pC, len, zKey, &c)==SQLITE_OK && c==0 ){ - rc = SQLITE_CONSTRAINT; - if( pOp->p3 && pOp->p3[0] ){ - sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0); - } - goto abort_due_to_error; - } - if( res<0 ){ - sqlite3BtreeNext(pCrsr, &res); - res = +1; - }else{ - break; - } - } - } assert( pC->isTable==0 ); rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0); assert( pC->deferredMoveto==0 ); |