Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Added support for the INTEGER PRIMARY KEY column type. (CVS 333) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
236a54d289e858a1e0505a20d907a2a4 |
User & Date: | drh 2001-12-21 14:30:43.000 |
Context
2001-12-22
| ||
14:49 | Bug fixing in the new integer primary key code. (CVS 334) (check-in: 29cab124b4 user: drh tags: trunk) | |
2001-12-21
| ||
14:30 | Added support for the INTEGER PRIMARY KEY column type. (CVS 333) (check-in: 236a54d289 user: drh tags: trunk) | |
2001-12-16
| ||
20:05 | Added the ability to say things like "SELECT rowid, * FROM table1;" (CVS 332) (check-in: ffbdd43f5d user: drh tags: trunk) | |
Changes
Changes to VERSION.
|
| | | 1 | 2.2.0 |
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.60 2001/12/21 14:30:43 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called after a single SQL statement has been ** parsed and we want to execute the VDBE code to implement |
︙ | ︙ | |||
264 265 266 267 268 269 270 | } for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){ Table *pTable = sqliteHashData(pElem); sqliteUnlinkAndDeleteTable(db, pTable); } sqliteHashClear(&toDelete); for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){ | | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | } for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){ Table *pTable = sqliteHashData(pElem); sqliteUnlinkAndDeleteTable(db, pTable); } sqliteHashClear(&toDelete); for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){ Index *pIndex = sqliteHashData(pElem); if( pIndex->isDelete ){ sqliteHashInsert(&toDelete, pIndex, 0, pIndex); }else{ pIndex->isCommit = 1; } } for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){ |
︙ | ︙ | |||
307 308 309 310 311 312 313 | } for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){ Table *pTable = sqliteHashData(pElem); sqliteUnlinkAndDeleteTable(db, pTable); } sqliteHashClear(&toDelete); for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){ | | | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | } for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){ Table *pTable = sqliteHashData(pElem); sqliteUnlinkAndDeleteTable(db, pTable); } sqliteHashClear(&toDelete); for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){ Index *pIndex = sqliteHashData(pElem); if( !pIndex->isCommit ){ sqliteHashInsert(&toDelete, pIndex, 0, pIndex); }else{ pIndex->isDelete = 0; } } for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){ |
︙ | ︙ | |||
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | if( pTable==0 ){ sqliteFree(zName); return; } pTable->zName = zName; pTable->nCol = 0; pTable->aCol = 0; pTable->pIndex = 0; pTable->isTemp = isTemp; if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){ if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); pParse->schemaVerified = 1; } if( !isTemp ){ sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2); sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC); } } } /* | > > | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | if( pTable==0 ){ sqliteFree(zName); return; } pTable->zName = zName; pTable->nCol = 0; pTable->aCol = 0; pTable->iPKey = -1; pTable->pIndex = 0; pTable->isTemp = isTemp; if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){ if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); pParse->schemaVerified = 1; } if( !isTemp ){ sqliteVdbeAddOp(v, OP_SetCookie, db->file_format, 1); sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2); sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC); } } } /* |
︙ | ︙ | |||
529 530 531 532 533 534 535 536 537 538 539 540 541 542 | if( minusFlag ){ sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0); }else{ sqliteSetNString(pz, pVal->z, pVal->n, 0); } sqliteDequote(*pz); } /* ** Come up with a new random value for the schema cookie. Make sure ** the new value is different from the old. ** ** The schema cookie is used to determine when the schema for the ** database changes. After each schema change, the cookie value | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 | if( minusFlag ){ sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0); }else{ sqliteSetNString(pz, pVal->z, pVal->n, 0); } sqliteDequote(*pz); } /* ** Designate the PRIMARY KEY for the table. pList is a list of names ** of columns that form the primary key. If pList is NULL, then the ** most recently added column of the table is the primary key. ** ** A table can have at most one primary key. If the table already has ** a primary key (and this is the second primary key) then create an ** error. ** ** If the PRIMARY KEY is on a single column whose datatype is INTEGER, ** then we will try to use that column as the row id. (Exception: ** For backwards compatibility with older databases, do not do this ** if the file format version number is less than 1.) Set the Table.iPKey ** field of the table under construction to be the index of the ** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is ** no INTEGER PRIMARY KEY. ** ** If the key is not an INTEGER PRIMARY KEY, then create a unique ** index for the key. No index is created for INTEGER PRIMARY KEYs. */ void sqliteAddPrimaryKey(Parse *pParse, IdList *pList){ Table *pTab = pParse->pNewTable; char *zType = 0; int iCol = -1; if( pTab==0 ) return; if( pTab->hasPrimKey ){ sqliteSetString(&pParse->zErrMsg, "table \"", pTab->zName, "\" has more than one primary key", 0); pParse->nErr++; return; } pTab->hasPrimKey = 1; if( pList==0 ){ iCol = pTab->nCol - 1; }else if( pList->nId==1 ){ for(iCol=0; iCol<pTab->nCol; iCol++){ if( sqliteStrICmp(pList->a[0].zName, pTab->aCol[iCol].zName)==0 ) break; } } if( iCol>=0 && iCol<pTab->nCol ){ zType = pTab->aCol[iCol].zType; } if( pParse->db->file_format>=1 && zType && sqliteStrICmp(zType, "INTEGER")==0 ){ pTab->iPKey = iCol; }else{ sqliteCreateIndex(pParse, 0, 0, pList, 1, 0, 0); } } /* ** Come up with a new random value for the schema cookie. Make sure ** the new value is different from the old. ** ** The schema cookie is used to determine when the schema for the ** database changes. After each schema change, the cookie value |
︙ | ︙ | |||
783 784 785 786 787 788 789 | " may not have new indices added", 0); pParse->nErr++; goto exit_create_index; } /* If this index is created while re-reading the schema from sqlite_master ** but the table associated with this index is a temporary table, it can | | | | 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | " may not have new indices added", 0); pParse->nErr++; goto exit_create_index; } /* If this index is created while re-reading the schema from sqlite_master ** but the table associated with this index is a temporary table, it can ** only mean that the table that this index is really associated with is ** one whose name is hidden behind a temporary table with the same name. ** Since its table has been suppressed, we need to also suppress the ** index. */ if( pParse->initFlag && pTab->isTemp ){ goto exit_create_index; } |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** ** $Id: delete.c,v 1.22 2001/12/21 14:30:43 drh Exp $ */ #include "sqliteInt.h" /* ** Process a DELETE FROM statement. */ void sqliteDeleteFrom( |
︙ | ︙ | |||
153 154 155 156 157 158 159 | addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); if( pTab->pIndex ){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ int j; sqliteVdbeAddOp(v, OP_Recno, base, 0); for(j=0; j<pIdx->nColumn; j++){ | > > > > | > | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); if( pTab->pIndex ){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ int j; sqliteVdbeAddOp(v, OP_Recno, base, 0); for(j=0; j<pIdx->nColumn; j++){ int idx = pIdx->aiColumn[j]; if( idx==pTab->iPKey ){ sqliteVdbeAddOp(v, OP_Dup, j, 0); }else{ sqliteVdbeAddOp(v, OP_Column, base, idx); } } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0); } } sqliteVdbeAddOp(v, OP_Delete, base, 0); sqliteVdbeAddOp(v, OP_Goto, 0, addr); |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.35 2001/12/21 14:30:43 drh Exp $ */ #include "sqliteInt.h" /* ** Walk an expression tree. Return 1 if the expression is constant ** and 0 if it involves variables. */ |
︙ | ︙ | |||
123 124 125 126 127 128 129 | int j; Table *pTab = pTabList->a[i].pTab; if( pTab==0 ) continue; for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){ cnt++; pExpr->iTable = i + pParse->nTab; | > > > > | > | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | int j; Table *pTab = pTabList->a[i].pTab; if( pTab==0 ) continue; for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){ cnt++; pExpr->iTable = i + pParse->nTab; if( j==pTab->iPKey ){ /* Substitute the record number for the INTEGER PRIMARY KEY */ pExpr->iColumn = -1; }else{ pExpr->iColumn = j; } } } } if( cnt==0 && sqliteIsRowid(z) ){ pExpr->iColumn = -1; pExpr->iTable = pParse->nTab; cnt = 1 + (pTabList->nId>1); |
︙ | ︙ | |||
186 187 188 189 190 191 192 | } if( sqliteStrICmp(zTab, zLeft)!=0 ) continue; if( 0==(cntTab++) ) pExpr->iTable = i + pParse->nTab; for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){ cnt++; pExpr->iTable = i + pParse->nTab; | > > > > | > | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | } if( sqliteStrICmp(zTab, zLeft)!=0 ) continue; if( 0==(cntTab++) ) pExpr->iTable = i + pParse->nTab; for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){ cnt++; pExpr->iTable = i + pParse->nTab; if( j==pTab->iPKey ){ /* Substitute the record number for the INTEGER PRIMARY KEY */ pExpr->iColumn = -1; }else{ pExpr->iColumn = j; } } } } if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){ cnt = 1; pExpr->iColumn = -1; } |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** ** $Id: insert.c,v 1.27 2001/12/21 14:30:43 drh Exp $ */ #include "sqliteInt.h" /* ** This routine is call to handle SQL of the following forms: ** ** insert into TABLE (IDLIST) values(EXPRLIST) |
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 | Index *pIdx; /* For looping over indices of the table */ int srcTab; /* Date comes from this temporary cursor if >=0 */ int nColumn; /* Number of columns in the data */ int base; /* First available cursor */ int iCont, iBreak; /* Beginning and end of the loop over srcTab */ sqlite *db; /* The main database structure */ int openOp; /* Opcode used to open cursors */ if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; db = pParse->db; /* Locate the table into which we will be inserting new information. */ zTab = sqliteTableNameFromToken(pTableName); | > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | Index *pIdx; /* For looping over indices of the table */ int srcTab; /* Date comes from this temporary cursor if >=0 */ int nColumn; /* Number of columns in the data */ int base; /* First available cursor */ int iCont, iBreak; /* Beginning and end of the loop over srcTab */ sqlite *db; /* The main database structure */ int openOp; /* Opcode used to open cursors */ int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */ if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; db = pParse->db; /* Locate the table into which we will be inserting new information. */ zTab = sqliteTableNameFromToken(pTableName); |
︙ | ︙ | |||
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | for(i=0; i<pColumn->nId; i++){ pColumn->a[i].idx = -1; } for(i=0; i<pColumn->nId; i++){ for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ pColumn->a[i].idx = j; break; } } if( j>=pTab->nCol ){ sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " has no column named ", pColumn->a[i].zName, 0); pParse->nErr++; goto insert_cleanup; } } } /* Open cursors into the table that is received the new data and ** all indices of that table. */ base = pParse->nTab; openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite; sqliteVdbeAddOp(v, openOp, base, pTab->tnum); | > > > > > > > > > > | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | for(i=0; i<pColumn->nId; i++){ pColumn->a[i].idx = -1; } for(i=0; i<pColumn->nId; i++){ for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ pColumn->a[i].idx = j; if( j==pTab->iPKey ){ keyColumn = j; } break; } } if( j>=pTab->nCol ){ sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " has no column named ", pColumn->a[i].zName, 0); pParse->nErr++; goto insert_cleanup; } } } /* If there is not IDLIST term but the table has an integer primary ** key, the set the keyColumn variable to the primary key column. */ if( pColumn==0 ){ keyColumn = pTab->iPKey; } /* Open cursors into the table that is received the new data and ** all indices of that table. */ base = pParse->nTab; openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite; sqliteVdbeAddOp(v, openOp, base, pTab->tnum); |
︙ | ︙ | |||
174 175 176 177 178 179 180 | sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */ } iBreak = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak); iCont = sqliteVdbeCurrentAddr(v); } | > > | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > | < > > > > > | 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 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 | sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */ } iBreak = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak); iCont = sqliteVdbeCurrentAddr(v); } /* Push the record number for the new entry onto the stack. The ** record number is a randomly generate integer created by NewRecno ** except when the table has an INTEGER PRIMARY KEY column, in which ** case the record number is the same as that column. */ if( keyColumn>=0 ){ if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn); }else{ sqliteExprCode(pParse, pList->a[keyColumn].pExpr); } sqliteVdbeAddOp(v, OP_AddImm, 0, 0); /* Make sure ROWID is an integer */ }else{ sqliteVdbeAddOp(v, OP_NewRecno, base, 0); } /* If there are indices, we'll need this record number again, so make ** a copy. */ if( pTab->pIndex ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0); } /* Push onto the stack data for all columns of the new entry, beginning ** with the first column. */ for(i=0; i<pTab->nCol; i++){ if( i==pTab->iPKey ){ /* The value of the INTEGER PRIMARY KEY column is always a NULL. ** Whenever this column is used, the record number will be substituted ** in its place, so there is no point it it taking up space in ** the data record. */ sqliteVdbeAddOp(v, OP_String, 0, 0); continue; } if( pColumn==0 ){ j = i; }else{ for(j=0; j<pColumn->nId; j++){ if( pColumn->a[j].idx==i ) break; } } if( pColumn && j>=pColumn->nId ){ sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC); }else if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Column, srcTab, i); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } } /* Create the new record and put it into the database. */ sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); sqliteVdbeAddOp(v, OP_Put, base, keyColumn>=0); /* Create appropriate entries for the new data row in all indices ** of the table. */ for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ if( pIdx->pNext ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0); } for(i=0; i<pIdx->nColumn; i++){ int idx = pIdx->aiColumn[i]; if( idx==pTab->iPKey ){ /* Copy the record number in place of the INTEGER PRIMARY KEY column */ sqliteVdbeAddOp(v, OP_Dup, i, 0); continue; } if( pColumn==0 ){ j = idx; }else{ for(j=0; j<pColumn->nId; j++){ if( pColumn->a[j].idx==idx ) break; } } |
︙ | ︙ |
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 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | ** ************************************************************************* ** 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.52 2001/12/21 14:30:43 drh Exp $ */ #include "sqliteInt.h" #include "os.h" /* ** This is the callback routine for the code that initializes the ** database. See sqliteInit() below for additional information. ** ** Each callback contains the following information: ** ** argv[0] = "file-format" or "schema-cookie" or "table" or "index" ** argv[1] = table or index name or meta statement type. ** argv[2] = root page number for table or index. NULL for meta. ** argv[3] = SQL create statement for the table or index ** */ static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){ sqlite *db = (sqlite*)pDb; Parse sParse; int nErr = 0; /* TODO: Do some validity checks on all fields. In particular, ** make sure fields do not contain NULLs. Otherwise we might core ** when attempting to initialize from a corrupt database file. */ assert( argc==4 ); switch( argv[0][0] ){ case 'f': { /* File format */ db->file_format = atoi(argv[3]); break; } case 's': { /* Schema cookie */ db->schema_cookie = atoi(argv[3]); db->next_cookie = db->schema_cookie; break; } case 'i': case 't': { /* CREATE TABLE and CREATE INDEX statements */ if( argv[3] && argv[3][0] ){ /* Call the parser to process a CREATE TABLE or CREATE INDEX statement. ** But because sParse.initFlag is set to 1, no VDBE code is generated |
︙ | ︙ | |||
152 153 154 155 156 157 158 | ** The following program invokes its callback on the SQL for each ** table then goes back and invokes the callback on the ** SQL for each index. The callback will invoke the ** parser to build the internal representation of the ** database scheme. */ static VdbeOp initProg[] = { | | | | | | | > | | | | < | | | | | | | | | | | | | | | | | | | | < < < < < | | > > > | | 152 153 154 155 156 157 158 159 160 161 162 163 164 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 | ** The following program invokes its callback on the SQL for each ** table then goes back and invokes the callback on the ** SQL for each index. The callback will invoke the ** parser to build the internal representation of the ** database scheme. */ static VdbeOp initProg[] = { { OP_Open, 0, 2, 0}, { OP_String, 0, 0, "file-format"}, { OP_String, 0, 0, 0}, { OP_String, 0, 0, 0}, { OP_ReadCookie, 0, 1, 0}, { OP_Callback, 4, 0, 0}, { OP_String, 0, 0, "schema_cookie"}, { OP_String, 0, 0, 0}, { OP_String, 0, 0, 0}, { OP_ReadCookie, 0, 0, 0}, { OP_Callback, 4, 0, 0}, { OP_Rewind, 0, 31, 0}, { OP_Column, 0, 0, 0}, /* 12 */ { OP_String, 0, 0, "table"}, { OP_Ne, 0, 20, 0}, { OP_Column, 0, 0, 0}, { OP_Column, 0, 1, 0}, { OP_Column, 0, 3, 0}, { OP_Column, 0, 4, 0}, { OP_Callback, 4, 0, 0}, { OP_Next, 0, 12, 0}, /* 20 */ { OP_Rewind, 0, 31, 0}, /* 21 */ { OP_Column, 0, 0, 0}, /* 22 */ { OP_String, 0, 0, "index"}, { OP_Ne, 0, 30, 0}, { OP_Column, 0, 0, 0}, { OP_Column, 0, 1, 0}, { OP_Column, 0, 3, 0}, { OP_Column, 0, 4, 0}, { OP_Callback, 4, 0, 0}, { OP_Next, 0, 22, 0}, /* 30 */ { OP_Close, 0, 0, 0}, /* 31 */ { OP_Halt, 0, 0, 0}, }; /* Create a virtual machine to run the initialization program. Run ** the program. Then delete the virtual machine. */ vdbe = sqliteVdbeCreate(db); if( vdbe==0 ){ sqliteSetString(pzErrMsg, "out of memory", 0); return SQLITE_NOMEM; } sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg); rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg, db->pBusyArg, db->xBusyCallback); sqliteVdbeDelete(vdbe); if( rc==SQLITE_OK && db->nTable==0 ){ db->file_format = FILE_FORMAT; } if( rc==SQLITE_OK && db->file_format>FILE_FORMAT ){ sqliteSetString(pzErrMsg, "unsupported file format", 0); rc = SQLITE_ERROR; } if( rc==SQLITE_OK ){ Table *pTab; char *azArg[6]; azArg[0] = "table"; |
︙ | ︙ | |||
278 279 280 281 282 283 284 | } } sqliteFree(db); sqliteStrRealloc(pzErrMsg); return 0; } | < < < | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | } } sqliteFree(db); sqliteStrRealloc(pzErrMsg); return 0; } /* Attempt to read the schema */ rc = sqliteInit(db, pzErrMsg); if( sqlite_malloc_failed ){ sqlite_close(db); goto no_mem_on_open; }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ sqlite_close(db); |
︙ | ︙ |
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.40 2001/12/21 14:30:43 drh Exp $ */ %token_prefix TK_ %token_type {Token} %default_type {Token} %extra_argument {Parse *pParse} %syntax_error { sqliteSetString(&pParse->zErrMsg,"syntax error",0); |
︙ | ︙ | |||
134 135 136 137 138 139 140 | carg ::= DEFAULT MINUS FLOAT(X). {sqliteAddDefaultValue(pParse,&X,1);} carg ::= DEFAULT NULL. // In addition to the type name, we also care about the primary key and // UNIQUE constraints. // ccons ::= NOT NULL. {sqliteAddNotNull(pParse);} | | | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | carg ::= DEFAULT MINUS FLOAT(X). {sqliteAddDefaultValue(pParse,&X,1);} carg ::= DEFAULT NULL. // In addition to the type name, we also care about the primary key and // UNIQUE constraints. // ccons ::= NOT NULL. {sqliteAddNotNull(pParse);} ccons ::= PRIMARY KEY sortorder. {sqliteAddPrimaryKey(pParse, 0);} ccons ::= UNIQUE. {sqliteCreateIndex(pParse,0,0,0,1,0,0);} ccons ::= CHECK LP expr RP. // 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 ids. tcons ::= PRIMARY KEY LP idxlist(X) RP. {sqliteAddPrimaryKey(pParse,X);} tcons ::= UNIQUE LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,1,0,0);} tcons ::= CHECK expr. ////////////////////////// The DROP TABLE ///////////////////////////////////// // cmd ::= DROP TABLE ids(X). {sqliteDropTable(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 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.73 2001/12/21 14:30:43 drh Exp $ */ #include "sqlite.h" #include "hash.h" #include "vdbe.h" #include "parse.h" #include "btree.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> /* ** The maximum number of in-memory pages to use for the main database ** table and for temporary tables. */ #define MAX_PAGES 100 #define TEMP_PAGES 25 /* ** File format version number */ #define FILE_FORMAT 1 /* ** Integers of known sizes. These typedefs might change for architectures ** where the sizes very. Preprocessor macros are available so that the ** types can be conveniently redefined at compile-type. Like this: ** ** cc '-DUINTPTR_TYPE=long long int' ... */ |
︙ | ︙ | |||
209 210 211 212 213 214 215 | ** information about each column of an SQL table is held in an instance ** of this structure. */ struct Column { char *zName; /* Name of this column */ char *zDflt; /* Default value of this column */ char *zType; /* Data type for this column */ | | > > > | 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 | ** information about each column of an SQL table is held in an instance ** of this structure. */ struct Column { char *zName; /* Name of this column */ char *zDflt; /* Default value of this column */ char *zType; /* Data type for this column */ u8 notNull; /* True if there is a NOT NULL constraint */ u8 isPrimKey; /* True if this column is an INTEGER PRIMARY KEY */ }; /* ** Each SQL table is represented in memory by ** an instance of the following structure. */ struct Table { char *zName; /* Name of the table */ int nCol; /* Number of columns in this table */ Column *aCol; /* Information about each column */ int iPKey; /* Use this column as the record-number for each row */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Page containing root for this table */ u8 readOnly; /* True if this table should not be written by the user */ u8 isCommit; /* True if creation of this table has been committed */ u8 isDelete; /* True if this table is being deleted */ u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */ u8 hasPrimKey; /* True if there exists a primary key */ }; /* ** 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 |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** ** $Id: update.c,v 1.23 2001/12/21 14:30:43 drh Exp $ */ #include "sqliteInt.h" /* ** Process an UPDATE statement. */ void sqliteUpdate( |
︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 | int base; /* Index of first available table cursor */ sqlite *db; /* The database structure */ Index **apIdx = 0; /* An array of indices that need updating too */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ int openOp; /* Opcode used to open tables */ if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup; db = pParse->db; /* Locate the table which we want to update. This table has to be ** put in an IdList structure because some of the subroutines we ** will be calling are designed to work with multiple tables and expect | > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | int base; /* Index of first available table cursor */ sqlite *db; /* The database structure */ Index **apIdx = 0; /* An array of indices that need updating too */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ int openOp; /* Opcode used to open tables */ int chngRecno; /* True if the record number is being changed */ Expr *pRecnoExpr; /* Expression defining the new record number */ if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup; db = pParse->db; /* Locate the table which we want to update. This table has to be ** put in an IdList structure because some of the subroutines we ** will be calling are designed to work with multiple tables and expect |
︙ | ︙ | |||
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){ goto update_cleanup; } if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ goto update_cleanup; } } for(i=0; i<pChanges->nExpr; i++){ if( sqliteExprResolveIds(pParse, pTabList, pChanges->a[i].pExpr) ){ goto update_cleanup; } if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){ goto update_cleanup; } for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){ aXRef[j] = i; break; } } if( j>=pTab->nCol ){ sqliteSetString(&pParse->zErrMsg, "no such column: ", pChanges->a[i].zName, 0); pParse->nErr++; goto update_cleanup; } } /* Allocate memory for the array apIdx[] and fill it with pointers to every ** index that needs to be updated. Indices only need updating if their ** key includes one of the columns named in pChanges. */ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ | > > > > > > > > | | > > > > | | > | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){ goto update_cleanup; } if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ goto update_cleanup; } } chngRecno = 0; for(i=0; i<pChanges->nExpr; i++){ if( sqliteExprResolveIds(pParse, pTabList, pChanges->a[i].pExpr) ){ goto update_cleanup; } if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){ goto update_cleanup; } for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){ if( i==pTab->iPKey ){ chngRecno = 1; pRecnoExpr = pChanges->a[i].pExpr; } aXRef[j] = i; break; } } if( j>=pTab->nCol ){ sqliteSetString(&pParse->zErrMsg, "no such column: ", pChanges->a[i].zName, 0); pParse->nErr++; goto update_cleanup; } } /* Allocate memory for the array apIdx[] and fill it with pointers to every ** index that needs to be updated. Indices only need updating if their ** key includes one of the columns named in pChanges. */ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( chngRecno ){ i = 0; }else { for(i=0; i<pIdx->nColumn; i++){ if( aXRef[pIdx->aiColumn[i]]>=0 ) break; } } if( i<pIdx->nColumn ) nIdx++; } if( nIdx>0 ){ apIdx = sqliteMalloc( sizeof(Index*) * nIdx ); if( apIdx==0 ) goto update_cleanup; } for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( chngRecno ){ i = 0; }else{ for(i=0; i<pIdx->nColumn; i++){ if( aXRef[pIdx->aiColumn[i]]>=0 ) break; } } if( i<pIdx->nColumn ) apIdx[nIdx++] = pIdx; } /* Begin generating code. */ v = sqliteGetVdbe(pParse); |
︙ | ︙ | |||
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 | sqliteVdbeAddOp(v, openOp, base+i+1, apIdx[i]->tnum); } /* Loop over every record that needs updating. We have to load ** the old data for each record to be updated because some columns ** might not change and we will need to copy the old value. ** Also, the old data is needed to delete the old index entires. */ end = sqliteVdbeMakeLabel(v); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end); sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); /* Delete the old indices for the current record. */ for(i=0; i<nIdx; i++){ sqliteVdbeAddOp(v, OP_Dup, 0, 0); pIdx = apIdx[i]; for(j=0; j<pIdx->nColumn; j++){ sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j]); } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); sqliteVdbeAddOp(v, OP_IdxDelete, base+i+1, 0); } /* Compute new data for this record. */ for(i=0; i<pTab->nCol; i++){ j = aXRef[i]; if( j<0 ){ sqliteVdbeAddOp(v, OP_Column, base, i); }else{ sqliteExprCode(pParse, pChanges->a[j].pExpr); } } /* Insert new index entries that correspond to the new data */ for(i=0; i<nIdx; i++){ sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0); /* The KEY */ pIdx = apIdx[i]; for(j=0; j<pIdx->nColumn; j++){ | > > > > > > > > > > > > > > > > > > > > > > > > | > | 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 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 | sqliteVdbeAddOp(v, openOp, base+i+1, apIdx[i]->tnum); } /* Loop over every record that needs updating. We have to load ** the old data for each record to be updated because some columns ** might not change and we will need to copy the old value. ** Also, the old data is needed to delete the old index entires. ** So make the cursor point at the old record. */ end = sqliteVdbeMakeLabel(v); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end); sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); /* Delete the old indices for the current record. */ for(i=0; i<nIdx; i++){ sqliteVdbeAddOp(v, OP_Dup, 0, 0); pIdx = apIdx[i]; for(j=0; j<pIdx->nColumn; j++){ sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j]); } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); sqliteVdbeAddOp(v, OP_IdxDelete, base+i+1, 0); } /* If changing the record number, remove the old record number ** from the top of the stack and replace it with the new one. */ if( chngRecno ){ sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteExprCode(pParse, pRecnoExpr); sqliteVdbeAddOp(v, OP_AddImm, 0, 0); } /* Compute new data for this record. */ for(i=0; i<pTab->nCol; i++){ if( i==pTab->iPKey ){ sqliteVdbeAddOp(v, OP_Dup, i, 0); continue; } j = aXRef[i]; if( j<0 ){ sqliteVdbeAddOp(v, OP_Column, base, i); }else{ sqliteExprCode(pParse, pChanges->a[j].pExpr); } } /* If changing the record number, delete the hold record. */ if( chngRecno ){ sqliteVdbeAddOp(v, OP_Delete, 0, 0); } /* Insert new index entries that correspond to the new data */ for(i=0; i<nIdx; i++){ sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0); /* The KEY */ pIdx = apIdx[i]; for(j=0; j<pIdx->nColumn; j++){ int idx = pIdx->aiColumn[j]; if( idx==pTab->iPKey ){ sqliteVdbeAddOp(v, OP_Dup, j, 0); }else{ sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-idx, 0); } } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, pIdx->isUnique); } /* Write the new data back into the database. */ |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** ** $Id: vdbe.c,v 1.101 2001/12/21 14:30:43 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveTo or the OP_Next opcode. The test |
︙ | ︙ | |||
1650 1651 1652 1653 1654 1655 1656 | aStack[nos].i = a; aStack[nos].flags = STK_Int; break; } /* Opcode: AddImm P1 * * ** | | > > > | 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 | aStack[nos].i = a; aStack[nos].flags = STK_Int; break; } /* Opcode: AddImm P1 * * ** ** Add the value P1 to whatever is on top of the stack. The result ** is always an integer. ** ** To force the top of the stack to be an integer, just add 0. */ case OP_AddImm: { int tos = p->tos; VERIFY( if( tos<0 ) goto not_enough_stack; ) Integerify(p, tos); aStack[tos].i += pOp->p1; break; |
︙ | ︙ | |||
2265 2266 2267 2268 2269 2270 2271 | sqliteBtreeRollback(db->pBeTemp); } rc = sqliteBtreeRollback(pBt); sqliteRollbackInternalChanges(db); break; } | | > | > > > > > | | > | | > > > | | > | > | > | | 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 | sqliteBtreeRollback(db->pBeTemp); } rc = sqliteBtreeRollback(pBt); sqliteRollbackInternalChanges(db); break; } /* Opcode: ReadCookie * P2 * ** ** When P2==0, ** read the schema cookie from the database file and push it onto the ** stack. The schema cookie is an integer that is used like a version ** number for the database schema. Everytime the schema changes, the ** cookie changes to a new random value. This opcode is used during ** initialization to read the initial cookie value so that subsequent ** database accesses can verify that the cookie has not changed. ** ** If P2>0, then read global database parameter number P2. There is ** a small fixed number of global database parameters. P2==1 is the ** database version number. Other parameters are currently unused. ** ** There must be a read-lock on the database (either a transaction ** must be started or there must be an open cursor) before ** executing this instruction. */ case OP_ReadCookie: { int i = ++p->tos; int aMeta[SQLITE_N_BTREE_META]; assert( pOp->p2<SQLITE_N_BTREE_META ); VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) rc = sqliteBtreeGetMeta(pBt, aMeta); aStack[i].i = aMeta[1+pOp->p2]; aStack[i].flags = STK_Int; break; } /* Opcode: SetCookie P1 P2 * ** ** When P2==0, ** this operation changes the value of the schema cookie on the database. ** The new value is P1. When P2>0, the value of global database parameter ** number P2 is changed. See ReadCookie for more information about ** global database parametes. ** ** The schema cookie changes its value whenever the database schema changes. ** That way, other processes can recognize when the schema has changed ** and reread it. ** ** A transaction must be started before executing this opcode. */ case OP_SetCookie: { int aMeta[SQLITE_N_BTREE_META]; assert( pOp->p2<SQLITE_N_BTREE_META ); rc = sqliteBtreeGetMeta(pBt, aMeta); if( rc==SQLITE_OK ){ aMeta[1+pOp->p2] = pOp->p1; rc = sqliteBtreeUpdateMeta(pBt, aMeta); } break; } /* Opcode: VerifyCookie P1 P2 * ** ** Check the value of global database parameter number P2 and make ** sure it is equal to P1. P2==0 is the schema cookie. P1==1 is ** the database version. If the values do not match, abort with ** an SQLITE_SCHEMA error. ** ** The cookie changes its value whenever the database schema changes. ** This operation is used to detect when that the cookie has changed ** and that the current process needs to reread the schema. ** ** Either a transaction needs to have been started or an OP_Open needs ** to be executed (to establish a read lock) before this opcode is ** invoked. */ case OP_VerifyCookie: { int aMeta[SQLITE_N_BTREE_META]; assert( pOp->p2<SQLITE_N_BTREE_META ); rc = sqliteBtreeGetMeta(pBt, aMeta); if( rc==SQLITE_OK && aMeta[1+pOp->p2]!=pOp->p1 ){ sqliteSetString(pzErrMsg, "database schema has changed", 0); rc = SQLITE_SCHEMA; } break; } /* Opcode: Open P1 P2 P3 |
︙ | ︙ | |||
2609 2610 2611 2612 2613 2614 2615 | break; } /* Opcode: NewRecno P1 * * ** ** Get a new integer record number used as the key to a table. ** The record number is not previously used as a key in the database | | | 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 | break; } /* Opcode: NewRecno P1 * * ** ** Get a new integer record number used as the key to a table. ** The record number is not previously used as a key in the database ** table that cursor P1 points to. The new record number is pushed ** onto the stack. */ case OP_NewRecno: { int i = pOp->p1; int v = 0; Cursor *pC; if( VERIFY( i<0 || i>=p->nCursor || ) (pC = &p->aCsr[i])->pCursor==0 ){ |
︙ | ︙ | |||
2662 2663 2664 2665 2666 2667 2668 | VERIFY( NeedStack(p, p->tos+1); ) p->tos++; aStack[p->tos].i = v; aStack[p->tos].flags = STK_Int; break; } | | > > > > > > > > > > > > > | 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 | VERIFY( NeedStack(p, p->tos+1); ) p->tos++; aStack[p->tos].i = v; aStack[p->tos].flags = STK_Int; break; } /* Opcode: Put P1 P2 * ** ** Write an entry into the database file P1. A new entry is ** created if it doesn't already exist or the data for an existing ** entry is overwritten. The data is the value on the top of the ** stack. The key is the next value down on the stack. The stack ** is popped twice by this instruction. ** ** If P2==1 then overwriting is prohibited. If a prior entry with ** the same key exists, an SQLITE_CONSTRAINT exception is raised. */ case OP_Put: { int tos = p->tos; int nos = p->tos-1; int i = pOp->p1; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){ char *zKey; int nKey, iKey; if( (aStack[nos].flags & STK_Int)==0 ){ if( Stringify(p, nos) ) goto no_mem; nKey = aStack[nos].n; zKey = zStack[nos]; }else{ nKey = sizeof(int); iKey = bigEndian(aStack[nos].i); zKey = (char*)&iKey; } if( pOp->p2 ){ int res; rc = sqliteBtreeMoveto(p->aCsr[i].pCursor, zKey, nKey, &res); if( res==0 && rc==SQLITE_OK ){ rc = SQLITE_CONSTRAINT; } if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey, zStack[tos], aStack[tos].n); } POPSTACK; POPSTACK; break; |
︙ | ︙ |
Added test/intpkey.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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | # 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 the special processing associated # with INTEGER PRIMARY KEY columns. # # $Id: intpkey.test,v 1.1 2001/12/21 14:30:44 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table with a primary key and a datatype other than # integer # do_test intpkey-1.0 { execsql { CREATE TABLE t1(a TEXT PRIMARY KEY, b, c); } } {} # There should be an index associated with the primary key # do_test intpkey-1.1 { execsql { SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='t1'; } } {{(t1 autoindex 1)}} # Now create a table with an integer primary key and verify that # there is no associated index. # do_test intpkey-1.2 { execsql { DROP TABLE t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='t1'; } } {} # Insert some records into the new table. Specify the primary key # and verify that the key is used as the record number. # do_test intpkey-1.3 { execsql { INSERT INTO t1 VALUES(5,'hello','world'); } } {} do_test intpkey-1.4 { execsql { SELECT * FROM t1; } } {5 hello world} do_test intpkey-1.5 { execsql { SELECT rowid, * FROM t1; } } {5 5 hello world} # Attempting to insert a duplicate primary key should give a constraint # failure. # do_test intpkey-1.6 { set r [catch {execsql { INSERT INTO t1 VALUES(5,'second','entry'); }} msg] lappend r $msg } {1 {constraint failed}} do_test intpkey-1.7 { execsql { SELECT rowid, * FROM t1; } } {5 5 hello world} do_test intpkey-1.8 { set r [catch {execsql { INSERT INTO t1 VALUES(6,'second','entry'); }} msg] lappend r $msg } {0 {}} do_test intpkey-1.9 { execsql { SELECT rowid, * FROM t1; } } {5 5 hello world 6 6 second entry} # A ROWID is automatically generated for new records that do not specify # the integer primary key. # do_test intpkey-1.10 { execsql { INSERT INTO t1(b,c) VALUES('one','two'); SELECT b FROM t1 ORDER BY b; } } {hello one second} # Try to change the ROWID for the new entry. # do_test intpkey-1.11 { execsql { UPDATE t1 SET a=7 WHERE b='one'; SELECT * FROM t1; } } {5 hello world 6 second entry 7 one two} # Make sure SELECT statements are able to use the primary key column # as an index. # do_test intpkey-1.12 { execsql { SELECT * FROM t1 WHERE a==7; } } {7 one two} finish_test |
Changes to test/unique.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # 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 UNIQUE INDEX statement, # and primary keys, and the UNIQUE constraint on table columns # | | > > > > > > > > > | 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 45 | # 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 UNIQUE INDEX statement, # and primary keys, and the UNIQUE constraint on table columns # # $Id: unique.test,v 1.3 2001/12/21 14:30:44 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Try to create a table with two primary keys. # (This is allowed in SQLite even that it is not valid SQL) # do_test unique-1.1 { catchsql { CREATE TABLE t1( a int PRIMARY KEY, b int PRIMARY KEY, c text ); } } {1 {table "t1" has more than one primary key}} do_test unique-1.1b { catchsql { CREATE TABLE t1( a int PRIMARY KEY, b int UNIQUE, c text ); } } {0 {}} do_test unique-1.2 { catchsql { INSERT INTO t1(a,b,c) VALUES(1,2,3) } } {0 {}} |
︙ | ︙ |