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

@ -1 +1 @@
2.2.5
2.3.0

View File

@ -1,9 +1,9 @@
C Version\s2.2.5\s(CVS\s448)
D 2002-01-28T16:00:00
C Beginning\sto\sinsert\sthe\sinfrastructure\sfor\sON\sCONFLICT\sclauses.\s(CVS\s355)
D 2002-01-29T18:41:24
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
F Makefile.template 3e26a3b9e7aee1b811deaf673e8d8973bdb3f22d
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
F VERSION 79f8cff9811acbf454323afd9f2fa6cd2a8b7674
F VERSION 34f7c904a063d2d3791c38521e40ae1648cd2e7e
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
F config.log 6a73d03433669b10a3f0c221198c3f26b9413914
@ -21,36 +21,36 @@ F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c c796e387da340cb628dc1e41f684fc20253f561e
F src/btree.h 9ead7f54c270d8a554e59352ca7318fdaf411390
F src/build.c 3f40a6e6cea4180fb742a3d0ce71f06df8121cab
F src/delete.c cc200609f927ee8fefdda5d11d3f3b2288493c0f
F src/build.c c5023252c4d0ed19067f2118639b8d9f14f3f91a
F src/delete.c 2d1abc228be80a3c41f29f3312534dd0c9cd5066
F src/expr.c 4cae8bf44d5732182e5e8c25b4552c05ea55593e
F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46
F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
F src/insert.c e3a3b5a1d46a02778feb3e2ccd9a6989201c03b5
F src/insert.c 475316610462d1b6881f45565bbebf3209f1088c
F src/main.c 0205771a6c31a9858ff131fc1e797b589afb76bf
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
F src/os.c c615faa4d23e742e0650e0751a6ad2a18438ad53
F src/os.h 5405a5695bf16889d4fc6caf9d42043caa41c269
F src/pager.c 1e80a3ba731e454df6bd2e58d32eeba7dd65121b
F src/pager.h f78d064c780855ff70beacbeba0e2324471b26fe
F src/parse.y f3fc4fb5766393003577bd175eb611495f6efd9f
F src/parse.y fd79a09265b4703e37a62084db6fe67c834defb4
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
F src/random.c f6b36bec5ebd3edb3440224bf5bf811fe4ac9a1b
F src/select.c fc11d5a8c2bae1b62d8028ffb111c773ad6bf161
F src/shell.c c102dfe388c7618a668c944ff157c49cb48f28e3
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c
F src/sqliteInt.h 3274f3039db3164ba8c31acce027ea6408f247b3
F src/sqliteInt.h f4dc7f359549f70cd0fd6c68ae054d6986ad3afc
F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b
F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf
F src/update.c 6f87a9aa0b3ec0dfec0b0758104461445e701fdb
F src/tokenize.c 1199b96a82d5c41509b5e24fc9faa1852b7f3135
F src/update.c 2ece9c433968f9268d93bcc2f0ece409ab4dc296
F src/util.c 8f8973dd55a6ec63be9632fc5de86965c99d6327
F src/vdbe.c 71c0b7d368dd4c58867d7e577df0ee5404e25722
F src/vdbe.h 22d4df31cc16ca50b66b8125caec3495e5b407b2
F src/vdbe.c 5e51f9dfc34ee329117f59c28410ea9d4224402a
F src/vdbe.h 5b1bd518126fc5a30e6ea13fe11de931b32c4b59
F src/where.c 2dda39367f193194e4c7d2e0dcab31527d9d8aba
F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
@ -111,7 +111,7 @@ F www/download.tcl 1ea61f9d89a2a5a9b2cee36b0d5cf97321bdefe0
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
F www/faq.tcl 32cbc134879871604070d4cc3a32e73fb22a35f9
F www/formatchng.tcl d96e5e937dcbbebd481720aa08745ca5a906a63f
F www/index.tcl 571c585a5c0b577db2fe7cb88cf1f12cccd96ceb
F www/index.tcl 748614d8208c761ed3840e7958b8eed04de81822
F www/lang.tcl 6843fd3f85cba95fd199a350533ce742c706603c
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
@ -119,7 +119,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P dbcfe198fbaa155874ef82a96b6a4b993ccf3931
R 8bfbd1ab9c2165331e9740c7a67704b7
P af3bb80810c6cd302a884a106cc70591a738e102
R 82f94ecaa281bc36c2caa4b6f3c6c838
U drh
Z 6a85a2ce8e8f7c7177b049892c502454
Z 16309c459073f336b26332a0e349efd1

View File

@ -1 +1 @@
af3bb80810c6cd302a884a106cc70591a738e102
e00a9ff8f99dd58f7cb19a6195fac21f4c8b4af9

