mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Parse foreign key constraints and populate internal data structures
appropriately. Constraints are still not enforced. (CVS 738) FossilOrigin-Name: 170711ca65dc894d0486b9d575edb8f1708250fb
This commit is contained in:
31
manifest
31
manifest
@@ -1,5 +1,5 @@
|
||||
C Version\s2.7.1\s(CVS\s737)
|
||||
D 2002-08-31T17:02:43
|
||||
C Parse\sforeign\skey\sconstraints\sand\spopulate\sinternal\sdata\sstructures\nappropriately.\s\sConstraints\sare\sstill\snot\senforced.\s(CVS\s738)
|
||||
D 2002-08-31T18:53:06
|
||||
F Makefile.in 420fada882179cb72ffd07313f3fd693f9f06640
|
||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||
@@ -20,7 +20,7 @@ F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e
|
||||
F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
|
||||
F src/btree.c 9e21606581a5a4a5b18ad304d7a4f433101f1538
|
||||
F src/btree.h 0ca6c2631338df62e4f7894252d9347ae234eda9
|
||||
F src/build.c b367b4a839f978c0225d984e327287852835948e
|
||||
F src/build.c 0116afe4f67687206364c4d1e88dc07aefc661de
|
||||
F src/delete.c c9f59ee217e062eb9de7b64b76b5cfff42b2f028
|
||||
F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
|
||||
F src/expr.c ee027b908a1e157fc21644121811fa6ec1eec798
|
||||
@@ -28,25 +28,25 @@ F src/func.c e45cd908b9b723d9b91473d09e12c23f786b3fc2
|
||||
F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
|
||||
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
|
||||
F src/insert.c a2f5455009904476b43ec5304a181b505235f72f
|
||||
F src/main.c 26a31201133c93b6065e11b49a83f5b987642e96
|
||||
F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b
|
||||
F src/main.c 46d6a88070974360918cdfd1241b1906c6e189ce
|
||||
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
|
||||
F src/os.c 00d10655e1dc9a52b4aabca58c8d8e45048057b0
|
||||
F src/os.h 3009379b06941e7796a9812d1b6cbc59b26248c8
|
||||
F src/pager.c 4b0169e91b34f6ff91e8feb57545c43e4d6eb370
|
||||
F src/pager.h 6991c9c2dc5e4c7f2df4d4ba47d1c6458f763a32
|
||||
F src/parse.y 1b180e14b6346e323bd4279469748716f412cc1c
|
||||
F src/parse.y 818b03a73f6b3b8b284b515c5b1d9998d4663dc3
|
||||
F src/printf.c 5c50fc1da75c8f5bf432b1ad17d91d6653acd167
|
||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||
F src/select.c 6cd3673edbb36a8f8027341093085e01c04dd3d4
|
||||
F src/shell.c 9e9a6eb6bca07f01e6472a603f908a0127ea50ff
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in d3999a9c6374675779058d6cfe5431131618e92b
|
||||
F src/sqliteInt.h 4d42c8685693ecf9d99edf52c9a404da2b2df7fd
|
||||
F src/sqliteInt.h 62177a08d332148b1d69cd040840aac45ad86a42
|
||||
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
|
||||
F src/tclsqlite.c c502819c209011659e1bbb428cbac5670cce7f79
|
||||
F src/test1.c 456cb080db85056be723e770435d9509afc3a83a
|
||||
F src/test2.c 279057a854359665b89122070ac1fc472acce1b2
|
||||
F src/test3.c b99d5ab68ee672f1fbb00520723b5c21bac35822
|
||||
F src/tclsqlite.c e6c6de6ce41614b9ae82161ed998308070a5790d
|
||||
F src/test1.c a46e9f61915b32787c5d5a05a4b92e4dacc437d9
|
||||
F src/test2.c 5fa694d130b3309e3f9c852f0a437750fcb5a006
|
||||
F src/test3.c 540fa7fc3cb3732517b779b5f90ad9cc4303d0ab
|
||||
F src/threadtest.c 72bce0a284647314847bbea44616ceb056bfb77f
|
||||
F src/tokenize.c 62c98842447effe92eba9622bb2f9a2a8a4b97ad
|
||||
F src/trigger.c c90a292a4bef25e478fd5deda6d300319be6a023
|
||||
@@ -64,6 +64,7 @@ F test/conflict.test 0173a12a257f73bac2c9d53ad44cac9b15ea517e
|
||||
F test/copy.test 55d60a4d5ed342a0fa08b7cd07d46d43ea0d0d7f
|
||||
F test/delete.test 5821a95a66061ae09723a88938f23d10d8a881ad
|
||||
F test/expr.test dea1cd62684a8bf116426447c948f5e8fb2c84b6
|
||||
F test/fkey1.test 33c850201a6ec35f0b370daf4e57f44456f1b35d
|
||||
F test/format3.test cbb168d446152fcf1dd85be299ad2d6cd507da4e
|
||||
F test/func.test bed7ae7a3482df05db0f5eed2debdf25ac2d07fc
|
||||
F test/in.test e59461f1702b7387880bf08a0ce6bb777925d282
|
||||
@@ -97,7 +98,7 @@ F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac
|
||||
F test/select6.test efb8d0c07a440441db87db2c4ade6904e1407e85
|
||||
F test/sort.test 876b76c5a837af5bead713146c7c65f85e84fbf5
|
||||
F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
|
||||
F test/table.test dedb4d3a73340d811e309672ca14537daa542fb1
|
||||
F test/table.test 10508e5e53fb7971b9fa6acb29d85748e545745c
|
||||
F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6
|
||||
F test/tclsqlite.test 6f4b9760681c7dbca52a18d0ab46a1679cdc79b9
|
||||
F test/temptable.test 9ed7ec0288f887e132de66d90c428ad109105f67
|
||||
@@ -149,7 +150,7 @@ F www/speed.tcl a20a792738475b68756ea7a19321600f23d1d803
|
||||
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
|
||||
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||
P b7f788fcc4a26ae42196a209d2e94672321dc154
|
||||
R c5c569997115d1f2c07a9211654c4fdd
|
||||
P 5f51e13d56a58d7c263043cae9898d796017a369
|
||||
R 5f57a541da1cc0eea6b8b3a2339bca70
|
||||
U drh
|
||||
Z 53b53adb384374736e4596208d092298
|
||||
Z 53eaaf70a55382e9bd46cf1caade9346
|
||||
|
@@ -1 +1 @@
|
||||
5f51e13d56a58d7c263043cae9898d796017a369
|
||||
170711ca65dc894d0486b9d575edb8f1708250fb
|
186
src/build.c
186
src/build.c
@@ -25,7 +25,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.110 2002/08/24 18:24:53 drh Exp $
|
||||
** $Id: build.c,v 1.111 2002/08/31 18:53:06 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -152,6 +152,7 @@ void sqliteResetInternalSchema(sqlite *db){
|
||||
Hash temp1;
|
||||
Hash temp2;
|
||||
|
||||
sqliteHashClear(&db->aFKey);
|
||||
temp1 = db->tblHash;
|
||||
temp2 = db->trigHash;
|
||||
sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0);
|
||||
@@ -194,8 +195,10 @@ void sqliteCommitInternalChanges(sqlite *db){
|
||||
** Table. No changes are made to disk by this routine.
|
||||
**
|
||||
** This routine just deletes the data structure. It does not unlink
|
||||
** the table data structure from the hash table. But it does destroy
|
||||
** memory structures of the indices associated with the table.
|
||||
** the table data structure from the hash table. Nor does it remove
|
||||
** foreign keys from the sqlite.aFKey hash table. But it does destroy
|
||||
** memory structures of the indices and foreign keys associated with
|
||||
** the table.
|
||||
**
|
||||
** Indices associated with the table are unlinked from the "db"
|
||||
** data structure if db!=NULL. If db==NULL, indices attached to
|
||||
@@ -205,16 +208,33 @@ void sqliteCommitInternalChanges(sqlite *db){
|
||||
void sqliteDeleteTable(sqlite *db, Table *pTable){
|
||||
int i;
|
||||
Index *pIndex, *pNext;
|
||||
FKey *pFKey, *pNextFKey;
|
||||
|
||||
if( pTable==0 ) return;
|
||||
|
||||
/* Delete all indices associated with this table
|
||||
*/
|
||||
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
|
||||
pNext = pIndex->pNext;
|
||||
sqliteDeleteIndex(db, pIndex);
|
||||
}
|
||||
|
||||
/* Delete all foreign keys associated with this table. The keys
|
||||
** should have already been unlinked from the db->aFKey hash table
|
||||
*/
|
||||
for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
|
||||
pNextFKey = pFKey->pNextFrom;
|
||||
assert( sqliteHashFind(&db->aFKey,pFKey->zTo,strlen(pFKey->zTo)+1)!=pFKey );
|
||||
sqliteFree(pFKey);
|
||||
}
|
||||
|
||||
/* Delete the Table structure itself.
|
||||
*/
|
||||
for(i=0; i<pTable->nCol; i++){
|
||||
sqliteFree(pTable->aCol[i].zName);
|
||||
sqliteFree(pTable->aCol[i].zDflt);
|
||||
sqliteFree(pTable->aCol[i].zType);
|
||||
}
|
||||
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
|
||||
pNext = pIndex->pNext;
|
||||
sqliteDeleteIndex(db, pIndex);
|
||||
}
|
||||
sqliteFree(pTable->zName);
|
||||
sqliteFree(pTable->aCol);
|
||||
sqliteSelectDelete(pTable->pSelect);
|
||||
@@ -223,13 +243,26 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){
|
||||
|
||||
/*
|
||||
** Unlink the given table from the hash tables and the delete the
|
||||
** table structure with all its indices.
|
||||
** table structure with all its indices and foreign keys.
|
||||
*/
|
||||
static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *p){
|
||||
Table *pOld;
|
||||
FKey *pF1, *pF2;
|
||||
assert( db!=0 );
|
||||
pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, 0);
|
||||
assert( pOld==0 || pOld==p );
|
||||
for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){
|
||||
int nTo = strlen(pF1->zTo) + 1;
|
||||
pF2 = sqliteHashFind(&db->aFKey, pF1->zTo, nTo);
|
||||
if( pF2==pF1 ){
|
||||
sqliteHashInsert(&db->aFKey, pF1->zTo, nTo, pF1->pNextTo);
|
||||
}else{
|
||||
while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; }
|
||||
if( pF2 ){
|
||||
pF2->pNextTo = pF1->pNextTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqliteDeleteTable(db, p);
|
||||
}
|
||||
|
||||
@@ -739,11 +772,17 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
|
||||
assert( pParse->nameClash==0 || pParse->initFlag==1 );
|
||||
if( pParse->explain==0 && pParse->nameClash==0 ){
|
||||
Table *pOld;
|
||||
FKey *pFKey;
|
||||
pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p);
|
||||
if( pOld ){
|
||||
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
|
||||
return;
|
||||
}
|
||||
for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
||||
int nTo = strlen(pFKey->zTo) + 1;
|
||||
pFKey->pNextTo = sqliteHashFind(&db->aFKey, pFKey->zTo, nTo);
|
||||
sqliteHashInsert(&db->aFKey, pFKey->zTo, nTo, pFKey);
|
||||
}
|
||||
pParse->pNewTable = 0;
|
||||
db->nTable++;
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
@@ -1141,6 +1180,137 @@ void sqliteAddIdxKeyType(Vdbe *v, Index *pIdx){
|
||||
sqliteFree(zType);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called to create a new foreign key on the table
|
||||
** currently under construction. pFromCol determines which columns
|
||||
** in the current table point to the foreign key. If pFromCol==0 then
|
||||
** connect the key to the last column inserted. pTo is the name of
|
||||
** the table referred to. pToCol is a list of tables in the other
|
||||
** pTo table that the foreign key points to. flags contains all
|
||||
** information about the conflict resolution algorithms specified
|
||||
** in the ON DELETE, ON UPDATE and ON INSERT clauses.
|
||||
**
|
||||
** An FKey structure is created and added to the table currently
|
||||
** under construction in the pParse->pNewTable field. The new FKey
|
||||
** is not linked into db->aFKey at this point - that does not happen
|
||||
** until sqliteEndTable().
|
||||
**
|
||||
** The foreign key is set for IMMEDIATE processing. A subsequent call
|
||||
** to sqliteDeferForeignKey() might change this to DEFERRED.
|
||||
*/
|
||||
void sqliteCreateForeignKey(
|
||||
Parse *pParse, /* Parsing context */
|
||||
IdList *pFromCol, /* Columns in this table that point to other table */
|
||||
Token *pTo, /* Name of the other table */
|
||||
IdList *pToCol, /* Columns in the other table */
|
||||
int flags /* Conflict resolution algorithms. */
|
||||
){
|
||||
Table *p = pParse->pNewTable;
|
||||
int nByte;
|
||||
int i;
|
||||
int nCol;
|
||||
char *z;
|
||||
FKey *pFKey = 0;
|
||||
|
||||
assert( pTo!=0 );
|
||||
if( p==0 || pParse->nErr ) goto fk_end;
|
||||
if( pFromCol==0 ){
|
||||
int iCol = p->nCol-1;
|
||||
if( iCol<0 ) goto fk_end;
|
||||
if( pToCol && pToCol->nId!=1 ){
|
||||
sqliteSetNString(&pParse->zErrMsg, "foreign key on ", -1,
|
||||
p->aCol[iCol].zName, -1,
|
||||
" should reference only one column of table ", -1,
|
||||
pTo->z, pTo->n, 0);
|
||||
pParse->nErr++;
|
||||
goto fk_end;
|
||||
}
|
||||
nCol = 1;
|
||||
}else if( pToCol && pToCol->nId!=pFromCol->nId ){
|
||||
sqliteSetString(&pParse->zErrMsg,
|
||||
"number of columns in foreign key does not match the number of "
|
||||
"columns in the referenced table", 0);
|
||||
pParse->nErr++;
|
||||
goto fk_end;
|
||||
}else{
|
||||
nCol = pFromCol->nId;
|
||||
}
|
||||
nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1;
|
||||
if( pToCol ){
|
||||
for(i=0; i<pToCol->nId; i++){
|
||||
nByte += strlen(pToCol->a[i].zName) + 1;
|
||||
}
|
||||
}
|
||||
pFKey = sqliteMalloc( nByte );
|
||||
if( pFKey==0 ) goto fk_end;
|
||||
pFKey->pFrom = p;
|
||||
pFKey->pNextFrom = p->pFKey;
|
||||
pFKey->zTo = z = (char*)&pFKey[1];
|
||||
memcpy(z, pTo->z, pTo->n);
|
||||
z[pTo->n] = 0;
|
||||
z += pTo->n+1;
|
||||
pFKey->pNextTo = 0;
|
||||
pFKey->nCol = nCol;
|
||||
pFKey->aCol = (struct sColMap*)z;
|
||||
z += sizeof(struct sColMap)*nCol;
|
||||
if( pFromCol==0 ){
|
||||
pFKey->aCol[0].iFrom = p->nCol-1;
|
||||
}else{
|
||||
for(i=0; i<nCol; i++){
|
||||
int j;
|
||||
for(j=0; j<p->nCol; j++){
|
||||
if( sqliteStrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){
|
||||
pFKey->aCol[i].iFrom = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>=p->nCol ){
|
||||
sqliteSetString(&pParse->zErrMsg, "unknown column \"",
|
||||
pFromCol->a[i].zName, "\" in foreign key definition", 0);
|
||||
pParse->nErr++;
|
||||
goto fk_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pToCol ){
|
||||
for(i=0; i<nCol; i++){
|
||||
int n = strlen(pToCol->a[i].zName);
|
||||
pFKey->aCol[i].zCol = z;
|
||||
memcpy(z, pToCol->a[i].zName, n);
|
||||
z[n] = 0;
|
||||
z += n+1;
|
||||
}
|
||||
}
|
||||
pFKey->isDeferred = 0;
|
||||
pFKey->deleteConf = flags & 0xff;
|
||||
pFKey->updateConf = (flags >> 8 ) & 0xff;
|
||||
pFKey->insertConf = (flags >> 16 ) & 0xff;
|
||||
|
||||
/* Link the foreign key to the table as the last step.
|
||||
*/
|
||||
p->pFKey = pFKey;
|
||||
pFKey = 0;
|
||||
|
||||
fk_end:
|
||||
sqliteFree(pFKey);
|
||||
sqliteIdListDelete(pFromCol);
|
||||
sqliteIdListDelete(pToCol);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED
|
||||
** clause is seen as part of a foreign key definition. The isDeferred
|
||||
** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE.
|
||||
** The behavior of the most recently created foreign key is adjusted
|
||||
** accordingly.
|
||||
*/
|
||||
void sqliteDeferForeignKey(Parse *pParse, int isDeferred){
|
||||
Table *pTab;
|
||||
FKey *pFKey;
|
||||
if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return;
|
||||
pFKey->isDeferred = isDeferred;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new index for an SQL table. pIndex is the name of the index
|
||||
** and pTable is the name of the table that is to be indexed. Both will
|
||||
|
@@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.99 2002/08/29 23:59:48 drh Exp $
|
||||
** $Id: main.c,v 1.100 2002/08/31 18:53:06 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@@ -354,6 +354,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
|
||||
sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
|
||||
sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
|
||||
sqliteHashInit(&db->aFKey, SQLITE_HASH_STRING, 1);
|
||||
sqliteRegisterBuiltinFunctions(db);
|
||||
db->onError = OE_Default;
|
||||
db->priorNewRowid = 0;
|
||||
@@ -466,6 +467,7 @@ void sqlite_close(sqlite *db){
|
||||
}
|
||||
}
|
||||
sqliteHashClear(&db->aFunc);
|
||||
sqliteHashClear(&db->aFKey);
|
||||
sqliteFree(db);
|
||||
}
|
||||
|
||||
|
@@ -293,7 +293,7 @@ static void DigestToBase16(unsigned char *digest, char *zBuf){
|
||||
** A TCL command for md5. The argument is the text to be hashed. The
|
||||
** Result is the hash in base64.
|
||||
*/
|
||||
static int md5_cmd(ClientData cd, Tcl_Interp *interp, int argc, char **argv){
|
||||
static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
|
||||
MD5Context ctx;
|
||||
unsigned char digest[16];
|
||||
|
||||
@@ -313,7 +313,7 @@ static int md5_cmd(ClientData cd, Tcl_Interp *interp, int argc, char **argv){
|
||||
** A TCL command to take the md5 hash of a file. The argument is the
|
||||
** name of the file.
|
||||
*/
|
||||
static int md5file_cmd(ClientData cd, Tcl_Interp*interp, int argc, char **argv){
|
||||
static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
|
||||
FILE *in;
|
||||
MD5Context ctx;
|
||||
unsigned char digest[16];
|
||||
@@ -347,8 +347,8 @@ static int md5file_cmd(ClientData cd, Tcl_Interp*interp, int argc, char **argv){
|
||||
** Register the two TCL commands above with the TCL interpreter.
|
||||
*/
|
||||
int Md5_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateCommand(interp, "md5", md5_cmd, 0, 0);
|
||||
Tcl_CreateCommand(interp, "md5file", md5file_cmd, 0, 0);
|
||||
Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd, 0, 0);
|
||||
Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd, 0, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
72
src/parse.y
72
src/parse.y
@@ -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.82 2002/08/24 18:24:54 drh Exp $
|
||||
** @(#) $Id: parse.y,v 1.83 2002/08/31 18:53:07 drh Exp $
|
||||
*/
|
||||
%token_prefix TK_
|
||||
%token_type {Token}
|
||||
@@ -169,31 +169,38 @@ 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.
|
||||
ccons ::= references.
|
||||
ccons ::= defer_subclause.
|
||||
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
|
||||
{sqliteCreateForeignKey(pParse,0,&T,TA,R);}
|
||||
ccons ::= defer_subclause(D). {sqliteDeferForeignKey(pParse,D);}
|
||||
ccons ::= COLLATE id(C). {
|
||||
sqliteAddCollateType(pParse, sqliteCollateType(pParse, &C));
|
||||
}
|
||||
|
||||
// A REFERENCES clause is parsed but the current implementation does not
|
||||
// do anything with it.
|
||||
// The next group of rules parses the arguments to a REFERENCES clause
|
||||
// that determine if the referential integrity checking is deferred or
|
||||
// or immediate and which determine what action to take if a ref-integ
|
||||
// check fails.
|
||||
//
|
||||
references ::= REFERENCES nm LP idxlist RP refargs.
|
||||
references ::= REFERENCES nm refargs.
|
||||
refargs ::= .
|
||||
refargs ::= refargs refarg.
|
||||
refarg ::= MATCH nm.
|
||||
refarg ::= ON DELETE refact.
|
||||
refarg ::= ON UPDATE refact.
|
||||
refact ::= SET NULL.
|
||||
refact ::= SET DEFAULT.
|
||||
refact ::= CASCADE.
|
||||
refact ::= RESTRICT.
|
||||
defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt.
|
||||
defer_subclause ::= DEFERRABLE init_deferred_pred_opt.
|
||||
init_deferred_pred_opt ::= .
|
||||
init_deferred_pred_opt ::= INITIALLY DEFERRED.
|
||||
init_deferred_pred_opt ::= INITIALLY IMMEDIATE.
|
||||
%type refargs {int}
|
||||
refargs(A) ::= . { A = OE_Restrict * 0x010101; }
|
||||
refargs(A) ::= refargs(X) refarg(Y). { A = (X & Y.mask) | Y.value; }
|
||||
%type refarg {struct {int value; int mask;}}
|
||||
refarg(A) ::= MATCH nm. { A.value = 0; A.mask = 0x000000; }
|
||||
refarg(A) ::= ON DELETE refact(X). { A.value = X; A.mask = 0x0000ff; }
|
||||
refarg(A) ::= ON UPDATE refact(X). { A.value = X<<8; A.mask = 0x00ff00; }
|
||||
refarg(A) ::= ON INSERT refact(X). { A.value = X<<16; A.mask = 0xff0000; }
|
||||
%type refact {int}
|
||||
refact(A) ::= SET NULL. { A = OE_SetNull; }
|
||||
refact(A) ::= SET DEFAULT. { A = OE_SetDflt; }
|
||||
refact(A) ::= CASCADE. { A = OE_Cascade; }
|
||||
refact(A) ::= RESTRICT. { A = OE_Restrict; }
|
||||
%type defer_subclause {int}
|
||||
defer_subclause(A) ::= NOT DEFERRABLE init_deferred_pred_opt(X). {A = X;}
|
||||
defer_subclause(A) ::= DEFERRABLE init_deferred_pred_opt(X). {A = X;}
|
||||
%type init_deferred_pred_opt {int}
|
||||
init_deferred_pred_opt(A) ::= . {A = 0;}
|
||||
init_deferred_pred_opt(A) ::= INITIALLY DEFERRED. {A = 1;}
|
||||
init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE. {A = 0;}
|
||||
|
||||
// For the time being, the only constraint we care about is the primary
|
||||
// key and UNIQUE. Both create indices.
|
||||
@@ -209,9 +216,14 @@ tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R).
|
||||
tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
|
||||
{sqliteCreateIndex(pParse,0,0,X,R,0,0);}
|
||||
tcons ::= CHECK expr onconf.
|
||||
tcons ::= FOREIGN KEY LP idxlist RP references defer_subclause_opt.
|
||||
defer_subclause_opt ::= .
|
||||
defer_subclause_opt ::= defer_subclause.
|
||||
tcons ::= FOREIGN KEY LP idxlist(FA) RP
|
||||
REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
|
||||
sqliteCreateForeignKey(pParse, FA, &T, TA, R);
|
||||
sqliteDeferForeignKey(pParse, D);
|
||||
}
|
||||
%type defer_subclause_opt {int}
|
||||
defer_subclause_opt(A) ::= . {A = 0;}
|
||||
defer_subclause_opt(A) ::= defer_subclause(X). {A = X;}
|
||||
|
||||
// The following is a non-standard extension that allows us to declare the
|
||||
// default behavior when there is a constraint conflict.
|
||||
@@ -677,13 +689,15 @@ uniqueflag(A) ::= . { A = OE_None; }
|
||||
|
||||
%type idxlist {IdList*}
|
||||
%destructor idxlist {sqliteIdListDelete($$);}
|
||||
%type idxlist_opt {IdList*}
|
||||
%destructor idxlist_opt {sqliteIdListDelete($$);}
|
||||
%type idxitem {Token}
|
||||
|
||||
idxlist(A) ::= idxlist(X) COMMA idxitem(Y).
|
||||
{A = sqliteIdListAppend(X,&Y);}
|
||||
idxlist(A) ::= idxitem(Y).
|
||||
{A = sqliteIdListAppend(0,&Y);}
|
||||
idxitem(A) ::= nm(X). {A = X;}
|
||||
idxlist_opt(A) ::= . {A = 0;}
|
||||
idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
|
||||
idxlist(A) ::= idxlist(X) COMMA idxitem(Y). {A = sqliteIdListAppend(X,&Y);}
|
||||
idxlist(A) ::= idxitem(Y). {A = sqliteIdListAppend(0,&Y);}
|
||||
idxitem(A) ::= nm(X). {A = X;}
|
||||
|
||||
///////////////////////////// The DROP INDEX command /////////////////////////
|
||||
//
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.144 2002/08/28 03:00:59 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.145 2002/08/31 18:53:07 drh Exp $
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "hash.h"
|
||||
@@ -175,6 +175,7 @@ typedef struct FuncDef FuncDef;
|
||||
typedef struct Trigger Trigger;
|
||||
typedef struct TriggerStep TriggerStep;
|
||||
typedef struct TriggerStack TriggerStack;
|
||||
typedef struct FKey FKey;
|
||||
|
||||
/*
|
||||
** Each database is an instance of the following structure.
|
||||
@@ -206,6 +207,7 @@ struct sqlite {
|
||||
Hash idxHash; /* All (named) indices indexed by name */
|
||||
Hash trigHash; /* All triggers indexed by name */
|
||||
Hash aFunc; /* All functions that can be in SQL exprs */
|
||||
Hash aFKey; /* Foreign keys indexed by to-table */
|
||||
int lastRowid; /* ROWID of most recent insert */
|
||||
int priorNewRowid; /* Last randomly generated ROWID */
|
||||
int onError; /* Default conflict algorithm */
|
||||
@@ -330,10 +332,52 @@ struct Table {
|
||||
u8 hasPrimKey; /* True if there exists a primary key */
|
||||
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
|
||||
Trigger *pTrigger; /* List of SQL triggers on this table */
|
||||
FKey *pFKey; /* Linked list of all foreign keys in this table */
|
||||
};
|
||||
|
||||
/*
|
||||
** SQLite supports 5 different ways to resolve a contraint
|
||||
** Each foreign key constraint is an instance of the following structure.
|
||||
**
|
||||
** A foreign key is associated with two tables. The "from" table is
|
||||
** the table that contains the REFERENCES clause that creates the foreign
|
||||
** key. The "to" table is the table that is named in the REFERENCES clause.
|
||||
** Consider this example:
|
||||
**
|
||||
** CREATE TABLE ex1(
|
||||
** a INTEGER PRIMARY KEY,
|
||||
** b INTEGER CONSTRAINT fk1 REFERENCES ex2(x)
|
||||
** );
|
||||
**
|
||||
** For foreign key "fk1", the from-table is "ex1" and the to-table is "ex2".
|
||||
**
|
||||
** Each REFERENCES clause generates an instance of the following structure
|
||||
** which is attached to the from-table. The to-table need not exist when
|
||||
** the from-table is created. The existance of the to-table is not checked
|
||||
** until an attempt is made to insert data into the from-table.
|
||||
**
|
||||
** The sqlite.aFKey hash table stores pointers to to this structure
|
||||
** given the name of a to-table. For each to-table, all foreign keys
|
||||
** associated with that table are on a linked list using the FKey.pNextTo
|
||||
** field.
|
||||
*/
|
||||
struct FKey {
|
||||
Table *pFrom; /* The table that constains the REFERENCES clause */
|
||||
FKey *pNextFrom; /* Next foreign key in pFrom */
|
||||
char *zTo; /* Name of table that the key points to */
|
||||
FKey *pNextTo; /* Next foreign key that points to zTo */
|
||||
int nCol; /* Number of columns in this key */
|
||||
struct sColMap { /* Mapping of columns in pFrom to columns in zTo */
|
||||
int iFrom; /* Index of column in pFrom */
|
||||
char *zCol; /* Name of column in zTo. If 0 use PRIMARY KEY */
|
||||
} *aCol; /* One entry for each of nCol column s */
|
||||
u8 isDeferred; /* True if constraint checking is deferred till COMMIT */
|
||||
u8 updateConf; /* How to resolve conflicts that occur on UPDATE */
|
||||
u8 deleteConf; /* How to resolve conflicts that occur on DELETE */
|
||||
u8 insertConf; /* How to resolve conflicts that occur on INSERT */
|
||||
};
|
||||
|
||||
/*
|
||||
** SQLite supports many different ways to resolve a contraint
|
||||
** error. ROLLBACK processing means that a constraint violation
|
||||
** causes the operation in process to fail and for the current transaction
|
||||
** to be rolled back. ABORT processing means the operation in process
|
||||
@@ -347,6 +391,13 @@ struct Table {
|
||||
** a UNIQUE constraint violation are removed so that the new insert or
|
||||
** update can proceed. Processing continues and no error is reported.
|
||||
**
|
||||
** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys.
|
||||
** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the
|
||||
** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign
|
||||
** key is set to NULL. CASCADE means that a DELETE or UPDATE of the
|
||||
** referenced table row is propagated into the row that holds the
|
||||
** foreign key.
|
||||
**
|
||||
** The following there symbolic values are used to record which type
|
||||
** of action to take.
|
||||
*/
|
||||
@@ -356,7 +407,13 @@ struct Table {
|
||||
#define OE_Fail 3 /* Stop the operation but leave all prior changes */
|
||||
#define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */
|
||||
#define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */
|
||||
#define OE_Default 9 /* Do whatever the default action is */
|
||||
|
||||
#define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */
|
||||
#define OE_SetNull 7 /* Set the foreign key value to NULL */
|
||||
#define OE_SetDflt 8 /* Set the foreign key value to its default */
|
||||
#define OE_Cascade 9 /* Cascade the changes */
|
||||
|
||||
#define OE_Default 99 /* Do whatever the default action is */
|
||||
|
||||
/*
|
||||
** Each SQL index is represented in memory by an
|
||||
@@ -947,3 +1004,5 @@ TriggerStep *sqliteTriggerUpdateStep(Token*, ExprList*, Expr*, int);
|
||||
TriggerStep *sqliteTriggerDeleteStep(Token*, Expr*);
|
||||
void sqliteDeleteTrigger(Trigger*);
|
||||
int sqliteJoinType(Parse*, Token*, Token*, Token*);
|
||||
void sqliteCreateForeignKey(Parse*, IdList*, Token*, IdList*, int);
|
||||
void sqliteDeferForeignKey(Parse*, int);
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** A TCL Interface to SQLite
|
||||
**
|
||||
** $Id: tclsqlite.c,v 1.39 2002/07/15 20:58:48 drh Exp $
|
||||
** $Id: tclsqlite.c,v 1.40 2002/08/31 18:53:08 drh Exp $
|
||||
*/
|
||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||
|
||||
@@ -643,13 +643,13 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
|
||||
*/
|
||||
int Sqlite_Init(Tcl_Interp *interp){
|
||||
Tcl_InitStubs(interp, "8.0", 0);
|
||||
Tcl_CreateCommand(interp, "sqlite", DbMain, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite", (Tcl_CmdProc*)DbMain, 0, 0);
|
||||
Tcl_PkgProvide(interp, "sqlite", "2.0");
|
||||
return TCL_OK;
|
||||
}
|
||||
int Tclsqlite_Init(Tcl_Interp *interp){
|
||||
Tcl_InitStubs(interp, "8.0", 0);
|
||||
Tcl_CreateCommand(interp, "sqlite", DbMain, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite", (Tcl_CmdProc*)DbMain, 0, 0);
|
||||
Tcl_PkgProvide(interp, "sqlite", "2.0");
|
||||
return TCL_OK;
|
||||
}
|
||||
|
54
src/test1.c
54
src/test1.c
@@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test1.c,v 1.12 2002/07/10 21:26:01 drh Exp $
|
||||
** $Id: test1.c,v 1.13 2002/08/31 18:53:08 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
@@ -238,7 +238,7 @@ static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){
|
||||
** sqlite_create_function function while a query is in progress in order
|
||||
** to test the SQLITE_MISUSE detection logic.
|
||||
*/
|
||||
static int sqlite_test_create_function(
|
||||
static int test_create_function(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
@@ -288,7 +288,7 @@ static void countFinalize(sqlite_func *context){
|
||||
** sqlite_create_aggregate function while a query is in progress in order
|
||||
** to test the SQLITE_MISUSE detection logic.
|
||||
*/
|
||||
static int sqlite_test_create_aggregate(
|
||||
static int test_create_aggregate(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
@@ -484,7 +484,7 @@ static void testFunc(sqlite_func *context, int argc, const char **argv){
|
||||
**
|
||||
** Register the test SQL function on the database DB under the name NAME.
|
||||
*/
|
||||
static int sqlite_register_test_function(
|
||||
static int test_register_func(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
@@ -511,27 +511,33 @@ static int sqlite_register_test_function(
|
||||
*/
|
||||
int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
extern int sqlite_search_count;
|
||||
Tcl_CreateCommand(interp, "sqlite_mprintf_int", sqlite_mprintf_int, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite_mprintf_str", sqlite_mprintf_str, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite_mprintf_double", sqlite_mprintf_double,0,0);
|
||||
Tcl_CreateCommand(interp, "sqlite_open", sqlite_test_open, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite_last_insert_rowid", test_last_rowid, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite_exec_printf", test_exec_printf, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite_get_table_printf", test_get_table_printf,
|
||||
0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite_close", sqlite_test_close, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite_create_function",
|
||||
sqlite_test_create_function, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite_create_aggregate",
|
||||
sqlite_test_create_aggregate, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite_register_test_function",
|
||||
sqlite_register_test_function, 0, 0);
|
||||
static struct {
|
||||
char *zName;
|
||||
Tcl_CmdProc *xProc;
|
||||
} aCmd[] = {
|
||||
{ "sqlite_mprintf_int", (Tcl_CmdProc*)sqlite_mprintf_int },
|
||||
{ "sqlite_mprintf_str", (Tcl_CmdProc*)sqlite_mprintf_str },
|
||||
{ "sqlite_mprintf_double", (Tcl_CmdProc*)sqlite_mprintf_double },
|
||||
{ "sqlite_open", (Tcl_CmdProc*)sqlite_test_open },
|
||||
{ "sqlite_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
|
||||
{ "sqlite_exec_printf", (Tcl_CmdProc*)test_exec_printf },
|
||||
{ "sqlite_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
|
||||
{ "sqlite_close", (Tcl_CmdProc*)sqlite_test_close },
|
||||
{ "sqlite_create_function", (Tcl_CmdProc*)test_create_function },
|
||||
{ "sqlite_create_aggregate", (Tcl_CmdProc*)test_create_aggregate },
|
||||
{ "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func },
|
||||
{ "sqlite_abort", (Tcl_CmdProc*)sqlite_abort },
|
||||
#ifdef MEMORY_DEBUG
|
||||
{ "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail },
|
||||
{ "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat },
|
||||
#endif
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
|
||||
}
|
||||
Tcl_LinkVar(interp, "sqlite_search_count",
|
||||
(char*)&sqlite_search_count, TCL_LINK_INT);
|
||||
#ifdef MEMORY_DEBUG
|
||||
Tcl_CreateCommand(interp, "sqlite_malloc_fail", sqlite_malloc_fail, 0, 0);
|
||||
Tcl_CreateCommand(interp, "sqlite_malloc_stat", sqlite_malloc_stat, 0, 0);
|
||||
#endif
|
||||
Tcl_CreateCommand(interp, "sqlite_abort", sqlite_abort, 0, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
71
src/test2.c
71
src/test2.c
@@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test2.c,v 1.9 2002/08/12 12:29:57 drh Exp $
|
||||
** $Id: test2.c,v 1.10 2002/08/31 18:53:08 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@@ -62,7 +62,7 @@ static int pager_open(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
int nPage;
|
||||
@@ -93,7 +93,7 @@ static int pager_close(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
int rc;
|
||||
@@ -120,7 +120,7 @@ static int pager_rollback(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
int rc;
|
||||
@@ -147,7 +147,7 @@ static int pager_commit(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
int rc;
|
||||
@@ -174,7 +174,7 @@ static int pager_ckpt_begin(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
int rc;
|
||||
@@ -201,7 +201,7 @@ static int pager_ckpt_rollback(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
int rc;
|
||||
@@ -228,7 +228,7 @@ static int pager_ckpt_commit(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
int rc;
|
||||
@@ -255,7 +255,7 @@ static int pager_stats(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
int i, *a;
|
||||
@@ -288,7 +288,7 @@ static int pager_pagecount(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
char zBuf[100];
|
||||
@@ -312,7 +312,7 @@ static int page_get(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
char zBuf[100];
|
||||
@@ -346,7 +346,7 @@ static int page_lookup(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Pager *pPager;
|
||||
char zBuf[100];
|
||||
@@ -376,7 +376,7 @@ static int page_unref(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
void *pPage;
|
||||
int rc;
|
||||
@@ -403,7 +403,7 @@ static int page_read(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
char zBuf[100];
|
||||
void *pPage;
|
||||
@@ -427,7 +427,7 @@ static int page_number(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
char zBuf[100];
|
||||
void *pPage;
|
||||
@@ -451,7 +451,7 @@ static int page_write(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
void *pPage;
|
||||
int rc;
|
||||
@@ -476,21 +476,30 @@ static int page_write(
|
||||
*/
|
||||
int Sqlitetest2_Init(Tcl_Interp *interp){
|
||||
extern int sqlite_io_error_pending;
|
||||
Tcl_CreateCommand(interp, "pager_open", pager_open, 0, 0);
|
||||
Tcl_CreateCommand(interp, "pager_close", pager_close, 0, 0);
|
||||
Tcl_CreateCommand(interp, "pager_commit", pager_commit, 0, 0);
|
||||
Tcl_CreateCommand(interp, "pager_rollback", pager_rollback, 0, 0);
|
||||
Tcl_CreateCommand(interp, "pager_ckpt_begin", pager_ckpt_begin, 0, 0);
|
||||
Tcl_CreateCommand(interp, "pager_ckpt_commit", pager_ckpt_commit, 0, 0);
|
||||
Tcl_CreateCommand(interp, "pager_ckpt_rollback", pager_ckpt_rollback, 0, 0);
|
||||
Tcl_CreateCommand(interp, "pager_stats", pager_stats, 0, 0);
|
||||
Tcl_CreateCommand(interp, "pager_pagecount", pager_pagecount, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_get", page_get, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_lookup", page_lookup, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_unref", page_unref, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_read", page_read, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_write", page_write, 0, 0);
|
||||
Tcl_CreateCommand(interp, "page_number", page_number, 0, 0);
|
||||
static struct {
|
||||
char *zName;
|
||||
Tcl_CmdProc *xProc;
|
||||
} aCmd[] = {
|
||||
{ "pager_open", (Tcl_CmdProc*)pager_open },
|
||||
{ "pager_close", (Tcl_CmdProc*)pager_close },
|
||||
{ "pager_commit", (Tcl_CmdProc*)pager_commit },
|
||||
{ "pager_rollback", (Tcl_CmdProc*)pager_rollback },
|
||||
{ "pager_ckpt_begin", (Tcl_CmdProc*)pager_ckpt_begin },
|
||||
{ "pager_ckpt_commit", (Tcl_CmdProc*)pager_ckpt_commit },
|
||||
{ "pager_ckpt_rollback", (Tcl_CmdProc*)pager_ckpt_rollback },
|
||||
{ "pager_stats", (Tcl_CmdProc*)pager_stats },
|
||||
{ "pager_pagecount", (Tcl_CmdProc*)pager_pagecount },
|
||||
{ "page_get", (Tcl_CmdProc*)page_get },
|
||||
{ "page_lookup", (Tcl_CmdProc*)page_lookup },
|
||||
{ "page_unref", (Tcl_CmdProc*)page_unref },
|
||||
{ "page_read", (Tcl_CmdProc*)page_read },
|
||||
{ "page_write", (Tcl_CmdProc*)page_write },
|
||||
{ "page_number", (Tcl_CmdProc*)page_number },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
|
||||
}
|
||||
Tcl_LinkVar(interp, "sqlite_io_error_pending",
|
||||
(char*)&sqlite_io_error_pending, TCL_LINK_INT);
|
||||
#ifdef SQLITE_TEST
|
||||
|
117
src/test3.c
117
src/test3.c
@@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test3.c,v 1.18 2002/08/11 20:10:48 drh Exp $
|
||||
** $Id: test3.c,v 1.19 2002/08/31 18:53:08 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@@ -57,7 +57,7 @@ static int btree_open(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int rc;
|
||||
@@ -89,7 +89,7 @@ static int btree_close(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int rc;
|
||||
@@ -116,7 +116,7 @@ static int btree_begin_transaction(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int rc;
|
||||
@@ -143,7 +143,7 @@ static int btree_rollback(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int rc;
|
||||
@@ -170,7 +170,7 @@ static int btree_commit(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int rc;
|
||||
@@ -197,7 +197,7 @@ static int btree_create_table(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int rc, iTable;
|
||||
@@ -227,7 +227,7 @@ static int btree_drop_table(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int iTable;
|
||||
@@ -256,7 +256,7 @@ static int btree_clear_table(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int iTable;
|
||||
@@ -285,7 +285,7 @@ static int btree_get_meta(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int rc;
|
||||
@@ -319,7 +319,7 @@ static int btree_update_meta(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int rc;
|
||||
@@ -354,7 +354,7 @@ static int btree_page_dump(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int iPage;
|
||||
@@ -384,7 +384,7 @@ static int btree_tree_dump(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int iPage;
|
||||
@@ -414,7 +414,7 @@ static int btree_pager_stats(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int i;
|
||||
@@ -449,7 +449,7 @@ static int btree_pager_ref_dump(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
|
||||
@@ -474,7 +474,7 @@ static int btree_integrity_check(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
char *zResult;
|
||||
@@ -510,7 +510,7 @@ static int btree_cursor(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
int iTable;
|
||||
@@ -546,7 +546,7 @@ static int btree_close_cursor(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
@@ -574,7 +574,7 @@ static int btree_move_to(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
@@ -608,7 +608,7 @@ static int btree_delete(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
@@ -637,7 +637,7 @@ static int btree_insert(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
@@ -666,7 +666,7 @@ static int btree_next(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
@@ -698,7 +698,7 @@ static int btree_first(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
@@ -730,7 +730,7 @@ static int btree_key(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
@@ -768,7 +768,7 @@ static int btree_data(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
@@ -806,7 +806,7 @@ static int btree_payload_size(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int n1, n2;
|
||||
@@ -845,7 +845,7 @@ static int btree_cursor_dump(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
@@ -877,33 +877,42 @@ static int btree_cursor_dump(
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
int Sqlitetest3_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateCommand(interp, "btree_open", btree_open, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_close", btree_close, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_begin_transaction",
|
||||
btree_begin_transaction, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_commit", btree_commit, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_rollback", btree_rollback, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_create_table", btree_create_table, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_drop_table", btree_drop_table, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_clear_table", btree_clear_table, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_get_meta", btree_get_meta, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_update_meta", btree_update_meta, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_page_dump", btree_page_dump, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_tree_dump", btree_tree_dump, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_pager_stats", btree_pager_stats, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_pager_ref_dump", btree_pager_ref_dump, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_cursor", btree_cursor, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_close_cursor", btree_close_cursor, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_move_to", btree_move_to, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_delete", btree_delete, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_insert", btree_insert, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_next", btree_next, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_key", btree_key, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_data", btree_data, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_payload_size", btree_payload_size, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_first", btree_first, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_cursor_dump", btree_cursor_dump, 0, 0);
|
||||
Tcl_CreateCommand(interp, "btree_integrity_check", btree_integrity_check,0,0);
|
||||
static struct {
|
||||
char *zName;
|
||||
Tcl_CmdProc *xProc;
|
||||
} aCmd[] = {
|
||||
{ "btree_open", (Tcl_CmdProc*)btree_open },
|
||||
{ "btree_close", (Tcl_CmdProc*)btree_close },
|
||||
{ "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction },
|
||||
{ "btree_commit", (Tcl_CmdProc*)btree_commit },
|
||||
{ "btree_rollback", (Tcl_CmdProc*)btree_rollback },
|
||||
{ "btree_create_table", (Tcl_CmdProc*)btree_create_table },
|
||||
{ "btree_drop_table", (Tcl_CmdProc*)btree_drop_table },
|
||||
{ "btree_clear_table", (Tcl_CmdProc*)btree_clear_table },
|
||||
{ "btree_get_meta", (Tcl_CmdProc*)btree_get_meta },
|
||||
{ "btree_update_meta", (Tcl_CmdProc*)btree_update_meta },
|
||||
{ "btree_page_dump", (Tcl_CmdProc*)btree_page_dump },
|
||||
{ "btree_tree_dump", (Tcl_CmdProc*)btree_tree_dump },
|
||||
{ "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats },
|
||||
{ "btree_pager_ref_dump", (Tcl_CmdProc*)btree_pager_ref_dump },
|
||||
{ "btree_cursor", (Tcl_CmdProc*)btree_cursor },
|
||||
{ "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor },
|
||||
{ "btree_move_to", (Tcl_CmdProc*)btree_move_to },
|
||||
{ "btree_delete", (Tcl_CmdProc*)btree_delete },
|
||||
{ "btree_insert", (Tcl_CmdProc*)btree_insert },
|
||||
{ "btree_next", (Tcl_CmdProc*)btree_next },
|
||||
{ "btree_key", (Tcl_CmdProc*)btree_key },
|
||||
{ "btree_data", (Tcl_CmdProc*)btree_data },
|
||||
{ "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
|
||||
{ "btree_first", (Tcl_CmdProc*)btree_first },
|
||||
{ "btree_cursor_dump", (Tcl_CmdProc*)btree_cursor_dump },
|
||||
{ "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
|
||||
}
|
||||
Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager_refinfo_enable,
|
||||
TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "btree_native_byte_order",(char*)&btree_native_byte_order,
|
||||
|
44
test/fkey1.test
Normal file
44
test/fkey1.test
Normal file
@@ -0,0 +1,44 @@
|
||||
# 2001 September 15
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# This file implements tests for foreign keys.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Create a table and some data to work with.
|
||||
#
|
||||
do_test fkey1-1.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(
|
||||
a INTEGER PRIMARY KEY,
|
||||
b INTEGER
|
||||
REFERENCES t1 ON DELETE CASCADE
|
||||
REFERENCES t2,
|
||||
c TEXT,
|
||||
FOREIGN KEY (b,c) REFERENCES t2(x,y) ON UPDATE CASCADE
|
||||
);
|
||||
}
|
||||
} {}
|
||||
do_test fkey1-1.1 {
|
||||
execsql {
|
||||
CREATE TABLE t2(
|
||||
x INTEGER PRIMARY KEY,
|
||||
y TEXT
|
||||
);
|
||||
}
|
||||
} {}
|
||||
|
||||
|
||||
|
||||
finish_test
|
@@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the CREATE TABLE statement.
|
||||
#
|
||||
# $Id: table.test,v 1.19 2002/08/13 23:02:58 drh Exp $
|
||||
# $Id: table.test,v 1.20 2002/08/31 18:53:09 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -433,6 +433,45 @@ do_test table-10.8 {
|
||||
);
|
||||
}
|
||||
} {0 {}}
|
||||
do_test table-10.9 {
|
||||
catchsql {
|
||||
DROP TABLE t6;
|
||||
CREATE TABLE t6(a,b,c,
|
||||
FOREIGN KEY (b,c) REFERENCES t4(x)
|
||||
);
|
||||
}
|
||||
} {1 {number of columns in foreign key does not match the number of columns in the referenced table}}
|
||||
do_test table-10.10 {
|
||||
catchsql {DROP TABLE t6}
|
||||
catchsql {
|
||||
CREATE TABLE t6(a,b,c,
|
||||
FOREIGN KEY (b,c) REFERENCES t4(x,y,z)
|
||||
);
|
||||
}
|
||||
} {1 {number of columns in foreign key does not match the number of columns in the referenced table}}
|
||||
do_test table-10.11 {
|
||||
catchsql {DROP TABLE t6}
|
||||
catchsql {
|
||||
CREATE TABLE t6(a,b, c REFERENCES t4(x,y));
|
||||
}
|
||||
} {1 {foreign key on c should reference only one column of table t4}}
|
||||
do_test table-10.12 {
|
||||
catchsql {DROP TABLE t6}
|
||||
catchsql {
|
||||
CREATE TABLE t6(a,b,c,
|
||||
FOREIGN KEY (b,x) REFERENCES t4(x,y)
|
||||
);
|
||||
}
|
||||
} {1 {unknown column "x" in foreign key definition}}
|
||||
do_test table-10.13 {
|
||||
catchsql {DROP TABLE t6}
|
||||
catchsql {
|
||||
CREATE TABLE t6(a,b,c,
|
||||
FOREIGN KEY (x,b) REFERENCES t4(x,y)
|
||||
);
|
||||
}
|
||||
} {1 {unknown column "x" in foreign key definition}}
|
||||
|
||||
|
||||
# Test for the "typeof" function.
|
||||
#
|
||||
|
Reference in New Issue
Block a user