aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2005-06-24 03:53:06 +0000
committerdrh <drh@noemail.net>2005-06-24 03:53:06 +0000
commit7f057c9166a1c8e13bda74b3db7ee488659ae7fb (patch)
tree956b9811b110b14adac869c6de43ced5ec19d84d /src
parent2f471496913a58a9d8f2c5852275a0666dc169df (diff)
downloadsqlite-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.c20
-rw-r--r--src/delete.c4
-rw-r--r--src/insert.c7
-rw-r--r--src/vdbe.c63
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 );