1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Beginning to insert the infrastructure for ON CONFLICT clauses. (CVS 355)

FossilOrigin-Name: e00a9ff8f99dd58f7cb19a6195fac21f4c8b4af9
This commit is contained in:
drh
2002-01-29 18:41:24 +00:00
parent 881a99e493
commit 9cfcf5d4f6
13 changed files with 590 additions and 209 deletions

View File

@@ -30,7 +30,7 @@
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.108 2002/01/28 15:53:05 drh Exp $
** $Id: vdbe.c,v 1.109 2002/01/29 18:41:25 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -382,6 +382,17 @@ void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){
}
}
/*
** Change the value of the P2 operand for a specific instruction.
** This routine is useful for setting a jump destination.
*/
void sqliteVdbeChangeP2(Vdbe *p, int addr, int val){
assert( val>=0 );
if( p && addr>=0 && p->nOp>addr && p->aOp ){
p->aOp[addr].p2 = val;
}
}
/*
** Change the value of the P3 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
@@ -853,31 +864,31 @@ static char *zOpName[] = { 0,
"SetCookie", "VerifyCookie", "Open", "OpenTemp",
"OpenWrite", "OpenAux", "OpenWrAux", "Close",
"MoveTo", "NewRecno", "PutIntKey", "PutStrKey",
"Distinct", "Found", "NotFound", "NotExists",
"Delete", "Column", "KeyAsData", "Recno",
"FullKey", "Rewind", "Next", "Destroy",
"Clear", "CreateIndex", "CreateTable", "Reorganize",
"IdxPut", "IdxDelete", "IdxRecno", "IdxGT",
"IdxGE", "MemLoad", "MemStore", "ListWrite",
"ListRewind", "ListRead", "ListReset", "SortPut",
"SortMakeRec", "SortMakeKey", "Sort", "SortNext",
"SortCallback", "SortReset", "FileOpen", "FileRead",
"FileColumn", "AggReset", "AggFocus", "AggIncr",
"AggNext", "AggSet", "AggGet", "SetInsert",
"SetFound", "SetNotFound", "MakeRecord", "MakeKey",
"MakeIdxKey", "IncrKey", "Goto", "If",
"Halt", "ColumnCount", "ColumnName", "Callback",
"NullCallback", "Integer", "String", "Pop",
"Dup", "Pull", "MustBeInt", "Add",
"AddImm", "Subtract", "Multiply", "Divide",
"Remainder", "BitAnd", "BitOr", "BitNot",
"ShiftLeft", "ShiftRight", "AbsValue", "Precision",
"Min", "Max", "Like", "Glob",
"Eq", "Ne", "Lt", "Le",
"Gt", "Ge", "IsNull", "NotNull",
"Negative", "And", "Or", "Not",
"Concat", "Noop", "Strlen", "Substr",
"Limit",
"Distinct", "Found", "NotFound", "IsUnique",
"NotExists", "Delete", "Column", "KeyAsData",
"Recno", "FullKey", "Rewind", "Next",
"Destroy", "Clear", "CreateIndex", "CreateTable",
"Reorganize", "IdxPut", "IdxDelete", "IdxRecno",
"IdxGT", "IdxGE", "MemLoad", "MemStore",
"ListWrite", "ListRewind", "ListRead", "ListReset",
"SortPut", "SortMakeRec", "SortMakeKey", "Sort",
"SortNext", "SortCallback", "SortReset", "FileOpen",
"FileRead", "FileColumn", "AggReset", "AggFocus",
"AggIncr", "AggNext", "AggSet", "AggGet",
"SetInsert", "SetFound", "SetNotFound", "MakeRecord",
"MakeKey", "MakeIdxKey", "IncrKey", "Goto",
"If", "Halt", "ColumnCount", "ColumnName",
"Callback", "NullCallback", "Integer", "String",
"Pop", "Dup", "Pull", "Push",
"MustBeInt", "Add", "AddImm", "Subtract",
"Multiply", "Divide", "Remainder", "BitAnd",
"BitOr", "BitNot", "ShiftLeft", "ShiftRight",
"AbsValue", "Precision", "Min", "Max",
"Like", "Glob", "Eq", "Ne",
"Lt", "Le", "Gt", "Ge",
"IsNull", "NotNull", "Negative", "And",
"Or", "Not", "Concat", "Noop",
"Strlen", "Substr", "Limit",
};
/*
@@ -1138,17 +1149,26 @@ case OP_Goto: {
break;
}
/* Opcode: Halt * * *
/* Opcode: Halt P1 * *
**
** Exit immediately. All open cursors, Lists, Sorts, etc are closed
** automatically.
**
** There is an implied Halt instruction inserted at the very end of
** P1 is the result code returned by sqlite_exec(). For a normal
** halt, this should be SQLITE_OK (0). For errors, it can be some
** other value.
**
** 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.
*/
case OP_Halt: {
pc = p->nOp-1;
if( pOp->p1!=SQLITE_OK ){
rc = pOp->p1;
goto abort_due_to_error;
}else{
pc = p->nOp-1;
}
break;
}
@@ -1195,7 +1215,7 @@ case OP_Pop: {
break;
}
/* Opcode: Dup P1 * *
/* Opcode: Dup P1 P2 *
**
** A copy of the P1-th element of the stack
** is made and pushed onto the top of the stack.
@@ -1203,6 +1223,11 @@ case OP_Pop: {
** instruction "Dup 0 0 0" will make a copy of the
** top of the stack.
**
** If the content of the P1-th element is a dynamically
** allocated string, then a new copy of that string
** is made if P2==0. If P2!=0, then just a pointer
** to the string is copied.
**
** Also see the Pull instruction.
*/
case OP_Dup: {
@@ -1212,7 +1237,7 @@ case OP_Dup: {
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
memcpy(&aStack[j], &aStack[i], sizeof(aStack[i])-NBFS);
if( aStack[j].flags & STK_Str ){
if( aStack[j].flags & STK_Static ){
if( pOp->p2 || (aStack[j].flags & STK_Static)!=0 ){
zStack[j] = zStack[i];
aStack[j].flags = STK_Str | STK_Static;
}else if( aStack[i].n<=NBFS ){
@@ -1265,6 +1290,33 @@ case OP_Pull: {
break;
}
/* Opcode: Push P1 * *
**
** Overwrite the value of the P1-th element down on the
** stack (P1==0 is the top of the stack) with the value
** of the top of the stack. The pop the top of the stack.
*/
case OP_Push: {
int from = p->tos;
int to = p->tos - pOp->p1;
int i;
Stack ts;
char *tz;
VERIFY( if( to<0 ) goto not_enough_stack; )
if( aStack[to].flags & STK_Dyn ){
sqliteFree(zStack[to]);
}
aStack[to] = aStack[from];
if( aStack[to].flags & (STK_Dyn|STK_Static) ){
zStack[to] = zStack[from];
}else{
zStack[to] = aStack[to].z;
}
aStack[from].flags &= ~STK_Dyn;
p->tos--;
break;
}
/* Opcode: ColumnCount P1 * *
**
** Specify the number of column values that will appear in the
@@ -2010,8 +2062,8 @@ case OP_IsNull: {
/* Opcode: NotNull * P2 *
**
** Pop a single value from the stack. If the value popped is not an
** empty string, then jump to p2. Otherwise continue to the next
** Pop a single value from the stack. If the value popped is not
** NULL, then jump to p2. Otherwise continue to the next
** instruction.
*/
case OP_NotNull: {
@@ -2675,7 +2727,7 @@ case OP_MoveTo: {
** The difference between this operation and Distinct is that
** Distinct does not pop the key from the stack.
**
** See also: Distinct, Found, MoveTo, NotExists
** See also: Distinct, Found, MoveTo, NotExists, IsUnique
*/
case OP_Distinct:
case OP_NotFound:
@@ -2702,6 +2754,66 @@ case OP_Found: {
break;
}
/* Opcode: IsUnique P1 P2 *
**
** The top of the stack is an index key created using MakeIdxKey. If
** there does not exist an entry in P1 that exactly matches the top of
** the stack, then jump immediately to P2. If there are no entries
** in P1 that match all but the last four bytes of the top of the stack
** then also jump to P2. The index key on the top of the stack is
** unchanged.
**
** If there is an entry in P1 which differs from the index key on the
** top of the stack only in the last four bytes, then do not jump.
** Instead, push the last four bytes of the existing P1 entry onto the
** stack and fall through. This new stack element is the record number
** of an existing entry this preventing the index key on the stack from
** being a unique key.
**
** See also: Distinct, NotFound, NotExists
*/
case OP_IsUnique: {
int i = pOp->p1;
int tos = p->tos;
BtCursor *pCrsr;
VERIFY( if( tos<0 ) goto not_enough_stack; )
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
int res, rc;
int v1, v2;
char *zKey = zStack[tos];
int nKey = aStack[tos].n;
if( Stringify(p, tos) ) goto no_mem;
assert( aStack[tos].n >= 4 );
rc = sqliteBtreeMoveto(pCrsr, zKey, nKey-4, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( res<0 ){
rc = sqliteBtreeNext(pCrsr, &res);
if( res ){
pc = pOp->p2 - 1;
break;
}
}
rc = sqliteBtreeKeyCompare(pCrsr, zKey, nKey-4, 4, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( res>0 ){
pc = pOp->p2 - 1;
break;
}
sqliteBtreeKey(pCrsr, nKey - 4, 4, (char*)&v1);
memcpy((char*)&v2, &zKey[nKey-4], 4);
if( v1==v2 ){
pc = pOp->p2 - 1;
break;
}
tos = ++p->tos;
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
aStack[tos].i = keyToInt(v1);
aStack[tos].flags = STK_Int;
}
break;
}
/* Opcode: NotExists P1 P2 *
**
** Use the top of the stack as a integer key. If a record with that key