View File

@ -25,7 +25,7 @@
** ROLLBACK
** PRAGMA
**
** $Id: build.c,v 1.66 2002/01/28 15:53:05 drh Exp $
** $Id: build.c,v 1.67 2002/01/29 18:41:25 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -517,12 +517,13 @@ void sqliteAddColumn(Parse *pParse, Token *pName){
** been seen on a column. This routine sets the notNull flag on
** the column currently under construction.
*/
void sqliteAddNotNull(Parse *pParse){
void sqliteAddNotNull(Parse *pParse, int onError){
Table *p;
int i;
if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1;
if( i>=0 ) p->aCol[i].notNull = 1;
if( onError==OE_Default ) onError = OE_Abort;
if( i>=0 ) p->aCol[i].notNull = onError;
}
/*
@ -599,7 +600,7 @@ void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){
** If the key is not an INTEGER PRIMARY KEY, then create a unique
** index for the key. No index is created for INTEGER PRIMARY KEYs.
*/
void sqliteAddPrimaryKey(Parse *pParse, IdList *pList){
void sqliteAddPrimaryKey(Parse *pParse, IdList *pList, int onError){
Table *pTab = pParse->pNewTable;
char *zType = 0;
int iCol = -1;
@ -621,11 +622,13 @@ void sqliteAddPrimaryKey(Parse *pParse, IdList *pList){
if( iCol>=0 && iCol<pTab->nCol ){
zType = pTab->aCol[iCol].zType;
}
if( onError==OE_Default ) onError = OE_Abort;
if( pParse->db->file_format>=1 &&
zType && sqliteStrICmp(zType, "INTEGER")==0 ){
pTab->iPKey = iCol;
pTab->keyConf = onError;
}else{
sqliteCreateIndex(pParse, 0, 0, pList, 1, 0, 0);
sqliteCreateIndex(pParse, 0, 0, pList, onError, 0, 0);
}
}
@ -850,7 +853,7 @@ void sqliteCreateIndex(
Token *pName, /* Name of the index. May be NULL */
Token *pTable, /* Name of the table to index. Use pParse->pNewTable if 0 */
IdList *pList, /* A list of columns to be indexed */
int isUnique, /* True if all entries in this index must be unique */
int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */
Token *pEnd /* The ")" that closes the CREATE INDEX statement */
){
@ -967,7 +970,7 @@ void sqliteCreateIndex(
strcpy(pIndex->zName, zName);
pIndex->pTable = pTab;
pIndex->nColumn = pList->nId;
pIndex->isUnique = isUnique;
pIndex->onError = pIndex->isUnique = onError;
/* Scan the names of the columns of the table to be indexed and
** load the column indices into the Index structure. Report an error
@ -1000,8 +1003,24 @@ void sqliteCreateIndex(
}
db->flags |= SQLITE_InternChanges;
}
pIndex->pNext = pTab->pIndex;
pTab->pIndex = pIndex;
/* When adding an index to the list of indices for a table, make
** sure all indices labeled OE_Replace come after all those labeled
** OE_Ignore. This is necessary for the correct operation of UPDATE
** and INSERT.
*/
if( onError!=OE_Replace || pTab->pIndex==0
|| pTab->pIndex->onError==OE_Replace){
pIndex->pNext = pTab->pIndex;
pTab->pIndex = pIndex;
}else{
Index *pOther = pTab->pIndex;
while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
pOther = pOther->pNext;
}
pIndex->pNext = pOther->pNext;
pOther->pNext = pIndex;
}
/* If the initFlag is 1 it means we are reading the SQL off the
** "sqlite_master" table on the disk. So do not write to the disk
@ -1086,7 +1105,7 @@ void sqliteCreateIndex(
sqliteVdbeAddOp(v, OP_Column, 2, pIndex->aiColumn[i]);
}
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
sqliteVdbeAddOp(v, OP_IdxPut, 1, pIndex->isUnique);
sqliteVdbeAddOp(v, OP_IdxPut, 1, pIndex->onError!=OE_None);
sqliteVdbeAddOp(v, OP_Next, 2, lbl1);
sqliteVdbeResolveLabel(v, lbl2);
sqliteVdbeAddOp(v, OP_Close, 2, 0);
@ -1392,7 +1411,7 @@ void sqliteCopy(
sqliteVdbeAddOp(v, OP_FileColumn, pIdx->aiColumn[j], 0);
}
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
sqliteVdbeAddOp(v, OP_IdxPut, i, pIdx->isUnique);
sqliteVdbeAddOp(v, OP_IdxPut, i, pIdx->onError!=OE_None);
}
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
sqliteVdbeResolveLabel(v, end);
@ -1682,7 +1701,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_Integer, pIdx->isUnique, 0);
sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
++i;
pIdx = pIdx->pNext;

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.23 2002/01/22 03:13:42 drh Exp $
** $Id: delete.c,v 1.24 2002/01/29 18:41:25 drh Exp $
*/
#include "sqliteInt.h"
@ -151,24 +151,7 @@ void sqliteDeleteFrom(
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
if( pTab->pIndex ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
int j;
sqliteVdbeAddOp(v, OP_Recno, base, 0);
for(j=0; j<pIdx->nColumn; j++){
int idx = pIdx->aiColumn[j];
if( idx==pTab->iPKey ){
sqliteVdbeAddOp(v, OP_Dup, j, 0);
}else{
sqliteVdbeAddOp(v, OP_Column, base, idx);
}
}
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0);
}
}
sqliteVdbeAddOp(v, OP_Delete, base, 0);
sqliteGenerateRowDelete(v, pTab, base);
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
sqliteVdbeResolveLabel(v, end);
sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
@ -192,3 +175,51 @@ delete_from_cleanup:
sqliteExprDelete(pWhere);
return;
}
/*
** This routine generates VDBE code that causes a single row of a
** single table to be deleted.
**
** The VDBE must be in a particular state when this routine is called.
** These are the requirements:
**
** 1. A read/write cursor pointing to pTab, the table containing the row
** to be deleted, must be opened as cursor number "base".
**
** 2. Read/write cursors for all indices of pTab must be open as
** cursor number base+i for the i-th index.
**
** 3. The record number of the row to be deleted must be on the top
** of the stack.
**
** This routine pops the top of the stack to remove the record number
** and then generates code to remove both the table record and all index
** entries that point to that record.
*/
void sqliteGenerateRowDelete(
Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */
int base /* Cursor number for the table */
){
int i;
Index *pIdx;
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
if( pTab->pIndex ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
int j;
sqliteVdbeAddOp(v, OP_Recno, base, 0);
for(j=0; j<pIdx->nColumn; j++){
int idx = pIdx->aiColumn[j];
if( idx==pTab->iPKey ){
sqliteVdbeAddOp(v, OP_Dup, j, 0);
}else{
sqliteVdbeAddOp(v, OP_Column, base, idx);
}
}
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0);
}
}
sqliteVdbeAddOp(v, OP_Delete, base, 0);
}

View File

@ -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.33 2002/01/28 15:53:05 drh Exp $
** $Id: insert.c,v 1.34 2002/01/29 18:41:25 drh Exp $
*/
#include "sqliteInt.h"
@ -36,7 +36,8 @@ void sqliteInsert(
Token *pTableName, /* Name of table into which we are inserting */
ExprList *pList, /* List of values to be inserted */
Select *pSelect, /* A SELECT statement to use as the data source */
IdList *pColumn /* Column names corresponding to IDLIST. */
IdList *pColumn, /* Column names corresponding to IDLIST. */
int onError /* How to handle constraint errors */
){
Table *pTab; /* The table to insert into */
char *zTab; /* Name of the table into which we are inserting */
@ -329,3 +330,171 @@ insert_cleanup:
if( pSelect ) sqliteSelectDelete(pSelect);
sqliteIdListDelete(pColumn);
}
#if 0
/*
** Generate code to do a constraint check prior to an INSERT or an UPDATE.
**
** When this routine is called, the stack contains (from bottom to top)
** the recno of the row to be updated and each column of new data beginning
** with the first column. The code generated by this routine pushes addition
** entries onto the stack which are the keys for new index entries for
** the new record. The order of index keys is the same as the order of
** the indices on the pTable->pIndex list. A key is only created for
** index i if aIdxUsed!=0 and aIdxUsed[i]!=0.
**
** This routine also generates code to check constraints. NOT NULL,
** CHECK, and UNIQUE constraints are all checked. If a constraint fails,
** then the appropriate action is performed. The default action is to
** execute OP_Halt to abort the transaction and cause sqlite_exec() to
** return SQLITE_CONSTRAINT. This is the so-called "ABORT" action.
** Other actions are REPLACE and IGNORE. The following table summarizes
** what happens.
**
** Constraint type Action What Happens
** --------------- ---------- ----------------------------------------
** any ABORT The current transaction is rolled back and
** sqlite_exec() returns immediately with a
** return code of SQLITE_CONSTRAINT.
**
** any IGNORE The record number and data is popped from
** the stack and there is an immediate jump
** to label ignoreDest.
**
** NOT NULL REPLACE The NULL value is replace by the default
** value for that column. If the default value
** is NULL, the action is the same as ABORT.
**
** UNIQUE REPLACE The other row that conflicts with the row
** being inserted is removed.
**
** CHECK REPLACE Illegal. The results in an exception.
**
** The action to take is determined by the constraint itself if
** overrideError is OE_Default. Otherwise, overrideError determines
** which action to use.
**
** The calling routine must an open read/write cursor for pTab with
** cursor number "base". All indices of pTab must also have open
** read/write cursors with cursor number base+i for the i-th cursor.
** Except, if there is no possibility of a REPLACE action then
** cursors do not need to be open for indices where aIdxUsed[i]==0.
**
** If the isUpdate flag is true, it means that the "base" cursor is
** initially pointing to an entry that is being updated. The isUpdate
** flag causes extra code to be generated so that the "base" cursor
** is still pointing at the same entry after the routine returns.
** Without the isUpdate flag, the "base" cursor might be moved.
*/
void sqliteGenerateConstraintChecks(
Parse *pParse, /* The parser context */
Table *pTab, /* the table into which we are inserting */
int base, /* Index of a read/write cursor pointing at pTab */
char *aIdxUsed, /* Which indices are used. NULL means all are used */
int overrideError, /* Override onError to this if not OE_Default */
int ignoreDest, /* Jump to this label on an OE_Ignore resolution */
int isUpdate /* True for UPDATE, False for INSERT */
){
int i;
Vdbe *v;
int nCol;
int onError;
int addr;
int extra;
char *pToFree = 0;
int seenIgnore = 0;
v = sqliteGetVdbe(pParse);
assert( v!=0 );
nCol = pTab->nCol;
/* Test all NOT NULL constraints.
*/
for(i=0; i<nCol; i++){
onError = pTab->aCol[i].notNull;
if( i==iPKey || onError==OE_None ) continue;
if( overrideError!=OE_Default ){
onError = overrideError;
}
if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){
onError = OE_Abort;
}
addr = sqliteVdbeAddOp(v, OP_Dup, nCol-i, 1);
sqliteVdbeAddOp(v, OP_NotNull, 0, addr+1+(onError!=OE_Abort));
switch( onError ){
case OE_Abort: {
sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, 0);
break;
}
case OE_Ignore: {
sqliteVdbeAddOp(v, OP_Pop, nCol+1, 0);
sqliteVdbeAddOp(v, OP_GoTo, 0, ignoreDest);
break;
}
case OE_Replace: {
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC);
sqliteVdbeAddOp(v, OP_Push, nCol-i, 0);
break;
}
default: {
CANT_HAPPEN;
}
}
}
/* Test all CHECK constraints
*/
/* Test all UNIQUE constraints. Add index records as we go.
*/
extra = 0;
for(extra=(-1), iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
int jumpInst;
int contAddr;
if( aIdxUsed && aIdxUsed[iCur]==0 ) continue;
extra++;
sqliteVdbeAddOp(v, OP_Dup, nCol+extra, 1);
for(i=0; i<pIdx->nColumn; i++){
int idx = pIdx->aiColumn[i];
if( idx==pTab->iPKey ){
sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol+1, 0);
}else{
sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 0);
}
}
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
onError = pIdx->onError;
if( onError==OE_None ) continue;
if( overrideError!=OE_Default ){
onError = overrideError;
}
jumpInst = sqliteVdbeAddOp(v, OP_IsUnique, iCur, 0);
switch( onError ){
case OE_Abort: {
sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, 0);
break;
}
case OE_Ignore: {
sqliteVdbeAddOp(v, OP_Pop, nCol+extra+2, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
seenIgnore = 1;
break;
}
case OE_Replace: {
assert( seenIgnore==0 );
sqliteGenerateRowDelete(v, pTab, base);
if( isUpdate ){
sqliteVdbeAddOp(v, OP_Dup, nCol+extra+2, 1);
sqliteVdbeAddOp(v, OP_Moveto, base, 0);
}
break;
}
default: CANT_HAPPEN;
}
contAddr = sqliteVdbeCurrentAddr(v);
sqliteVdbeChangeP2(v, jumpInst, contAddr);
}
}
#endif

