Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Parse foreign key constraints and populate internal data structures appropriately. Constraints are still not enforced. (CVS 738) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
170711ca65dc894d0486b9d575edb8f1 |
User & Date: | drh 2002-08-31 18:53:06.000 |
Context
2002-09-01
| ||
23:20 |
Relax the locking requirements on BTree cursors. Any number of read and
write cursors can be open at the same time now, but a write cannot occur
as long as one or more read cursors are open.
Before this change, one or more read cursors could be open on a table, or a single write cursor, but not both. Both policies have the same desirable effect: they prevent writes to a table while a sequential scan of that table is underway. But the new policy is a little less restrictive. Both policies prevent an UPDATE from occurring inside a SELECT (which is what we want) but the new policy allows a SELECT to occur inside an UPDATE. (CVS 739) (check-in: 8c2a083698 user: drh tags: trunk) | |
2002-08-31
| ||
18:53 | Parse foreign key constraints and populate internal data structures appropriately. Constraints are still not enforced. (CVS 738) (check-in: 170711ca65 user: drh tags: trunk) | |
17:02 | Version 2.7.1 (CVS 737) (check-in: 5f51e13d56 user: drh tags: trunk) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | ** COPY ** VACUUM ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** PRAGMA ** | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** COPY ** VACUUM ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** PRAGMA ** ** $Id: build.c,v 1.111 2002/08/31 18:53:06 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called when a new SQL statement is beginning to ** be parsed. Check to see if the schema for the database needs |
︙ | ︙ | |||
148 149 150 151 152 153 154 155 156 157 158 159 160 161 | ** if there were schema changes during the transaction. */ void sqliteResetInternalSchema(sqlite *db){ HashElem *pElem; Hash temp1; Hash temp2; temp1 = db->tblHash; temp2 = db->trigHash; sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0); sqliteHashClear(&db->idxHash); for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ Trigger *pTrigger = sqliteHashData(pElem); sqliteDeleteTrigger(pTrigger); | > | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | ** if there were schema changes during the transaction. */ void sqliteResetInternalSchema(sqlite *db){ HashElem *pElem; Hash temp1; Hash temp2; sqliteHashClear(&db->aFKey); temp1 = db->tblHash; temp2 = db->trigHash; sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0); sqliteHashClear(&db->idxHash); for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ Trigger *pTrigger = sqliteHashData(pElem); sqliteDeleteTrigger(pTrigger); |
︙ | ︙ | |||
190 191 192 193 194 195 196 | } /* ** Remove the memory data structures associated with the given ** Table. No changes are made to disk by this routine. ** ** This routine just deletes the data structure. It does not unlink | | > | > > > > > > > > > > > > > > > > > > > > > > < < < < | > > > > > > > > > > > > > | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | } /* ** Remove the memory data structures associated with the given ** 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. 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 ** the table are deleted, but it is assumed they have already been ** unlinked. */ 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); } sqliteFree(pTable->zName); sqliteFree(pTable->aCol); sqliteSelectDelete(pTable->pSelect); sqliteFree(pTable); } /* ** Unlink the given table from the hash tables and the delete the ** 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); } /* ** Construct the name of a user table or index from a token. ** ** Space to hold the name is obtained from sqliteMalloc() and must |
︙ | ︙ | |||
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | if( p==0 ) return; /* Add the table to the in-memory representation of the database. */ assert( pParse->nameClash==0 || pParse->initFlag==1 ); if( pParse->explain==0 && pParse->nameClash==0 ){ Table *pOld; pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ return; } pParse->pNewTable = 0; db->nTable++; db->flags |= SQLITE_InternChanges; } /* If the table is generated from a SELECT, then construct the ** list of columns and the text of the table. | > > > > > > | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 | if( p==0 ) return; /* Add the table to the in-memory representation of the database. */ 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; } /* If the table is generated from a SELECT, then construct the ** list of columns and the text of the table. |
︙ | ︙ | |||
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 | zType[i] = 'n'; } } zType[n] = 0; sqliteVdbeChangeP3(v, -1, zType, n); sqliteFree(zType); } /* ** 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 ** be NULL for a primary key or an index that is created to satisfy a ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable ** as the table to be indexed. pParse->pNewTable is a table that is | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 | zType[i] = 'n'; } } zType[n] = 0; sqliteVdbeChangeP3(v, -1, zType, n); 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 ** be NULL for a primary key or an index that is created to satisfy a ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable ** as the table to be indexed. pParse->pNewTable is a table that is |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** ** $Id: main.c,v 1.100 2002/08/31 18:53:06 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> /* ** A pointer to this structure is used to communicate information |
︙ | ︙ | |||
350 351 352 353 354 355 356 357 358 359 360 361 362 363 | db = sqliteMalloc( sizeof(sqlite) ); if( pzErrMsg ) *pzErrMsg = 0; if( db==0 ) goto no_mem_on_open; sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1); sqliteRegisterBuiltinFunctions(db); db->onError = OE_Default; db->priorNewRowid = 0; db->magic = SQLITE_MAGIC_BUSY; /* Open the backend database driver */ rc = sqliteBtreeOpen(zFilename, mode, MAX_PAGES, &db->pBe); | > | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | db = sqliteMalloc( sizeof(sqlite) ); if( pzErrMsg ) *pzErrMsg = 0; if( db==0 ) goto no_mem_on_open; sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0); 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; db->magic = SQLITE_MAGIC_BUSY; /* Open the backend database driver */ rc = sqliteBtreeOpen(zFilename, mode, MAX_PAGES, &db->pBe); |
︙ | ︙ | |||
462 463 464 465 466 467 468 469 470 471 472 473 474 475 | FuncDef *pFunc, *pNext; for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){ pNext = pFunc->pNext; sqliteFree(pFunc); } } sqliteHashClear(&db->aFunc); sqliteFree(db); } /* ** Return TRUE if the given SQL string ends in a semicolon. ** ** Special handling is require for CREATE TRIGGER statements. | > | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | FuncDef *pFunc, *pNext; for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){ pNext = pFunc->pNext; sqliteFree(pFunc); } } sqliteHashClear(&db->aFunc); sqliteHashClear(&db->aFKey); sqliteFree(db); } /* ** Return TRUE if the given SQL string ends in a semicolon. ** ** Special handling is require for CREATE TRIGGER statements. |
︙ | ︙ |
Changes to src/md5.c.
︙ | ︙ | |||
289 290 291 292 293 294 295 | zBuf[j] = 0; } /* ** A TCL command for md5. The argument is the text to be hashed. The ** Result is the hash in base64. */ | | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | zBuf[j] = 0; } /* ** A TCL command for md5. The argument is the text to be hashed. The ** Result is the hash in base64. */ static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){ MD5Context ctx; unsigned char digest[16]; if( argc!=2 ){ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], " TEXT\"", 0); return TCL_ERROR; } MD5Init(&ctx); MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1])); MD5Final(digest, &ctx); DigestToBase16(digest, interp->result); return TCL_OK; } /* ** A TCL command to take the md5 hash of a file. The argument is the ** name of the file. */ static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){ FILE *in; MD5Context ctx; unsigned char digest[16]; char zBuf[10240]; if( argc!=2 ){ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], |
︙ | ︙ | |||
343 344 345 346 347 348 349 | return TCL_OK; } /* ** Register the two TCL commands above with the TCL interpreter. */ int Md5_Init(Tcl_Interp *interp){ | | | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | return TCL_OK; } /* ** Register the two TCL commands above with the TCL interpreter. */ int Md5_Init(Tcl_Interp *interp){ Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd, 0, 0); Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd, 0, 0); return TCL_OK; } /* ** During testing, the special md5sum() aggregate function is available. ** inside SQLite. The following routines implement that function. */ |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** ** @(#) $Id: parse.y,v 1.83 2002/08/31 18:53:07 drh Exp $ */ %token_prefix TK_ %token_type {Token} %default_type {Token} %extra_argument {Parse *pParse} %syntax_error { sqliteSetString(&pParse->zErrMsg,"syntax error",0); |
︙ | ︙ | |||
165 166 167 168 169 170 171 | // UNIQUE constraints. // ccons ::= NULL onconf. 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. | | > | | > > | | | | | | | | > | > | | | > | | | > | | | > > > > | > | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | // UNIQUE constraints. // ccons ::= NULL onconf. 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 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)); } // 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. // %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. // conslist_opt ::= . conslist_opt ::= COMMA conslist. conslist ::= conslist COMMA tcons. conslist ::= conslist tcons. conslist ::= tcons. tcons ::= CONSTRAINT nm. 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. 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. // %type onconf {int} %type orconf {int} %type resolvetype {int} |
︙ | ︙ | |||
673 674 675 676 677 678 679 680 681 | %type uniqueflag {int} uniqueflag(A) ::= UNIQUE. { A = OE_Abort; } uniqueflag(A) ::= . { A = OE_None; } %type idxlist {IdList*} %destructor idxlist {sqliteIdListDelete($$);} %type idxitem {Token} | > > > > | < | < | | 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | %type uniqueflag {int} uniqueflag(A) ::= UNIQUE. { A = OE_Abort; } uniqueflag(A) ::= . { A = OE_None; } %type idxlist {IdList*} %destructor idxlist {sqliteIdListDelete($$);} %type idxlist_opt {IdList*} %destructor idxlist_opt {sqliteIdListDelete($$);} %type idxitem {Token} 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 ///////////////////////// // cmd ::= DROP INDEX nm(X). {sqliteDropIndex(pParse, &X);} |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.145 2002/08/31 18:53:07 drh Exp $ */ #include "sqlite.h" #include "hash.h" #include "vdbe.h" #include "parse.h" #include "btree.h" #include <stdio.h> |
︙ | ︙ | |||
171 172 173 174 175 176 177 178 179 180 181 182 183 184 | typedef struct WhereLevel WhereLevel; typedef struct Select Select; typedef struct AggExpr AggExpr; typedef struct FuncDef FuncDef; typedef struct Trigger Trigger; typedef struct TriggerStep TriggerStep; typedef struct TriggerStack TriggerStack; /* ** Each database is an instance of the following structure. ** ** The sqlite.file_format is initialized by the database file ** and helps determines how the data in the database file is ** represented. This field allows newer versions of the library | > | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | typedef struct WhereLevel WhereLevel; typedef struct Select Select; typedef struct AggExpr AggExpr; 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. ** ** The sqlite.file_format is initialized by the database file ** and helps determines how the data in the database file is ** represented. This field allows newer versions of the library |
︙ | ︙ | |||
202 203 204 205 206 207 208 209 210 211 212 213 214 215 | int nTable; /* Number of tables in the database */ void *pBusyArg; /* 1st Argument to the busy callback */ int (*xBusyCallback)(void *,const char*,int); /* The busy callback */ Hash tblHash; /* All tables indexed by name */ 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 */ int lastRowid; /* ROWID of most recent insert */ int priorNewRowid; /* Last randomly generated ROWID */ int onError; /* Default conflict algorithm */ int magic; /* Magic number for detect library misuse */ int nChange; /* Number of rows changed */ int recursionDepth; /* Number of nested calls to sqlite_exec() */ }; | > | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | int nTable; /* Number of tables in the database */ void *pBusyArg; /* 1st Argument to the busy callback */ int (*xBusyCallback)(void *,const char*,int); /* The busy callback */ Hash tblHash; /* All tables indexed by name */ 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 */ int magic; /* Magic number for detect library misuse */ int nChange; /* Number of rows changed */ int recursionDepth; /* Number of nested calls to sqlite_exec() */ }; |
︙ | ︙ | |||
326 327 328 329 330 331 332 333 334 335 | Select *pSelect; /* NULL for tables. Points to definition if a view. */ u8 readOnly; /* True if this table should not be written by the user */ u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */ u8 isTransient; /* True if automatically deleted when VDBE finishes */ 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 */ }; /* | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > | | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | Select *pSelect; /* NULL for tables. Points to definition if a view. */ u8 readOnly; /* True if this table should not be written by the user */ u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */ u8 isTransient; /* True if automatically deleted when VDBE finishes */ 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 */ }; /* ** 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 ** fails and any prior changes from that one operation are backed out, ** but the transaction is not rolled back. FAIL processing means that ** the operation in progress stops and returns an error code. But prior ** changes due to the same operation are not backed out and no rollback ** occurs. IGNORE means that the particular row that caused the constraint ** error is not inserted or updated. Processing continues and no error ** is returned. REPLACE means that preexisting database rows that caused ** 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. */ #define OE_None 0 /* There is no constraint to check */ #define OE_Rollback 1 /* Fail the operation and rollback the transaction */ #define OE_Abort 2 /* Back out changes but do no rollback transaction */ #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_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 ** instance of the following structure. ** ** The columns of the table that are to be indexed are described ** by the aiColumn[] field of this structure. For example, suppose |
︙ | ︙ | |||
943 944 945 946 947 948 949 | void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); TriggerStep *sqliteTriggerSelectStep(Select*); TriggerStep *sqliteTriggerInsertStep(Token*, IdList*, ExprList*, Select*, int); TriggerStep *sqliteTriggerUpdateStep(Token*, ExprList*, Expr*, int); TriggerStep *sqliteTriggerDeleteStep(Token*, Expr*); void sqliteDeleteTrigger(Trigger*); int sqliteJoinType(Parse*, Token*, Token*, Token*); | > > | 1000 1001 1002 1003 1004 1005 1006 1007 1008 | void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); TriggerStep *sqliteTriggerSelectStep(Select*); TriggerStep *sqliteTriggerInsertStep(Token*, IdList*, ExprList*, Select*, int); 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); |
Changes to src/tclsqlite.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. ** ************************************************************************* ** A TCL Interface to SQLite ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 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. ** ************************************************************************* ** A TCL Interface to SQLite ** ** $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 */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
639 640 641 642 643 644 645 | ** (Hence there is no namespace. There is no point in using a namespace ** if the extension only supplies one new name!) The "sqlite" command is ** used to open a new SQLite database. See the DbMain() routine above ** for additional information. */ int Sqlite_Init(Tcl_Interp *interp){ Tcl_InitStubs(interp, "8.0", 0); | | | | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 | ** (Hence there is no namespace. There is no point in using a namespace ** if the extension only supplies one new name!) The "sqlite" command is ** used to open a new SQLite database. See the DbMain() routine above ** for additional information. */ int Sqlite_Init(Tcl_Interp *interp){ Tcl_InitStubs(interp, "8.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", (Tcl_CmdProc*)DbMain, 0, 0); Tcl_PkgProvide(interp, "sqlite", "2.0"); return TCL_OK; } int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } int Tclsqlite_SafeInit(Tcl_Interp *interp){ |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the printf() interface to SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the printf() interface to SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test1.c,v 1.13 2002/08/31 18:53:08 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> /* |
︙ | ︙ | |||
234 235 236 237 238 239 240 | ** The effect is similar to trying to use the same database connection from ** two threads at the same time. ** ** The original motivation for this routine was to be able to call the ** sqlite_create_function function while a query is in progress in order ** to test the SQLITE_MISUSE detection logic. */ | | | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | ** The effect is similar to trying to use the same database connection from ** two threads at the same time. ** ** The original motivation for this routine was to be able to call the ** sqlite_create_function function while a query is in progress in order ** to test the SQLITE_MISUSE detection logic. */ static int test_create_function( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite *db; extern void Md5_Register(sqlite*); |
︙ | ︙ | |||
284 285 286 287 288 289 290 | ** to create a function named "x_count". This function does the same thing ** as the "md5sum" function. ** ** The original motivation for this routine was to be able to call the ** sqlite_create_aggregate function while a query is in progress in order ** to test the SQLITE_MISUSE detection logic. */ | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | ** to create a function named "x_count". This function does the same thing ** as the "md5sum" function. ** ** The original motivation for this routine was to be able to call the ** sqlite_create_aggregate function while a query is in progress in order ** to test the SQLITE_MISUSE detection logic. */ static int test_create_aggregate( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite *db; if( argc!=2 ){ |
︙ | ︙ | |||
480 481 482 483 484 485 486 | } /* ** Usage: sqlite_register_test_function DB NAME ** ** Register the test SQL function on the database DB under the name NAME. */ | | | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 | } /* ** Usage: sqlite_register_test_function DB NAME ** ** Register the test SQL function on the database DB under the name NAME. */ static int test_register_func( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite *db; int rc; |
︙ | ︙ | |||
507 508 509 510 511 512 513 | } /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite_search_count; | > > > > | | | | | | | < | | < | < < | | < | | > > > > | > > > | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | } /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite_search_count; 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); return TCL_OK; } |
Changes to src/test2.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the pager.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the pager.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test2.c,v 1.10 2002/08/31 18:53:08 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" #include "tcl.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
58 59 60 61 62 63 64 | ** ** Open a new pager */ static int pager_open( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | ** ** Open a new pager */ static int pager_open( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int nPage; int rc; char zBuf[100]; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
︙ | ︙ | |||
89 90 91 92 93 94 95 | ** ** Close the given pager. */ static int pager_close( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | ** ** Close the given pager. */ static int pager_close( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
116 117 118 119 120 121 122 | ** ** Rollback changes */ static int pager_rollback( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | ** ** Rollback changes */ static int pager_rollback( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
143 144 145 146 147 148 149 | ** ** Commit all changes */ static int pager_commit( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | ** ** Commit all changes */ static int pager_commit( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
170 171 172 173 174 175 176 | ** ** Start a new checkpoint. */ static int pager_ckpt_begin( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | ** ** Start a new checkpoint. */ static int pager_ckpt_begin( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
197 198 199 200 201 202 203 | ** ** Rollback changes to a checkpoint */ static int pager_ckpt_rollback( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | ** ** Rollback changes to a checkpoint */ static int pager_ckpt_rollback( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
224 225 226 227 228 229 230 | ** ** Commit changes to a checkpoint */ static int pager_ckpt_commit( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | ** ** Commit changes to a checkpoint */ static int pager_ckpt_commit( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
251 252 253 254 255 256 257 | ** ** Return pager statistics. */ static int pager_stats( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | ** ** Return pager statistics. */ static int pager_stats( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int i, *a; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
284 285 286 287 288 289 290 | ** ** Return the size of the database file. */ static int pager_pagecount( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | ** ** Return the size of the database file. */ static int pager_pagecount( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; char zBuf[100]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
308 309 310 311 312 313 314 | ** ** Return a pointer to a page from the database. */ static int page_get( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | ** ** Return a pointer to a page from the database. */ static int page_get( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; char zBuf[100]; void *pPage; int pgno; int rc; if( argc!=3 ){ |
︙ | ︙ | |||
342 343 344 345 346 347 348 | ** Return a pointer to a page if the page is already in cache. ** If not in cache, return an empty string. */ static int page_lookup( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | ** Return a pointer to a page if the page is already in cache. ** If not in cache, return an empty string. */ static int page_lookup( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; char zBuf[100]; void *pPage; int pgno; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
︙ | ︙ | |||
372 373 374 375 376 377 378 | ** ** Drop a pointer to a page. */ static int page_unref( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | ** ** Drop a pointer to a page. */ static int page_unref( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ void *pPage; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PAGE\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
399 400 401 402 403 404 405 | ** ** Return the content of a page */ static int page_read( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | ** ** Return the content of a page */ static int page_read( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ char zBuf[100]; void *pPage; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PAGE\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
423 424 425 426 427 428 429 | ** ** Return the page number for a page. */ static int page_number( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | ** ** Return the page number for a page. */ static int page_number( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ char zBuf[100]; void *pPage; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PAGE\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
447 448 449 450 451 452 453 | ** ** Write something into a page. */ static int page_write( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | ** ** Write something into a page. */ static int page_write( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ void *pPage; int rc; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PAGE DATA\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
472 473 474 475 476 477 478 | } /* ** Register commands with the TCL interpreter. */ int Sqlitetest2_Init(Tcl_Interp *interp){ extern int sqlite_io_error_pending; | > > > > | | | | | | | | | | | | | | > > > > | > | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | } /* ** Register commands with the TCL interpreter. */ int Sqlitetest2_Init(Tcl_Interp *interp){ extern int sqlite_io_error_pending; 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 Tcl_LinkVar(interp, "pager_old_format", (char*)&pager_old_format, TCL_LINK_INT); #endif return TCL_OK; } |
Changes to src/test3.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test3.c,v 1.19 2002/08/31 18:53:08 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" #include "btree.h" #include "tcl.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
53 54 55 56 57 58 59 | ** ** Open a new database */ static int btree_open( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | ** ** Open a new database */ static int btree_open( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc; char zBuf[100]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME\"", 0); |
︙ | ︙ | |||
85 86 87 88 89 90 91 | ** ** Close the given database. */ static int btree_close( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | ** ** Close the given database. */ static int btree_close( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
112 113 114 115 116 117 118 | ** ** Start a new transaction */ static int btree_begin_transaction( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | ** ** Start a new transaction */ static int btree_begin_transaction( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
139 140 141 142 143 144 145 | ** ** Rollback changes */ static int btree_rollback( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | ** ** Rollback changes */ static int btree_rollback( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
166 167 168 169 170 171 172 | ** ** Commit all changes */ static int btree_commit( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | ** ** Commit all changes */ static int btree_commit( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
193 194 195 196 197 198 199 | ** ** Create a new table in the database */ static int btree_create_table( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | ** ** Create a new table in the database */ static int btree_create_table( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc, iTable; char zBuf[30]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); |
︙ | ︙ | |||
223 224 225 226 227 228 229 | ** ** Delete an entire table from the database */ static int btree_drop_table( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | ** ** Delete an entire table from the database */ static int btree_drop_table( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int iTable; int rc; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID TABLENUM\"", 0); |
︙ | ︙ | |||
252 253 254 255 256 257 258 | ** ** Remove all entries from the given table but keep the table around. */ static int btree_clear_table( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | ** ** Remove all entries from the given table but keep the table around. */ static int btree_clear_table( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int iTable; int rc; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID TABLENUM\"", 0); |
︙ | ︙ | |||
281 282 283 284 285 286 287 | ** ** Return meta data */ static int btree_get_meta( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | ** ** Return meta data */ static int btree_get_meta( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc; int i; int aMeta[SQLITE_N_BTREE_META]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
︙ | ︙ | |||
315 316 317 318 319 320 321 | ** ** Return meta data */ static int btree_update_meta( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | ** ** Return meta data */ static int btree_update_meta( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc; int i; int aMeta[SQLITE_N_BTREE_META]; if( argc!=2+SQLITE_N_BTREE_META ){ |
︙ | ︙ | |||
350 351 352 353 354 355 356 | ** ** Print a disassembly of a page on standard output */ static int btree_page_dump( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | ** ** Print a disassembly of a page on standard output */ static int btree_page_dump( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int iPage; int rc; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
︙ | ︙ | |||
380 381 382 383 384 385 386 | ** ** Print a disassembly of a page and all its child pages on standard output */ static int btree_tree_dump( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | ** ** Print a disassembly of a page and all its child pages on standard output */ static int btree_tree_dump( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int iPage; int rc; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
︙ | ︙ | |||
410 411 412 413 414 415 416 | ** ** Returns pager statistics */ static int btree_pager_stats( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | ** ** Returns pager statistics */ static int btree_pager_stats( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int i; int *a; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
︙ | ︙ | |||
445 446 447 448 449 450 451 | ** ** Print out all outstanding pages. */ static int btree_pager_ref_dump( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 | ** ** Print out all outstanding pages. */ static int btree_pager_ref_dump( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; |
︙ | ︙ | |||
470 471 472 473 474 475 476 | ** formatting and linkage. Return a line of text for each problem found. ** Return an empty string if everything worked. */ static int btree_integrity_check( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | ** formatting and linkage. Return a line of text for each problem found. ** Return an empty string if everything worked. */ static int btree_integrity_check( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; char *zResult; int nRoot; int *aRoot; int i; |
︙ | ︙ | |||
506 507 508 509 510 511 512 | ** ** Create a new cursor. Return the ID for the cursor. */ static int btree_cursor( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | ** ** Create a new cursor. Return the ID for the cursor. */ static int btree_cursor( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int iTable; BtCursor *pCur; int rc; int wrFlag; char zBuf[30]; |
︙ | ︙ | |||
542 543 544 545 546 547 548 | ** ** Close a cursor opened using btree_cursor. */ static int btree_close_cursor( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | ** ** Close a cursor opened using btree_cursor. */ static int btree_close_cursor( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); |
︙ | ︙ | |||
570 571 572 573 574 575 576 | ** ** Move the cursor to the entry with the given key. */ static int btree_move_to( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 | ** ** Move the cursor to the entry with the given key. */ static int btree_move_to( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; int res; char zBuf[20]; if( argc!=3 ){ |
︙ | ︙ | |||
604 605 606 607 608 609 610 | ** ** Delete the entry that the cursor is pointing to */ static int btree_delete( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | ** ** Delete the entry that the cursor is pointing to */ static int btree_delete( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); |
︙ | ︙ | |||
633 634 635 636 637 638 639 | ** Create a new entry with the given key and data. If an entry already ** exists with the same key the old entry is overwritten. */ static int btree_insert( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | ** Create a new entry with the given key and data. If an entry already ** exists with the same key the old entry is overwritten. */ static int btree_insert( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; if( argc!=4 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID KEY DATA\"", 0); |
︙ | ︙ | |||
662 663 664 665 666 667 668 | ** ** Move the cursor to the next entry in the table. */ static int btree_next( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | ** ** Move the cursor to the next entry in the table. */ static int btree_next( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; int res = 0; char zBuf[100]; if( argc!=2 ){ |
︙ | ︙ | |||
694 695 696 697 698 699 700 | ** ** Move the cursor to the first entry in the table. */ static int btree_first( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 | ** ** Move the cursor to the first entry in the table. */ static int btree_first( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; int res = 0; char zBuf[100]; if( argc!=2 ){ |
︙ | ︙ | |||
726 727 728 729 730 731 732 | ** ** Return the key for the entry at which the cursor is pointing. */ static int btree_key( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 | ** ** Return the key for the entry at which the cursor is pointing. */ static int btree_key( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; int n; char *zBuf; if( argc!=2 ){ |
︙ | ︙ | |||
764 765 766 767 768 769 770 | ** ** Return the data for the entry at which the cursor is pointing. */ static int btree_data( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 | ** ** Return the data for the entry at which the cursor is pointing. */ static int btree_data( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; int n; char *zBuf; if( argc!=2 ){ |
︙ | ︙ | |||
802 803 804 805 806 807 808 | ** ** Return the number of bytes of payload */ static int btree_payload_size( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 | ** ** Return the number of bytes of payload */ static int btree_payload_size( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int n1, n2; char zBuf[50]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
︙ | ︙ | |||
841 842 843 844 845 846 847 | ** aResult[6] = Page number of the left child of this entry ** aResult[7] = Page number of the right child for the whole page */ static int btree_cursor_dump( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ | | | 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 | ** aResult[6] = Page number of the left child of this entry ** aResult[7] = Page number of the right child for the whole page */ static int btree_cursor_dump( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; int i, j; int aResult[8]; char zBuf[400]; |
︙ | ︙ | |||
873 874 875 876 877 878 879 | return SQLITE_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest3_Init(Tcl_Interp *interp){ | > > > > | | | < | | | | | | | | | | | | | | | | | | | | | > > > > | > | > | 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 | return SQLITE_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest3_Init(Tcl_Interp *interp){ 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, TCL_LINK_INT); return TCL_OK; } |
Added test/fkey1.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 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 |
Changes to test/table.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 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. The # focus of this file is testing the CREATE TABLE statement. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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. The # focus of this file is testing the CREATE TABLE statement. # # $Id: table.test,v 1.20 2002/08/31 18:53:09 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a basic table and verify it is added to sqlite_master # do_test table-1.1 { |
︙ | ︙ | |||
429 430 431 432 433 434 435 436 437 438 439 440 441 442 | DROP TABLE t6; CREATE TABLE t6(a,b,c, FOREIGN KEY (b,c) REFERENCES t4(x,y) MATCH PARTIAL ON UPDATE SET NULL ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED ); } } {0 {}} # Test for the "typeof" function. # do_test table-11.1 { execsql { CREATE TABLE t7( a integer primary key, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 | DROP TABLE t6; CREATE TABLE t6(a,b,c, FOREIGN KEY (b,c) REFERENCES t4(x,y) MATCH PARTIAL ON UPDATE SET NULL ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED ); } } {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. # do_test table-11.1 { execsql { CREATE TABLE t7( a integer primary key, |
︙ | ︙ |