View File

@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.42 2002/01/06 17:07:40 drh Exp $
** @(#) $Id: parse.y,v 1.43 2002/01/29 18:41:25 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@ -103,6 +103,10 @@ id(A) ::= ID(X). {A = X;}
id(A) ::= TEMP(X). {A = X;}
id(A) ::= OFFSET(X). {A = X;}
id(A) ::= KEY(X). {A = X;}
id(A) ::= ABORT(X). {A = X;}
id(A) ::= IGNORE(X). {A = X;}
id(A) ::= REPLACE(X). {A = X;}
id(A) ::= CONFLICT(X). {A = X;}
// And "ids" is an identifer-or-string.
//
@ -138,10 +142,10 @@ carg ::= DEFAULT NULL.
// In addition to the type name, we also care about the primary key and
// UNIQUE constraints.
//
ccons ::= NOT NULL. {sqliteAddNotNull(pParse);}
ccons ::= PRIMARY KEY sortorder. {sqliteAddPrimaryKey(pParse, 0);}
ccons ::= UNIQUE. {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
ccons ::= CHECK LP expr RP.
ccons ::= NOT NULL onconf(R). {sqliteAddNotNull(pParse, R);}
ccons ::= PRIMARY KEY sortorder onconf(R). {sqliteAddPrimaryKey(pParse,0,R);}
ccons ::= UNIQUE onconf(R). {sqliteCreateIndex(pParse,0,0,0,R,0,0);}
ccons ::= CHECK LP expr RP onconf.
// For the time being, the only constraint we care about is the primary
// key and UNIQUE. Both create indices.
@ -152,9 +156,25 @@ conslist ::= conslist COMMA tcons.
conslist ::= conslist tcons.
conslist ::= tcons.
tcons ::= CONSTRAINT ids.
tcons ::= PRIMARY KEY LP idxlist(X) RP. {sqliteAddPrimaryKey(pParse,X);}
tcons ::= UNIQUE LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
tcons ::= CHECK expr.
tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R).
{sqliteAddPrimaryKey(pParse,X,R);}
tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
{sqliteCreateIndex(pParse,0,0,X,R,0,0);}
tcons ::= CHECK expr onconf.
// The following is a non-standard extension that allows us to declare the
// default behavior when there is a constraint conflict.
//
%type onconf {int}
%type onconf_u {int}
%type confresolve {int}
onconf(A) ::= confresolve(X). { A = X; }
onconf(A) ::= onconf_u(X). { A = X; }
onconf_u(A) ::= ON CONFLICT confresolve(X). { A = X; }
onconf_u(A) ::= . { A = OE_Default; }
confresolve(A) ::= ABORT. { A = OE_Abort; }
confresolve(A) ::= IGNORE. { A = OE_Ignore; }
confresolve(A) ::= REPLACE. { A = OE_Replace; }
////////////////////////// The DROP TABLE /////////////////////////////////////
//
@ -293,8 +313,8 @@ where_opt(A) ::= WHERE expr(X). {A = X;}
////////////////////////// The UPDATE command ////////////////////////////////
//
cmd ::= UPDATE ids(X) SET setlist(Y) where_opt(Z).
{sqliteUpdate(pParse,&X,Y,Z);}
cmd ::= UPDATE onconf_u(R) ids(X) SET setlist(Y) where_opt(Z).
{sqliteUpdate(pParse,&X,Y,Z,R);}
setlist(A) ::= setlist(Z) COMMA ids(X) EQ expr(Y).
{A = sqliteExprListAppend(Z,Y,&X);}
@ -302,10 +322,10 @@ setlist(A) ::= ids(X) EQ expr(Y). {A = sqliteExprListAppend(0,Y,&X);}
////////////////////////// The INSERT command /////////////////////////////////
//
cmd ::= INSERT INTO ids(X) inscollist_opt(F) VALUES LP itemlist(Y) RP.
{sqliteInsert(pParse, &X, Y, 0, F);}
cmd ::= INSERT INTO ids(X) inscollist_opt(F) select(S).
{sqliteInsert(pParse, &X, 0, S, F);}
cmd ::= INSERT onconf(R) INTO ids(X) inscollist_opt(F) VALUES LP itemlist(Y) RP.
{sqliteInsert(pParse, &X, Y, 0, F, R);}
cmd ::= INSERT onconf(R) INTO ids(X) inscollist_opt(F) select(S).
{sqliteInsert(pParse, &X, 0, S, F, R);}
%type itemlist {ExprList*}
@ -499,12 +519,16 @@ expritem(A) ::= . {A = 0;}
///////////////////////////// The CREATE INDEX command ///////////////////////
//
cmd ::= CREATE(S) uniqueflag(U) INDEX ids(X) ON ids(Y) LP idxlist(Z) RP(E).
{sqliteCreateIndex(pParse, &X, &Y, Z, U, &S, &E);}
cmd ::= CREATE(S) uniqueflag(U) INDEX ids(X)
ON ids(Y) LP idxlist(Z) RP(E) onconf(R). {
if( U!=OE_None ) U = R;
if( U==OE_Default) U = OE_Abort;
sqliteCreateIndex(pParse, &X, &Y, Z, U, &S, &E);
}
%type uniqueflag {int}
uniqueflag(A) ::= UNIQUE. { A = 1; }
uniqueflag(A) ::= . { A = 0; }
uniqueflag(A) ::= UNIQUE. { A = OE_Abort; }
uniqueflag(A) ::= . { A = OE_None; }
%type idxlist {IdList*}
%destructor idxlist {sqliteIdListDelete($$);}

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.79 2002/01/22 14:11:29 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.80 2002/01/29 18:41:25 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
@ -233,8 +233,24 @@ struct Table {
u8 isCommit; /* True if creation of this table has been committed */
u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */
u8 hasPrimKey; /* True if there exists a primary key */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
};
/*
** SQLite supports three different ways to resolve a UNIQUE contraint
** error. (1) It can abort the transaction return SQLITE_CONSTRAINT.
** (2) It can decide to not do the INSERT or UPDATE that was causing
** the constraint violation. (3) It can delete existing records from
** the table so that the pending INSERT or UPDATE will work without
** a constraint error. The following there symbolic values are used
** to record which type of action to take.
*/
#define OE_None 0 /* There is no constraint to check */
#define OE_Abort 1 /* Abort and rollback. */
#define OE_Ignore 2 /* Ignore the error. Do not do the INSERT or UPDATE */
#define OE_Replace 3 /* Delete existing record, then do INSERT or UPDATE */
#define OE_Default 9 /* Do whatever the default action is */
/*
** Each SQL index is represented in memory by an
** instance of the following structure.
@ -260,9 +276,10 @@ struct Index {
int *aiColumn; /* Which columns are used by this index. 1st is 0 */
Table *pTable; /* The SQL table being indexed */
int tnum; /* Page containing root of this index in database file */
u8 isUnique; /* True if keys must all be unique */
u8 isUnique; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
u8 isCommit; /* True if creation of this index has been committed */
u8 isDropped; /* True if a DROP INDEX has executed on this index */
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
Index *pNext; /* The next index associated with the same table */
};
@ -483,13 +500,14 @@ void sqliteCommitInternalChanges(sqlite*);
void sqliteRollbackInternalChanges(sqlite*);
void sqliteStartTable(Parse*,Token*,Token*,int);
void sqliteAddColumn(Parse*,Token*);
void sqliteAddNotNull(Parse*);
void sqliteAddNotNull(Parse*, int);
void sqliteAddPrimaryKey(Parse*, IdList*, int);
void sqliteAddColumnType(Parse*,Token*,Token*);
void sqliteAddDefaultValue(Parse*,Token*,int);
void sqliteEndTable(Parse*,Token*);
void sqliteDropTable(Parse*, Token*);
void sqliteDeleteTable(sqlite*, Table*);
void sqliteInsert(Parse*, Token*, ExprList*, Select*, IdList*);
void sqliteInsert(Parse*, Token*, ExprList*, Select*, IdList*, int);
IdList *sqliteIdListAppend(IdList*, Token*);
void sqliteIdListAddAlias(IdList*, Token*);
void sqliteIdListDelete(IdList*);
@ -500,7 +518,7 @@ Select *sqliteSelectNew(ExprList*,IdList*,Expr*,ExprList*,Expr*,ExprList*,
int,int,int);
void sqliteSelectDelete(Select*);
void sqliteDeleteFrom(Parse*, Token*, Expr*);
void sqliteUpdate(Parse*, Token*, ExprList*, Expr*);
void sqliteUpdate(Parse*, Token*, ExprList*, Expr*, int);
WhereInfo *sqliteWhereBegin(Parse*, IdList*, Expr*, int);
void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*);

View File

@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.32 2001/11/06 04:00:19 drh Exp $
** $Id: tokenize.c,v 1.33 2002/01/29 18:41:25 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -38,6 +38,7 @@ struct Keyword {
** These are the keywords
*/
static Keyword aKeywordTable[] = {
{ "ABORT", 0, TK_ABORT, 0 },
{ "ALL", 0, TK_ALL, 0 },
{ "AND", 0, TK_AND, 0 },
{ "AS", 0, TK_AS, 0 },
@ -48,6 +49,7 @@ static Keyword aKeywordTable[] = {
{ "CHECK", 0, TK_CHECK, 0 },
{ "CLUSTER", 0, TK_CLUSTER, 0 },
{ "COMMIT", 0, TK_COMMIT, 0 },
{ "CONFLICT", 0, TK_CONFLICT, 0 },
{ "CONSTRAINT", 0, TK_CONSTRAINT, 0 },
{ "COPY", 0, TK_COPY, 0 },
{ "CREATE", 0, TK_CREATE, 0 },
@ -64,6 +66,7 @@ static Keyword aKeywordTable[] = {
{ "GLOB", 0, TK_GLOB, 0 },
{ "GROUP", 0, TK_GROUP, 0 },
{ "HAVING", 0, TK_HAVING, 0 },
{ "IGNORE", 0, TK_IGNORE, 0 },
{ "IN", 0, TK_IN, 0 },
{ "INDEX", 0, TK_INDEX, 0 },
{ "INSERT", 0, TK_INSERT, 0 },
@ -83,6 +86,7 @@ static Keyword aKeywordTable[] = {
{ "ORDER", 0, TK_ORDER, 0 },
{ "PRAGMA", 0, TK_PRAGMA, 0 },
{ "PRIMARY", 0, TK_PRIMARY, 0 },
{ "REPLACE", 0, TK_REPLACE, 0 },
{ "ROLLBACK", 0, TK_ROLLBACK, 0 },
{ "SELECT", 0, TK_SELECT, 0 },
{ "SET", 0, TK_SET, 0 },

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.28 2002/01/28 15:53:05 drh Exp $
** $Id: update.c,v 1.29 2002/01/29 18:41:25 drh Exp $
*/
#include "sqliteInt.h"
@ -23,7 +23,8 @@ void sqliteUpdate(
Parse *pParse, /* The parser context */
Token *pTableName, /* The table in which we should change things */
ExprList *pChanges, /* Things to be changed */
Expr *pWhere /* The WHERE clause. May be null */
Expr *pWhere, /* The WHERE clause. May be null */
int onError /* How to handle constraint errors */
){
int i, j; /* Loop counters */
Table *pTab; /* The table to be updated */

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

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.38 2002/01/28 15:53:05 drh Exp $
** $Id: vdbe.h,v 1.39 2002/01/29 18:41:25 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@ -89,117 +89,119 @@ typedef struct VdbeOp VdbeOp;
#define OP_Distinct 17
#define OP_Found 18
#define OP_NotFound 19
#define OP_NotExists 20
#define OP_Delete 21
#define OP_Column 22
#define OP_KeyAsData 23
#define OP_Recno 24
#define OP_FullKey 25
#define OP_Rewind 26
#define OP_Next 27
#define OP_IsUnique 20
#define OP_NotExists 21
#define OP_Delete 22
#define OP_Column 23
#define OP_KeyAsData 24
#define OP_Recno 25
#define OP_FullKey 26
#define OP_Rewind 27
#define OP_Next 28
#define OP_Destroy 28
#define OP_Clear 29
#define OP_CreateIndex 30
#define OP_CreateTable 31
#define OP_Reorganize 32
#define OP_Destroy 29
#define OP_Clear 30
#define OP_CreateIndex 31
#define OP_CreateTable 32
#define OP_Reorganize 33
#define OP_IdxPut 33
#define OP_IdxDelete 34
#define OP_IdxRecno 35
#define OP_IdxGT 36
#define OP_IdxGE 37
#define OP_IdxPut 34
#define OP_IdxDelete 35
#define OP_IdxRecno 36
#define OP_IdxGT 37
#define OP_IdxGE 38
#define OP_MemLoad 38
#define OP_MemStore 39
#define OP_MemLoad 39
#define OP_MemStore 40
#define OP_ListWrite 40
#define OP_ListRewind 41
#define OP_ListRead 42
#define OP_ListReset 43
#define OP_ListWrite 41
#define OP_ListRewind 42
#define OP_ListRead 43
#define OP_ListReset 44
#define OP_SortPut 44
#define OP_SortMakeRec 45
#define OP_SortMakeKey 46
#define OP_Sort 47
#define OP_SortNext 48
#define OP_SortCallback 49
#define OP_SortReset 50
#define OP_SortPut 45
#define OP_SortMakeRec 46
#define OP_SortMakeKey 47
#define OP_Sort 48
#define OP_SortNext 49
#define OP_SortCallback 50
#define OP_SortReset 51
#define OP_FileOpen 51
#define OP_FileRead 52
#define OP_FileColumn 53
#define OP_FileOpen 52
#define OP_FileRead 53
#define OP_FileColumn 54
#define OP_AggReset 54
#define OP_AggFocus 55
#define OP_AggIncr 56
#define OP_AggNext 57
#define OP_AggSet 58
#define OP_AggGet 59
#define OP_AggReset 55
#define OP_AggFocus 56
#define OP_AggIncr 57
#define OP_AggNext 58
#define OP_AggSet 59
#define OP_AggGet 60
#define OP_SetInsert 60
#define OP_SetFound 61
#define OP_SetNotFound 62
#define OP_SetInsert 61
#define OP_SetFound 62
#define OP_SetNotFound 63
#define OP_MakeRecord 63
#define OP_MakeKey 64
#define OP_MakeIdxKey 65
#define OP_IncrKey 66
#define OP_MakeRecord 64
#define OP_MakeKey 65
#define OP_MakeIdxKey 66
#define OP_IncrKey 67
#define OP_Goto 67
#define OP_If 68
#define OP_Halt 69
#define OP_Goto 68
#define OP_If 69
#define OP_Halt 70
#define OP_ColumnCount 70
#define OP_ColumnName 71
#define OP_Callback 72
#define OP_NullCallback 73
#define OP_ColumnCount 71
#define OP_ColumnName 72
#define OP_Callback 73
#define OP_NullCallback 74
#define OP_Integer 74
#define OP_String 75
#define OP_Pop 76
#define OP_Dup 77
#define OP_Pull 78
#define OP_MustBeInt 79
#define OP_Integer 75
#define OP_String 76
#define OP_Pop 77
#define OP_Dup 78
#define OP_Pull 79
#define OP_Push 80
#define OP_MustBeInt 81
#define OP_Add 80
#define OP_AddImm 81
#define OP_Subtract 82
#define OP_Multiply 83
#define OP_Divide 84
#define OP_Remainder 85
#define OP_BitAnd 86
#define OP_BitOr 87
#define OP_BitNot 88
#define OP_ShiftLeft 89
#define OP_ShiftRight 90
#define OP_AbsValue 91
#define OP_Precision 92
#define OP_Min 93
#define OP_Max 94
#define OP_Like 95
#define OP_Glob 96
#define OP_Eq 97
#define OP_Ne 98
#define OP_Lt 99
#define OP_Le 100
#define OP_Gt 101
#define OP_Ge 102
#define OP_IsNull 103
#define OP_NotNull 104
#define OP_Negative 105
#define OP_And 106
#define OP_Or 107
#define OP_Not 108
#define OP_Concat 109
#define OP_Noop 110
#define OP_Add 82
#define OP_AddImm 83
#define OP_Subtract 84
#define OP_Multiply 85
#define OP_Divide 86
#define OP_Remainder 87
#define OP_BitAnd 88
#define OP_BitOr 89
#define OP_BitNot 90
#define OP_ShiftLeft 91
#define OP_ShiftRight 92
#define OP_AbsValue 93
#define OP_Precision 94
#define OP_Min 95
#define OP_Max 96
#define OP_Like 97
#define OP_Glob 98
#define OP_Eq 99
#define OP_Ne 100
#define OP_Lt 101
#define OP_Le 102
#define OP_Gt 103
#define OP_Ge 104
#define OP_IsNull 105
#define OP_NotNull 106
#define OP_Negative 107
#define OP_And 108
#define OP_Or 109
#define OP_Not 110
#define OP_Concat 111
#define OP_Noop 112
#define OP_Strlen 111
#define OP_Substr 112
#define OP_Strlen 113
#define OP_Substr 114
#define OP_Limit 113
#define OP_Limit 115
#define OP_MAX 113
#define OP_MAX 115
/*
** Prototypes for the VDBE interface. See comments on the implementation
@ -210,6 +212,7 @@ void sqliteVdbeCreateCallback(Vdbe*, int*);
int sqliteVdbeAddOp(Vdbe*,int,int,int);
int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOp const *aOp);
void sqliteVdbeChangeP1(Vdbe*, int addr, int P1);
void sqliteVdbeChangeP2(Vdbe*, int addr, int P2);
void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
void sqliteVdbeDequoteP3(Vdbe*, int addr);
int sqliteVdbeMakeLabel(Vdbe*);

View File

@ -1,7 +1,7 @@
#
# Run this TCL script to generate HTML for the index.html file.
#
set rcsid {$Id: index.tcl,v 1.51 2002/01/09 13:35:11 drh Exp $}
set rcsid {$Id: index.tcl,v 1.52 2002/01/29 18:41:26 drh Exp $}
puts {<html>
<head><title>SQLite: An SQL Database Engine In A C Library</title></head>
@ -65,7 +65,7 @@ puts {<h2>Current Status</h2>
The latest source code is
<a href="download.html">available for download</a>.
There are currently no known memory leaks or bugs
in version 2.2.1 of the library.
in version 2.2.5 of the library.
</p>
<p>