Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | The BTree changes are now integrated and the whole thing compiles and links. I have not yet tried to run it, though. (CVS 239) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
a0a1e701abc52a164d9b09a5426eb12a |
User & Date: | drh 2001-09-13 14:46:10.000 |
Context
2001-09-13
| ||
15:21 | The new Btree code runs, but it does not yet work. (CVS 240) (check-in: 991ce81150 user: drh tags: trunk) | |
14:46 | The BTree changes are now integrated and the whole thing compiles and links. I have not yet tried to run it, though. (CVS 239) (check-in: a0a1e701ab user: drh tags: trunk) | |
13:46 | The code is in place to replace GDBM with BTree. But I have not yet attempted to compile it. I am sure the code contains bugs. (CVS 238) (check-in: 6ecc8b20d4 user: drh tags: trunk) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
43 44 45 46 47 48 49 | # The library that programs using readline() must link against. # LIBREADLINE = @TARGET_READLINE_LIBS@ # Object files for the SQLite library. # | | | | < < < > | 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 | # The library that programs using readline() must link against. # LIBREADLINE = @TARGET_READLINE_LIBS@ # Object files for the SQLite library. # LIBOBJ = btree.o build.o delete.o expr.o insert.o \ main.o pager.o parse.o printf.o random.o select.o table.o \ tokenize.o update.o util.o vdbe.o where.o tclsqlite.o # All of the source code files. # SRC = \ $(TOP)/src/btree.c \ $(TOP)/src/btree.h \ $(TOP)/src/build.c \ $(TOP)/src/delete.c \ $(TOP)/src/expr.c \ $(TOP)/src/insert.c \ $(TOP)/src/main.c \ $(TOP)/src/pager.c \ $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ $(TOP)/src/printf.c \ $(TOP)/src/random.c \ $(TOP)/src/select.c \ $(TOP)/src/shell.c \ $(TOP)/src/sqlite.h.in \ $(TOP)/src/sqliteInt.h \ |
︙ | ︙ | |||
117 118 119 120 121 122 123 | $(BCC) -o lemon $(TOP)/tool/lemon.c cp $(TOP)/tool/lempar.c . # Header files used by all library source files. # HDR = \ sqlite.h \ | | | | < < < < < < < < < | | 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 | $(BCC) -o lemon $(TOP)/tool/lemon.c cp $(TOP)/tool/lempar.c . # Header files used by all library source files. # HDR = \ sqlite.h \ $(TOP)/src/btree.h \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/vdbe.h \ parse.h btree.o: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/btree.c build.o: $(TOP)/src/build.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/build.c main.o: $(TOP)/src/main.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/main.c pager.o: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/pager.c parse.o: parse.c $(HDR) $(TCC) $(GDBM_FLAGS) -c parse.c parse.h: parse.c |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** Boston, MA 02111-1307, USA. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** Boston, MA 02111-1307, USA. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** $Id: btree.c,v 1.23 2001/09/13 14:46:10 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
722 723 724 725 726 727 728 | if( pBt->inTrans ) return SQLITE_ERROR; if( pBt->page1==0 ){ rc = lockBtree(pBt); if( rc!=SQLITE_OK ){ return rc; } } | | | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | if( pBt->inTrans ) return SQLITE_ERROR; if( pBt->page1==0 ){ rc = lockBtree(pBt); if( rc!=SQLITE_OK ){ return rc; } } if( !sqlitepager_isreadonly(pBt->pPager) ){ rc = sqlitepager_write(pBt->page1); if( rc!=SQLITE_OK ){ return rc; } rc = newDatabase(pBt); } pBt->inTrans = 1; |
︙ | ︙ | |||
2008 2009 2010 2011 2012 2013 2014 | ** Insert a new record into the BTree. The key is given by (pKey,nKey) ** and the data is given by (pData,nData). The cursor is used only to ** define what database the record should be inserted into. The cursor ** is left pointing at the new record. */ int sqliteBtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ | | | 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 | ** Insert a new record into the BTree. The key is given by (pKey,nKey) ** and the data is given by (pData,nData). The cursor is used only to ** define what database the record should be inserted into. The cursor ** is left pointing at the new record. */ int sqliteBtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ const void *pKey, int nKey, /* The key of the new record */ const void *pData, int nData /* The data of the new record */ ){ Cell newCell; int rc; int loc; int szNew; MemPage *pPage; |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. ** | | > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. ** ** @(#) $Id: btree.h,v 1.12 2001/09/13 14:46:10 drh Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ typedef struct Btree Btree; typedef struct BtCursor BtCursor; int sqliteBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree); int sqliteBtreeClose(Btree*); |
︙ | ︙ | |||
58 59 60 61 62 63 64 | int sqliteBtreeGetMeta(Btree*, int*); int sqliteBtreeUpdateMeta(Btree*, int*); #ifdef SQLITE_TEST int sqliteBtreePageDump(Btree*, int, int); int sqliteBtreeCursorDump(BtCursor*, int*); | | > > | 60 61 62 63 64 65 66 67 68 69 70 71 | int sqliteBtreeGetMeta(Btree*, int*); int sqliteBtreeUpdateMeta(Btree*, int*); #ifdef SQLITE_TEST int sqliteBtreePageDump(Btree*, int, int); int sqliteBtreeCursorDump(BtCursor*, int*); struct Pager *sqliteBtreePager(Btree*); char *sqliteBtreeSanityCheck(Btree*, int*, int); #endif #endif /* _BTREE_H_ */ |
Changes to src/build.c.
︙ | ︙ | |||
29 30 31 32 33 34 35 | ** DROP TABLE ** CREATE INDEX ** DROP INDEX ** creating expressions and ID lists ** COPY ** VACUUM ** | | > | | | | 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 | ** DROP TABLE ** CREATE INDEX ** DROP INDEX ** creating expressions and ID lists ** COPY ** VACUUM ** ** $Id: build.c,v 1.30 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" /* ** This routine is called after a single SQL statement has been ** parsed and we want to execute the VDBE code to implement ** that statement. Prior action routines should have already ** constructed VDBE code to do the work of the SQL statement. ** This routine just has to execute the VDBE code. ** ** Note that if an error occurred, it might be the case that ** no VDBE code was generated. */ void sqliteExec(Parse *pParse){ int rc = SQLITE_OK; sqlite *db = pParse->db; if( sqlite_malloc_failed ) return; if( pParse->pVdbe ){ if( pParse->explain ){ rc = sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg, &pParse->zErrMsg); }else{ FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stderr : 0; sqliteVdbeTrace(pParse->pVdbe, trace); rc = sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg, &pParse->zErrMsg, db->pBusyArg, db->xBusyCallback); } sqliteVdbeDelete(pParse->pVdbe); pParse->pVdbe = 0; pParse->colNamesSet = 0; pParse->rc = rc; } } |
︙ | ︙ | |||
254 255 256 257 258 259 260 | ** See also: sqliteRollbackInternalChanges() */ void sqliteCommitInternalChanges(sqlite *db){ int i; if( (db->flags & SQLITE_InternChanges)==0 ) return; for(i=0; i<N_HASH; i++){ Table *pTable, *pNext; | | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | ** See also: sqliteRollbackInternalChanges() */ void sqliteCommitInternalChanges(sqlite *db){ int i; if( (db->flags & SQLITE_InternChanges)==0 ) return; for(i=0; i<N_HASH; i++){ Table *pTable, *pNext; for(pTable = db->apTblHash[i]; pTable; pTable=pNext){ pNext = pTable->pHash; if( pTable->isDelete ){ sqliteDeleteTable(db, pTable); }else if( pTable->isCommit==0 ){ pTable->isCommit = 1; } } } for(i=0; i<N_HASH; i++){ Index *pIndex, *pNext; for(pIndex = db->apIdxHash[i]; pIndex; pIndex=pNext){ pNext = pIndex->pHash; if( pIndex->isDelete ){ sqliteUnlinkAndDeleteIndex(db, pIndex); }else if( pIndex->isCommit==0 ){ pIndex->isCommit = 1; } } |
︙ | ︙ | |||
290 291 292 293 294 295 296 | ** See also: sqliteCommitInternalChanges() */ void sqliteRollbackInternalChanges(sqlite *db){ int i; if( (db->flags & SQLITE_InternChanges)==0 ) return; for(i=0; i<N_HASH; i++){ Table *pTable, *pNext; | | | | 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 | ** See also: sqliteCommitInternalChanges() */ void sqliteRollbackInternalChanges(sqlite *db){ int i; if( (db->flags & SQLITE_InternChanges)==0 ) return; for(i=0; i<N_HASH; i++){ Table *pTable, *pNext; for(pTable = db->apTblHash[i]; pTable; pTable=pNext){ pNext = pTable->pHash; if( !pTable->isCommit ){ sqliteDeleteTable(db, pTable); }else if( pTable->isDelete ){ pTable->isDelete = 0; } } } for(i=0; i<N_HASH; i++){ Index *pIndex, *pNext; for(pIndex = db->apIdxHash[i]; pIndex; pIndex=pNext){ pNext = pIndex->pHash; if( !pIndex->isCommit ){ sqliteUnlinkAndDeleteIndex(db, pIndex); }else if( pIndex->isDelete ){ pIndex->isDelete = 0; } } |
︙ | ︙ | |||
339 340 341 342 343 344 345 346 347 348 349 | ** The new table is constructed in files of the pParse structure. As ** more of the CREATE TABLE statement is parsed, additional action ** routines are called to build up more of the table. */ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){ Table *pTable; char *zName; pParse->sFirstToken = *pStart; zName = sqliteTableNameFromToken(pName); if( zName==0 ) return; | > | | | | | 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 | ** The new table is constructed in files of the pParse structure. As ** more of the CREATE TABLE statement is parsed, additional action ** routines are called to build up more of the table. */ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){ Table *pTable; char *zName; sqlite *db = pParse->db; pParse->sFirstToken = *pStart; zName = sqliteTableNameFromToken(pName); if( zName==0 ) return; pTable = sqliteFindTable(db, zName); if( pTable!=0 ){ sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n, " already exists", 0, 0); sqliteFree(zName); pParse->nErr++; return; } if( sqliteFindIndex(db, zName) ){ sqliteSetString(&pParse->zErrMsg, "there is already an index named ", zName, 0); sqliteFree(zName); pParse->nErr++; return; } pTable = sqliteMalloc( sizeof(Table) ); if( pTable==0 ) return; pTable->zName = zName; pTable->pHash = 0; pTable->nCol = 0; pTable->aCol = 0; pTable->pIndex = 0; if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; if( !pParse->initFlag && (db->flags & SQLITE_InTrans)==0 ){ Vdbe *v = sqliteGetVdbe(pParse); if( v ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } } } |
︙ | ︙ | |||
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | ** the master table because we just connected to the database, so ** the entry for this table already exists in the master table. ** We do not want to create it again. */ void sqliteEndTable(Parse *pParse, Token *pEnd){ Table *p; int h; if( pEnd==0 || pParse->nErr || sqlite_malloc_failed ) return; p = pParse->pNewTable; if( p==0 ) return; /* Add the table to the in-memory representation of the database */ if( pParse->explain==0 ){ h = sqliteHashNoCase(p->zName, 0) % N_HASH; | > | | | | 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 | ** the master table because we just connected to the database, so ** the entry for this table already exists in the master table. ** We do not want to create it again. */ void sqliteEndTable(Parse *pParse, Token *pEnd){ Table *p; int h; sqlite *db = pParse->db; if( pEnd==0 || pParse->nErr || sqlite_malloc_failed ) return; p = pParse->pNewTable; if( p==0 ) return; /* Add the table to the in-memory representation of the database */ if( pParse->explain==0 ){ h = sqliteHashNoCase(p->zName, 0) % N_HASH; p->pHash = db->apTblHash[h]; db->apTblHash[h] = p; pParse->pNewTable = 0; db->nTable++; db->flags |= SQLITE_InternChanges; } /* If not initializing, then create the table on disk. */ if( !pParse->initFlag ){ static VdbeOp addTable[] = { |
︙ | ︙ | |||
480 481 482 483 484 485 486 | n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1; base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable); sqliteVdbeChangeP3(v, base+3, p->zName, 0); sqliteVdbeTableRootAddr(v, &p->tnum); sqliteVdbeChangeP3(v, base+5, p->zName, 0); sqliteVdbeChangeP3(v, base+6, pParse->sFirstToken.z, n); sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0); | | | 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 | n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1; base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable); sqliteVdbeChangeP3(v, base+3, p->zName, 0); sqliteVdbeTableRootAddr(v, &p->tnum); sqliteVdbeChangeP3(v, base+5, p->zName, 0); sqliteVdbeChangeP3(v, base+6, pParse->sFirstToken.z, n); sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0); if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } } } /* ** Given a token, look up a table with that name. If not found, leave |
︙ | ︙ | |||
511 512 513 514 515 516 517 | /* ** This routine is called to do the work of a DROP TABLE statement. ** pName is the name of the table to be dropped. */ void sqliteDropTable(Parse *pParse, Token *pName){ Table *pTable; | < | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | /* ** This routine is called to do the work of a DROP TABLE statement. ** pName is the name of the table to be dropped. */ void sqliteDropTable(Parse *pParse, Token *pName){ Table *pTable; Vdbe *v; int base; if( pParse->nErr || sqlite_malloc_failed ) return; pTable = sqliteTableFromToken(pParse, pName); if( pTable==0 ) return; if( pTable->readOnly ){ |
︙ | ︙ | |||
565 566 567 568 569 570 571 | ** deletion occurs inside of sqliteCommitInternalChanges(). ** ** Exception: if the SQL statement began with the EXPLAIN keyword, ** then no changes should be made. */ if( !pParse->explain ){ pTable->isDelete = 1; | | | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | ** deletion occurs inside of sqliteCommitInternalChanges(). ** ** Exception: if the SQL statement began with the EXPLAIN keyword, ** then no changes should be made. */ if( !pParse->explain ){ pTable->isDelete = 1; pParse->db->flags |= SQLITE_InternChanges; } } /* ** 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. In that case, use pParse->pNewTable as the |
︙ | ︙ | |||
591 592 593 594 595 596 597 598 599 600 601 602 603 604 | Token *pEnd /* The ")" that closes the CREATE INDEX statement */ ){ Table *pTab; /* Table to be indexed */ Index *pIndex; /* The index to be created */ char *zName = 0; int i, j, h; Token nullId; /* Fake token for an empty ID list */ if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index; /* ** Find the table that is to be indexed. Return early if not found. */ if( pTable!=0 ){ | > | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 | Token *pEnd /* The ")" that closes the CREATE INDEX statement */ ){ Table *pTab; /* Table to be indexed */ Index *pIndex; /* The index to be created */ char *zName = 0; int i, j, h; Token nullId; /* Fake token for an empty ID list */ sqlite *db = pParse->db; if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index; /* ** Find the table that is to be indexed. Return early if not found. */ if( pTable!=0 ){ |
︙ | ︙ | |||
621 622 623 624 625 626 627 | if( pName ){ zName = sqliteTableNameFromToken(pName); }else{ zName = 0; sqliteSetString(&zName, pTab->zName, "__primary_key", 0); } if( zName==0 ) goto exit_create_index; | | | | 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 | if( pName ){ zName = sqliteTableNameFromToken(pName); }else{ zName = 0; sqliteSetString(&zName, pTab->zName, "__primary_key", 0); } if( zName==0 ) goto exit_create_index; if( sqliteFindIndex(db, zName) ){ sqliteSetString(&pParse->zErrMsg, "index ", zName, " already exists", 0); pParse->nErr++; goto exit_create_index; } if( sqliteFindTable(db, zName) ){ sqliteSetString(&pParse->zErrMsg, "there is already a table named ", zName, 0); pParse->nErr++; goto exit_create_index; } /* If pList==0, it means this routine was called to make a primary |
︙ | ︙ | |||
680 681 682 683 684 685 686 | } /* Link the new Index structure to its table and to the other ** in-memory database structures. */ if( pParse->explain==0 ){ h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH; | | | | 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 | } /* Link the new Index structure to its table and to the other ** in-memory database structures. */ if( pParse->explain==0 ){ h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH; pIndex->pHash = db->apIdxHash[h]; db->apIdxHash[h] = pIndex; pIndex->pNext = pTab->pIndex; pTab->pIndex = pIndex; db->flags |= SQLITE_InternChanges; } /* If the initFlag is 0 then create the index on disk. This ** involves writing the index into the master table and filling in the |
︙ | ︙ | |||
717 718 719 720 721 722 723 | int n; Vdbe *v = pParse->pVdbe; int lbl1, lbl2; int i; v = sqliteGetVdbe(pParse); if( v==0 ) goto exit_create_index; | | | | | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 | int n; Vdbe *v = pParse->pVdbe; int lbl1, lbl2; int i; v = sqliteGetVdbe(pParse); if( v==0 ) goto exit_create_index; if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0); sqliteVdbeAddOp(v, OP_Open, 1, pIndex->tnum, pIndex->zName, 0); if( pStart && pEnd ){ int base; n = (int)pEnd->z - (int)pStart->z + 1; base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable); sqliteVdbeChangeP3(v, base+3, pIndex->zName, 0); sqliteVdbeIndexRootAddr(v, &pIndex->tnum); sqliteVdbeChangeP3(v, base+5, pTab->zName, 0); sqliteVdbeChangeP3(v, base+6, pStart->z, n); } lbl1 = sqliteVdbeMakeLabel(v); lbl2 = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1); sqliteVdbeAddOp(v, OP_Recno, 0, 0, 0, 0); for(i=0; i<pIndex->nColumn; i++){ sqliteVdbeAddOp(v, OP_Column, 0, pIndex->aiColumn[i], 0, 0); } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_PutIdx, 1, 0, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0); sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2); sqliteVdbeAddOp(v, OP_Close, 1, 0, 0, 0); sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0); if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } } /* Reclaim memory on an EXPLAIN call. */ if( pParse->explain ){ |
︙ | ︙ | |||
769 770 771 772 773 774 775 776 777 778 779 | /* ** This routine will drop an existing named index. */ void sqliteDropIndex(Parse *pParse, Token *pName){ Index *pIndex; char *zName; Vdbe *v; if( pParse->nErr || sqlite_malloc_failed ) return; zName = sqliteTableNameFromToken(pName); if( zName==0 ) return; | > | | | | | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 | /* ** This routine will drop an existing named index. */ void sqliteDropIndex(Parse *pParse, Token *pName){ Index *pIndex; char *zName; Vdbe *v; sqlite *db = pParse->db; if( pParse->nErr || sqlite_malloc_failed ) return; zName = sqliteTableNameFromToken(pName); if( zName==0 ) return; pIndex = sqliteFindIndex(db, zName); sqliteFree(zName); if( pIndex==0 ){ sqliteSetNString(&pParse->zErrMsg, "no such index: ", 0, pName->z, pName->n, 0); pParse->nErr++; return; } /* Generate code to remove the index and from the master table */ v = sqliteGetVdbe(pParse); if( v ){ static VdbeOp dropIndex[] = { { OP_Open, 0, 2, 0}, { OP_String, 0, 0, 0}, /* 1 */ { OP_Next, 0, ADDR(8), 0}, /* 2 */ { OP_Dup, 0, 0, 0}, { OP_Column, 0, 1, 0}, { OP_Ne, 0, ADDR(2), 0}, { OP_Recno, 0, 0, 0}, { OP_Delete, 0, 0, 0}, { OP_Destroy, 0, 0, 0}, /* 8 */ { OP_Close, 0, 0, 0}, }; int base; if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex); sqliteVdbeChangeP1(v, base+8, pIndex->tnum); if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } } /* Mark the internal Index structure for deletion by the ** sqliteCommitInternalChanges routine. */ |
︙ | ︙ | |||
948 949 950 951 952 953 954 955 956 957 | ){ Table *pTab; char *zTab; int i, j; Vdbe *v; int addr, end; Index *pIdx; zTab = sqliteTableNameFromToken(pTableName); if( sqlite_malloc_failed || zTab==0 ) goto copy_cleanup; | > | | | 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 | ){ Table *pTab; char *zTab; int i, j; Vdbe *v; int addr, end; Index *pIdx; sqlite *db = pParse->db; zTab = sqliteTableNameFromToken(pTableName); if( sqlite_malloc_failed || zTab==0 ) goto copy_cleanup; pTab = sqliteFindTable(db, zTab); sqliteFree(zTab); if( pTab==0 ){ sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0, pTableName->z, pTableName->n, 0); pParse->nErr++; goto copy_cleanup; } if( pTab->readOnly ){ sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " may not be modified", 0); pParse->nErr++; goto copy_cleanup; } v = sqliteGetVdbe(pParse); if( v ){ if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0); sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n); sqliteVdbeDequoteP3(v, addr); sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ |
︙ | ︙ | |||
1006 1007 1008 1009 1010 1011 1012 | sqliteVdbeAddOp(v, OP_FileColumn, pIdx->aiColumn[j], 0, 0, 0); } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_PutIdx, i, 0, 0, 0); } sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0); sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, end); | | > | | | | | < < < | 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 | sqliteVdbeAddOp(v, OP_FileColumn, pIdx->aiColumn[j], 0, 0, 0); } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_PutIdx, i, 0, 0, 0); } sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0); sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, end); if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } } copy_cleanup: return; } /* ** The non-standard VACUUM command is used to clean up the database, ** collapse free space, etc. It is modelled after the VACUUM command ** in PostgreSQL. */ void sqliteVacuum(Parse *pParse, Token *pTableName){ char *zName; Vdbe *v; sqlite *db = pParse->db; if( pParse->nErr || sqlite_malloc_failed ) return; if( pTableName ){ zName = sqliteTableNameFromToken(pTableName); }else{ zName = 0; } if( zName && sqliteFindIndex(db, zName)==0 && sqliteFindTable(db, zName)==0 ){ sqliteSetString(&pParse->zErrMsg, "no such table or index: ", zName, 0); pParse->nErr++; goto vacuum_cleanup; } v = sqliteGetVdbe(pParse); if( v==0 ) goto vacuum_cleanup; if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } if( zName ){ sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, zName, 0); }else{ int h; Table *pTab; Index *pIdx; for(h=0; h<N_HASH; h++){ for(pTab=db->apTblHash[h]; pTab; pTab=pTab->pHash){ sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, pTab->zName, 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, pIdx->zName, 0); } } } } if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } vacuum_cleanup: sqliteFree(zName); return; } /* ** Begin a transaction */ void sqliteBeginTransaction(Parse *pParse){ sqlite *db; Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return; if( pParse->nErr || sqlite_malloc_failed ) return; if( db->flags & SQLITE_InTrans ) return; v = sqliteGetVdbe(pParse); if( v ){ sqliteVdbeAddOp(v, OP_Transaction, 1, 0, 0, 0); } db->flags |= SQLITE_InTrans; } /* ** Commit a transaction */ void sqliteCommitTransaction(Parse *pParse){ sqlite *db; Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return; if( pParse->nErr || sqlite_malloc_failed ) return; if( (db->flags & SQLITE_InTrans)==0 ) return; v = sqliteGetVdbe(pParse); if( v ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } db->flags &= ~SQLITE_InTrans; } /* ** Rollback a transaction */ void sqliteRollbackTransaction(Parse *pParse){ sqlite *db; Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return; if( pParse->nErr || sqlite_malloc_failed ) return; if( (db->flags & SQLITE_InTrans)==0 ) return; v = sqliteGetVdbe(pParse); if( v ){ sqliteVdbeAddOp(v, OP_Rollback, 0, 0, 0, 0); } db->flags &= ~SQLITE_InTrans; } |
Deleted src/dbbe.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/dbbe.h.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/dbbebtree.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/dbbegdbm.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted src/dbbemem.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/delete.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** ** $Id: delete.c,v 1.11 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" /* ** Process a DELETE FROM statement. */ void sqliteDeleteFrom( |
︙ | ︙ | |||
133 134 135 136 137 138 139 | for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Open, base+i, pIdx->tnum, 0, 0); } end = sqliteVdbeMakeLabel(v); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0); if( pTab->pIndex ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); | | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Open, base+i, pIdx->tnum, 0, 0); } end = sqliteVdbeMakeLabel(v); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0); if( pTab->pIndex ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_MoveTo, base, 0, 0, 0); for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ int j; sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); for(j=0; j<pIdx->nColumn; j++){ sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j], 0, 0); } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0, 0, 0); } } sqliteVdbeAddOp(v, OP_Delete, base, 0, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0); |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions. ** | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions. ** ** $Id: expr.c,v 1.26 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" /* ** Walk an expression tree. Return 1 if the expression is constant ** and 0 if it involves variables. */ |
︙ | ︙ | |||
242 243 244 245 246 247 248 | if( pExpr->pSelect ){ /* Case 1: expr IN (SELECT ...) ** ** Generate code to write the results of the select into a temporary ** table. The cursor number of the temporary table has already ** been put in iTable by sqliteExprResolveInSelect(). */ | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | if( pExpr->pSelect ){ /* Case 1: expr IN (SELECT ...) ** ** Generate code to write the results of the select into a temporary ** table. The cursor number of the temporary table has already ** been put in iTable by sqliteExprResolveInSelect(). */ sqliteVdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 0, 0, 0); if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) ); }else if( pExpr->pList ){ /* Case 2: expr IN (exprlist) ** ** Create a set to put the exprlist values in. The Set id is stored ** in iTable. */ |
︙ | ︙ | |||
511 512 513 514 515 516 517 | default: break; } switch( pExpr->op ){ case TK_COLUMN: { if( pParse->useAgg ){ sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg, 0, 0); }else if( pExpr->iColumn>=0 ){ | | | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | default: break; } switch( pExpr->op ){ case TK_COLUMN: { if( pParse->useAgg ){ sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg, 0, 0); }else if( pExpr->iColumn>=0 ){ sqliteVdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn, 0, 0); }else{ sqliteVdbeAddOp(v, OP_FullKey, pExpr->iTable, 0, 0, 0); } break; } case TK_INTEGER: { int i = atoi(pExpr->token.z); sqliteVdbeAddOp(v, OP_Integer, i, 0, 0, 0); break; |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements. ** | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements. ** ** $Id: insert.c,v 1.15 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" /* ** This routine is call to handle SQL of the following forms: ** ** insert into TABLE (IDLIST) values(EXPRLIST) |
︙ | ︙ | |||
94 95 96 97 98 99 100 | ** all the code to implement the SELECT statement and leave the data ** in a temporary table. If data is coming from an expression list, ** then we just have to count the number of expressions. */ if( pSelect ){ int rc; srcTab = pParse->nTab++; | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | ** all the code to implement the SELECT statement and leave the data ** in a temporary table. If data is coming from an expression list, ** then we just have to count the number of expressions. */ if( pSelect ){ int rc; srcTab = pParse->nTab++; sqliteVdbeAddOp(v, OP_OpenTemp, srcTab, 0, 0, 0); rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab); if( rc || pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; assert( pSelect->pEList ); nColumn = pSelect->pEList->nExpr; }else{ assert( pList!=0 ); srcTab = -1; |
︙ | ︙ | |||
159 160 161 162 163 164 165 | } } /* Open cursors into the table that is received the new data and ** all indices of that table. */ base = pParse->nTab; | | | | | | 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 | } } /* Open cursors into the table that is received the new data and ** all indices of that table. */ base = pParse->nTab; sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, pTab->zName, 0); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ sqliteVdbeAddOp(v, OP_Open, idx+base, pIdx->tnum, pIdx->zName, 0); } /* If the data source is a SELECT statement, then we have to create ** a loop because there might be multiple rows of data. If the data ** source is an expression list, then exactly one row will be inserted ** and the loop is not used. */ if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Rewind, srcTab, 0, 0, 0); iBreak = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeAddOp(v, OP_Next, srcTab, iBreak, 0, 0); } /* Create a new entry in the table and fill it with data. */ sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0); if( pTab->pIndex ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); } for(i=0; i<pTab->nCol; i++){ 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 ){ char *zDflt = pTab->aCol[i].zDflt; if( zDflt==0 ){ sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0); }else{ sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0); } }else if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Column, srcTab, i, 0, 0); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } } sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0); sqliteVdbeAddOp(v, OP_Put, base, 0, 0, 0); |
︙ | ︙ | |||
229 230 231 232 233 234 235 | char *zDflt = pTab->aCol[idx].zDflt; if( zDflt==0 ){ sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0); }else{ sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0); } }else if( srcTab>=0 ){ | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | char *zDflt = pTab->aCol[idx].zDflt; if( zDflt==0 ){ sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0); }else{ sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0); } }else if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Column, srcTab, idx, 0, 0); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_PutIdx, idx+base, 0, 0, 0); } |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | ** ************************************************************************* ** 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. ** | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ** ************************************************************************* ** 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.31 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" #if defined(HAVE_USLEEP) && HAVE_USLEEP #include <unistd.h> #endif /* |
︙ | ︙ | |||
229 230 231 232 233 234 235 | default: { if( pzErrMsg ){ sqliteSetString(pzErrMsg, "unable to open database: ", zFilename, 0); } } } sqliteFree(db); | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | default: { if( pzErrMsg ){ sqliteSetString(pzErrMsg, "unable to open database: ", zFilename, 0); } } } sqliteFree(db); return 0; } /* Assume file format 1 unless the database says otherwise */ db->file_format = 1; /* Attempt to read the schema */ rc = sqliteInit(db, pzErrMsg); |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | ************************************************************************* ** This is the implementation of the page cache subsystem. ** ** The page cache is used to access a database file. The pager journals ** all writes in order to support rollback. Locking is used to limit ** access to one or more reader or to one writer. ** | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | ************************************************************************* ** This is the implementation of the page cache subsystem. ** ** The page cache is used to access a database file. The pager journals ** all writes in order to support rollback. Locking is used to limit ** access to one or more reader or to one writer. ** ** @(#) $Id: pager.c,v 1.15 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" #include <fcntl.h> #include <sys/stat.h> #include <unistd.h> #include <assert.h> |
︙ | ︙ | |||
472 473 474 475 476 477 478 | "/temp", "./temp", }; int i; struct stat buf; for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ if( stat(azDirs[i], &buf)==0 && S_ISDIR(buf.st_mode) | | | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 | "/temp", "./temp", }; int i; struct stat buf; for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ if( stat(azDirs[i], &buf)==0 && S_ISDIR(buf.st_mode) && access(azDirs[i], W_OK) ){ return azDirs[i]; } } return 0; } /* |
︙ | ︙ | |||
511 512 513 514 515 516 517 | if( fd<0 ){ fd = open(zFilename, O_RDONLY, 0); readOnly = 1; } tempFile = 0; }else{ int cnt = 8; | | | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 | if( fd<0 ){ fd = open(zFilename, O_RDONLY, 0); readOnly = 1; } tempFile = 0; }else{ int cnt = 8; const char *zDir = findTempDir(); if( zDir==0 ) return SQLITE_CANTOPEN; do{ cnt--; sprintf(zTemp,"%s/_sqlite_%u", zDir, (unsigned)sqliteRandomInteger()); fd = open(zTemp, O_RDWR|O_CREAT|O_EXCL, 0600); }while( cnt>0 && fd<0 ); zFilename = zTemp; tempFile = 1; } if( fd<0 ){ return SQLITE_CANTOPEN; |
︙ | ︙ | |||
1134 1135 1136 1137 1138 1139 1140 | }; /* ** Return TRUE if the database file is opened read-only. Return FALSE ** if the database is (in theory) writable. */ int sqlitepager_isreadonly(Pager *pPager){ | | | 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 | }; /* ** Return TRUE if the database file is opened read-only. Return FALSE ** if the database is (in theory) writable. */ int sqlitepager_isreadonly(Pager *pPager){ return pPager->readOnly; } /* ** This routine is used for testing and analysis only. */ int *sqlitepager_stats(Pager *pPager){ static int a[9]; |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements. ** | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements. ** ** $Id: select.c,v 1.33 2001/09/13 14:46:10 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ |
︙ | ︙ | |||
118 119 120 121 122 123 124 | if( pEList ){ for(i=0; i<pEList->nExpr; i++){ sqliteExprCode(pParse, pEList->a[i].pExpr); } nColumn = pEList->nExpr; }else{ for(i=0; i<nColumn; i++){ | | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | if( pEList ){ for(i=0; i<pEList->nExpr; i++){ sqliteExprCode(pParse, pEList->a[i].pExpr); } nColumn = pEList->nExpr; }else{ for(i=0; i<nColumn; i++){ sqliteVdbeAddOp(v, OP_Column, srcTab, i, 0, 0); } } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ |
︙ | ︙ | |||
167 168 169 170 171 172 173 | sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0); }else /* Store the result as data using a unique key. */ if( eDest==SRT_Table ){ sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0, 0, 0); | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0); }else /* Store the result as data using a unique key. */ if( eDest==SRT_Table ){ sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_NewRecno, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_Pull, 1, 0, 0, 0); sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0); }else /* Construct a record from the query result, but instead of ** saving that record, use it as a key to delete elements from ** the temporary table iParm. |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
19 20 21 22 23 24 25 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | < | < | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.44 2001/09/13 14:46:10 drh Exp $ */ #include "sqlite.h" #include "vdbe.h" #include "parse.h" #include "btree.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> /* ** The paging system deals with 32-bit integers. |
︙ | ︙ | |||
178 179 180 181 182 183 184 | Table *pHash; /* Next table with same hash on zName */ int nCol; /* Number of columns in this table */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Page containing root for this table */ int readOnly; /* True if this table should not be written by the user */ int isCommit; /* True if creation of this table has been committed */ | | | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | Table *pHash; /* Next table with same hash on zName */ int nCol; /* Number of columns in this table */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Page containing root for this table */ int readOnly; /* True if this table should not be written by the user */ int isCommit; /* True if creation of this table has been committed */ int isDelete; /* True if this table is being deleted */ }; /* ** 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 |
︙ | ︙ | |||
206 207 208 209 210 211 212 213 214 215 216 217 218 219 | */ struct Index { char *zName; /* Name of this index */ Index *pHash; /* Next index with the same hash on zName */ int nColumn; /* Number of columns in the table used by this index */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */ Table *pTable; /* The SQL table being indexed */ int isUnique; /* True if keys must all be unique */ int isCommit; /* True if creation of this index has been committed */ int isDelete; /* True if deletion of this index has not been comitted */ Index *pNext; /* The next index associated with the same table */ }; /* | > | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | */ struct Index { char *zName; /* Name of this index */ Index *pHash; /* Next index with the same hash on zName */ int nColumn; /* Number of columns in the table used by this index */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */ Table *pTable; /* The SQL table being indexed */ int tnum; /* Page containing root of this index in database file */ int isUnique; /* True if keys must all be unique */ int isCommit; /* True if creation of this index has been committed */ int isDelete; /* True if deletion of this index has not been comitted */ Index *pNext; /* The next index associated with the same table */ }; /* |
︙ | ︙ | |||
441 442 443 444 445 446 447 | void sqliteExprResolveInSelect(Parse*, Expr*); int sqliteExprAnalyzeAggregates(Parse*, Expr*); void sqliteParseInfoReset(Parse*); Vdbe *sqliteGetVdbe(Parse*); int sqliteRandomByte(void); int sqliteRandomInteger(void); void sqliteRandomName(char*,char*); | < | 440 441 442 443 444 445 446 447 448 449 450 451 | void sqliteExprResolveInSelect(Parse*, Expr*); int sqliteExprAnalyzeAggregates(Parse*, Expr*); void sqliteParseInfoReset(Parse*); Vdbe *sqliteGetVdbe(Parse*); int sqliteRandomByte(void); int sqliteRandomInteger(void); void sqliteRandomName(char*,char*); void sqliteBeginTransaction(Parse*); void sqliteCommitTransaction(Parse*); void sqliteRollbackTransaction(Parse*); char *sqlite_mprintf(const char *, ...); const char *sqliteErrStr(int); |
Changes to src/vdbe.c.
︙ | ︙ | |||
37 38 39 40 41 42 43 | ** inplicit conversion from one 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. ** | | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ** inplicit conversion from one 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.61 2001/09/13 14:46:11 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** SQL is translated into a sequence of instructions to be ** executed by a virtual machine. Each instruction is an instance |
︙ | ︙ | |||
190 191 192 193 194 195 196 | }; /* ** An instance of the virtual machine */ struct Vdbe { sqlite *db; /* The whole database */ | | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | }; /* ** An instance of the virtual machine */ struct Vdbe { sqlite *db; /* The whole database */ Btree *pBt; /* Opaque context structure used by DB backend */ FILE *trace; /* Write an execution trace here, if not NULL */ int nOp; /* Number of instructions in the program */ int nOpAlloc; /* Number of slots allocated for aOp[] */ Op *aOp; /* Space to hold the virtual machine's program */ int nLabel; /* Number of labels used */ int nLabelAlloc; /* Number of slots allocated in aLabel[] */ int *aLabel; /* Space to hold the labels */ |
︙ | ︙ | |||
231 232 233 234 235 236 237 | /* ** Create a new virtual database engine. */ Vdbe *sqliteVdbeCreate(sqlite *db){ Vdbe *p; p = sqliteMalloc( sizeof(Vdbe) ); if( p==0 ) return 0; | | | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | /* ** Create a new virtual database engine. */ Vdbe *sqliteVdbeCreate(sqlite *db){ Vdbe *p; p = sqliteMalloc( sizeof(Vdbe) ); if( p==0 ) return 0; p->pBt = db->pBe; p->db = db; return p; } /* ** Turn tracing on or off */ |
︙ | ︙ | |||
877 878 879 880 881 882 883 | "Recno", "FullKey", "Rewind", "Next", "Destroy", "CreateIndex", "CreateTable", "Reorganize", "BeginIdx", "NextIdx", "PutIdx", "DeleteIdx", "MemLoad", "MemStore", "ListOpen", "ListWrite", "ListRewind", "ListRead", "ListClose", "SortOpen", "SortPut", "SortMakeRec", "SortMakeKey", "Sort", "SortNext", "SortKey", "SortCallback", "SortClose", | | | | | | | | | | | | | 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 | "Recno", "FullKey", "Rewind", "Next", "Destroy", "CreateIndex", "CreateTable", "Reorganize", "BeginIdx", "NextIdx", "PutIdx", "DeleteIdx", "MemLoad", "MemStore", "ListOpen", "ListWrite", "ListRewind", "ListRead", "ListClose", "SortOpen", "SortPut", "SortMakeRec", "SortMakeKey", "Sort", "SortNext", "SortKey", "SortCallback", "SortClose", "FileOpen", "FileRead", "FileColumn", "FileClose", "AggReset", "AggFocus", "AggIncr", "AggNext", "AggSet", "AggGet", "SetInsert", "SetFound", "SetNotFound", "SetClear", "MakeRecord", "MakeKey", "MakeIdxKey", "Goto", "If", "Halt", "ColumnCount", "ColumnName", "Callback", "Integer", "String", "Null", "Pop", "Dup", "Pull", "Add", "AddImm", "Subtract", "Multiply", "Divide", "Min", "Max", "Like", "Glob", "Eq", "Ne", "Lt", "Le", "Gt", "Ge", "IsNull", "NotNull", "Negative", "And", "Or", "Not", "Concat", "Noop", "Strlen", "Substr", }; /* ** Given the name of an opcode, return its number. Return 0 if ** there is no match. ** ** This routine is used for testing and debugging. |
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 | char **pzErrMsg, /* Error msg written here */ void *pBusyArg, /* 1st argument to the busy callback */ int (*xBusy)(void*,const char*,int) /* Called when a file is busy */ ){ int pc; /* The program counter */ Op *pOp; /* Current operation */ int rc; /* Value to return */ | | < | 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 | char **pzErrMsg, /* Error msg written here */ void *pBusyArg, /* 1st argument to the busy callback */ int (*xBusy)(void*,const char*,int) /* Called when a file is busy */ ){ int pc; /* The program counter */ Op *pOp; /* Current operation */ int rc; /* Value to return */ Btree *pBt = p->pBt; /* The backend driver */ sqlite *db = p->db; /* The database */ char **zStack; /* Text stack */ Stack *aStack; /* Additional stack information */ char zBuf[100]; /* Space to sprintf() an integer */ /* No instruction ever pushes more than a single element onto the ** stack. And the stack never grows on successive executions of the |
︙ | ︙ | |||
1916 1917 1918 1919 1920 1921 1922 | memcpy(&zNewKey[j], zStack[i], aStack[i].n-1); j += aStack[i].n-1; } if( i<p->tos ) zNewKey[j++] = '\t'; } zNewKey[j++] = 0; Integerify(p, p->tos-nField); | | | | | | 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 | memcpy(&zNewKey[j], zStack[i], aStack[i].n-1); j += aStack[i].n-1; } if( i<p->tos ) zNewKey[j++] = '\t'; } zNewKey[j++] = 0; Integerify(p, p->tos-nField); memcpy(&zNewKey[j], &aStack[p->tos-nField].i, sizeof(int)); PopStack(p, nField+1); VERIFY( NeedStack(p, p->tos+1); ) p->tos++; aStack[p->tos].n = nByte; aStack[p->tos].flags = STK_Str|STK_Dyn; zStack[p->tos] = zNewKey; break; } /* Opcode: Transaction * * * ** ** Begin a transaction. The transaction ends when a Commit or Rollback ** opcode is encountered or whenever there is an execution error that causes ** a script to abort. ** ** A transaction must be started before any changes can be made to the ** database. */ case OP_Transaction: { rc = sqliteBtreeBeginTrans(pBt); break; } /* Opcode: Commit * * * ** ** Cause all modifications to the database that have been made since the ** last Transaction to actually take effect. No additional modifications ** are allowed until another transaction is started. */ case OP_Commit: { rc = sqliteBtreeCommit(pBt); if( rc==SQLITE_OK ){ sqliteCommitInternalChanges(db); }else{ sqliteRollbackInternalChanges(db); } break; } /* Opcode: Rollback * * * ** ** Cause all modifications to the database that have been made since the ** last Transaction to be undone. The database is restored to its state ** before the Transaction opcode was executed. No additional modifications ** are allowed until another transaction is started. */ case OP_Rollback: { rc = sqliteBtreeRollback(pBt); sqliteRollbackInternalChanges(db); break; } /* Opcode: Open P1 P2 P3 ** ** Open a new cursor for the database table whose root page is |
︙ | ︙ | |||
1995 1996 1997 1998 1999 2000 2001 | if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; } for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0; p->nCursor = i+1; }else if( p->aCsr[i].pCursor ){ sqliteBtreeCloseCursor(p->aCsr[i].pCursor); } memset(&p->aCsr[i], 0, sizeof(Cursor)); | | | | 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 | if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; } for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0; p->nCursor = i+1; }else if( p->aCsr[i].pCursor ){ sqliteBtreeCloseCursor(p->aCsr[i].pCursor); } memset(&p->aCsr[i], 0, sizeof(Cursor)); do{ rc = sqliteBtreeCursor(pBt, pOp->p2, &p->aCsr[i].pCursor); switch( rc ){ case SQLITE_BUSY: { if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){ sqliteSetString(pzErrMsg, sqliteErrStr(rc), 0); busy = 0; } break; |
︙ | ︙ | |||
2025 2026 2027 2028 2029 2030 2031 | ** ** Open a new cursor that points to a table in a temporary database ** file. The temporary file is opened read/write event if the main ** database is read-only. The temporary file is deleted when the ** cursor is closed. */ case OP_OpenTemp: { | < | | 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 | ** ** Open a new cursor that points to a table in a temporary database ** file. The temporary file is opened read/write event if the main ** database is read-only. The temporary file is deleted when the ** cursor is closed. */ case OP_OpenTemp: { int i = pOp->p1; Cursor *pCx; VERIFY( if( i<0 ) goto bad_instruction; ) if( i>=p->nCursor ){ int j; p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) ); if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; } for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0; p->nCursor = i+1; }else if( p->aCsr[i].pCursor ){ sqliteBtreeCloseCursor(p->aCsr[i].pCursor); } pCx = &p->aCsr[i]; memset(pCx, 0, sizeof(*pCx)); rc = sqliteBtreeOpen(0, 0, 100, &pCx->pBt); if( rc==SQLITE_OK ){ rc = sqliteBtreeCursor(pCx->pBt, 2, &pCx->pCursor); } if( rc==SQLITE_OK ){ rc = sqliteBtreeBeginTrans(pCx->pBt); } break; } |
︙ | ︙ | |||
2087 2088 2089 2090 2091 2092 2093 | case OP_MoveTo: { int i = pOp->p1; int tos = p->tos; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){ int res; if( aStack[tos].flags & STK_Int ){ | | | | < | 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 | case OP_MoveTo: { int i = pOp->p1; int tos = p->tos; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){ int res; if( aStack[tos].flags & STK_Int ){ sqliteBtreeMoveto(p->aCsr[i].pCursor, (char*)&aStack[tos].i, sizeof(int), &res); p->aCsr[i].lastRecno = aStack[tos].i; p->aCsr[i].recnoIsValid = 1; }else{ if( Stringify(p, tos) ) goto no_mem; sqliteBtreeMoveto(p->aCsr[i].pCursor, zStack[tos], aStack[tos].n, &res); p->aCsr[i].recnoIsValid = 0; } p->nFetch++; } POPSTACK; break; } |
︙ | ︙ | |||
2157 2158 2159 2160 2161 2162 2163 | int i = pOp->p1; int tos = p->tos; int alreadyExists = 0; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor ){ int res, rx; if( aStack[tos].flags & STK_Int ){ | | | | | | 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 | int i = pOp->p1; int tos = p->tos; int alreadyExists = 0; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor ){ int res, rx; if( aStack[tos].flags & STK_Int ){ rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, (char*)&aStack[tos].i, sizeof(int), &res); }else{ if( Stringify(p, tos) ) goto no_mem; rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, zStack[tos], aStack[tos].n, &res); } alreadyExists = rx==SQLITE_OK && res==0; } if( pOp->opcode==OP_Found ){ if( alreadyExists ) pc = pOp->p2 - 1; }else{ if( !alreadyExists ) pc = pOp->p2 - 1; |
︙ | ︙ | |||
2194 2195 2196 2197 2198 2199 2200 | if( VERIFY( i<0 || i>=p->nCursor || ) p->aCsr[i].pCursor==0 ){ v = 0; }else{ int res, rx, cnt; cnt = 0; do{ v = sqliteRandomInteger(); | | | 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 | if( VERIFY( i<0 || i>=p->nCursor || ) p->aCsr[i].pCursor==0 ){ v = 0; }else{ int res, rx, cnt; cnt = 0; do{ v = sqliteRandomInteger(); rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, &v, sizeof(v), &res); cnt++; }while( cnt<10 && rx==SQLITE_OK && res==0 ); } VERIFY( NeedStack(p, p->tos+1); ) p->tos++; aStack[p->tos].i = v; aStack[p->tos].flags = STK_Int; |
︙ | ︙ | |||
2229 2230 2231 2232 2233 2234 2235 | if( Stringify(p, nos) ) goto no_mem; nKey = aStack[nos].n; zKey = zStack[nos]; }else{ nKey = sizeof(int); zKey = (char*)&aStack[nos].i; } | | | < > > | < | 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 | if( Stringify(p, nos) ) goto no_mem; nKey = aStack[nos].n; zKey = zStack[nos]; }else{ nKey = sizeof(int); zKey = (char*)&aStack[nos].i; } rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey, zStack[tos], aStack[tos].n); } POPSTACK; POPSTACK; break; } /* Opcode: Delete P1 * * ** ** The top of the stack is a key. Remove this key and its data ** from database file P1. Then pop the stack to discard the key. */ case OP_Delete: { int tos = p->tos; int i = pOp->p1; int res; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){ char *zKey; int nKey; if( aStack[tos].flags & STK_Int ){ nKey = sizeof(int); zKey = (char*)&aStack[tos].i; }else{ if( Stringify(p, tos) ) goto no_mem; nKey = aStack[tos].n; zKey = zStack[tos]; } rc = sqliteBtreeMoveto(p->aCsr[i].pCursor, zKey, nKey, &res); rc = sqliteBtreeDelete(p->aCsr[i].pCursor); } POPSTACK; break; } /* Opcode: KeyAsData P1 P2 * ** |
︙ | ︙ | |||
2297 2298 2299 2300 2301 2302 2303 | ** "Concat 1 0 0") if it needs to persist longer than that. ** ** If the KeyAsData opcode has previously executed on this cursor, ** then the field might be extracted from the key rather than the ** data. */ case OP_Column: { | < | | 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 | ** "Concat 1 0 0") if it needs to persist longer than that. ** ** If the KeyAsData opcode has previously executed on this cursor, ** then the field might be extracted from the key rather than the ** data. */ case OP_Column: { int amt, offset, nCol, payloadSize; int aHdr[10]; const int mxHdr = sizeof(aHdr)/sizeof(aHdr[0]); int i = pOp->p1; int p2 = pOp->p2; int tos = ++p->tos; BtCursor *pCrsr; char *z; VERIFY( if( NeedStack(p, tos) ) goto no_mem; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int (*xSize)(BtCursor*, int*); int (*xRead)(BtCursor*, int, int, char*); /* Use different access functions depending on whether the information ** is coming from the key or the data of the record. */ if( p->aCsr[i].keyAsData ){ xSize = sqliteBtreeKeySize; xRead = sqliteBtreeKey; |
︙ | ︙ | |||
2336 2337 2338 2339 2340 2341 2342 | */ (*xSize)(pCrsr, &payloadSize); if( payloadSize < sizeof(int)*(p2+1) ){ rc = SQLITE_CORRUPT; goto abort_due_to_error; } if( p2+1<mxHdr ){ | | | | | | 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 | */ (*xSize)(pCrsr, &payloadSize); if( payloadSize < sizeof(int)*(p2+1) ){ rc = SQLITE_CORRUPT; goto abort_due_to_error; } if( p2+1<mxHdr ){ (*xRead)(pCrsr, 0, sizeof(aHdr[0])*(p2+2), (char*)aHdr); nCol = aHdr[0]; offset = aHdr[p2]; if( p2 == nCol-1 ){ amt = payloadSize - offset; }else{ amt = aHdr[p2+1] - offset; } }else{ sqliteBtreeData(pCrsr, 0, sizeof(int), (char*)&nCol); nCol /= sizeof(int); if( p2 == nCol-1 ){ (*xRead)(pCrsr, sizeof(int)*p2, sizeof(int), (char*)&offset); amt = payloadSize - offset; }else{ (*xRead)(pCrsr, sizeof(int)*p2, sizeof(int)*2, (char*)aHdr); offset = aHdr[0]; amt = aHdr[1] - offset; } } if( payloadSize < nCol || amt<0 || offset<0 ){ rc = SQLITE_CORRUPT; goto abort_due_to_error; |
︙ | ︙ | |||
2392 2393 2394 2395 2396 2397 2398 | VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int v; if( p->aCsr[i].recnoIsValid ){ v = p->aCsr[i].lastRecno; }else{ | | | 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 | VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int v; if( p->aCsr[i].recnoIsValid ){ v = p->aCsr[i].lastRecno; }else{ sqliteBtreeKey(pCrsr, 0, sizeof(int), (char*)&v); } aStack[tos].i = v; aStack[tos].flags = STK_Int; } break; } |
︙ | ︙ | |||
2502 2503 2504 2505 2506 2507 2508 | if( Stringify(p, tos) ) goto no_mem; pCrsr->nKey = aStack[tos].n; pCrsr->zKey = sqliteMalloc( 2*(pCrsr->nKey + 1) ); if( pCrsr->zKey==0 ) goto no_mem; pCrsr->zBuf = &pCrsr->zKey[pCrsr->nKey+1]; strncpy(pCrsr->zKey, zStack[tos], aStack[tos].n); pCrsr->zKey[aStack[tos].n] = 0; | | | | | | | | | | 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 | if( Stringify(p, tos) ) goto no_mem; pCrsr->nKey = aStack[tos].n; pCrsr->zKey = sqliteMalloc( 2*(pCrsr->nKey + 1) ); if( pCrsr->zKey==0 ) goto no_mem; pCrsr->zBuf = &pCrsr->zKey[pCrsr->nKey+1]; strncpy(pCrsr->zKey, zStack[tos], aStack[tos].n); pCrsr->zKey[aStack[tos].n] = 0; rx = sqliteBtreeMoveto(pCrsr->pCursor, zStack[tos], aStack[tos].n, &res); pCrsr->atFirst = rx==SQLITE_OK && res>0; pCrsr->recnoIsValid = 0; } POPSTACK; break; } /* Opcode: NextIdx P1 P2 * ** ** The P1 cursor points to an SQL index for which a BeginIdx operation ** has been issued. This operation retrieves the next record number and ** pushes that record number onto the stack. Or, if there are no more ** record numbers for the given key, this opcode pushes nothing onto the ** stack but instead jumps to instruction P2. */ case OP_NextIdx: { int i = pOp->p1; int tos = ++p->tos; Cursor *pCrsr; BtCursor *pCur; int rx, res, size; VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) zStack[tos] = 0; if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = &p->aCsr[i])->pCursor!=0 ){ pCur = pCrsr->pCursor; rx = sqliteBtreeNext(pCur, &res); if( rx!=SQLITE_OK ) goto abort_due_to_error; sqliteBtreeKeySize(pCur, &size); if( res>0 || size!=pCrsr->nKey+sizeof(int) || sqliteBtreeKey(pCur, 0, pCrsr->nKey, pCrsr->zBuf)!=pCrsr->nKey || strncmp(pCrsr->zKey, pCrsr->zBuf, pCrsr->nKey)!=0 ){ pc = pOp->p2 - 1; POPSTACK; }else{ int recno; sqliteBtreeKey(pCur, pCrsr->nKey, sizeof(int), (char*)&recno); p->aCsr[i].lastRecno = aStack[tos].i = recno; p->aCsr[i].recnoIsValid = 1; aStack[tos].flags = STK_Int; } } break; } /* Opcode: PutIdx P1 * * ** ** The top of the stack hold an SQL index key made using the ** MakeIdxKey instruction. This opcode writes that key into the ** index P1. Data for the entry is nil. */ case OP_PutIdx: { int i = pOp->p1; int tos = p->tos; BtCursor *pCrsr; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ sqliteBtreeInsert(pCrsr, zStack[tos], aStack[tos].n, "", 0); } POPSTACK; break; } /* Opcode: DeleteIdx P1 * * ** ** The top of the stack is an index key built using the MakeIdxKey opcode. ** This opcode removes that entry from the index. */ case OP_DeleteIdx: { int i = pOp->p1; int tos = p->tos; BtCursor *pCrsr; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int rx, res; rx = sqliteBtreeMoveto(pCrsr, zStack[tos], aStack[tos].n, &res); if( rx==SQLITE_OK && res==0 ){ sqliteBtreeDelete(pCrsr); } } POPSTACK; break; } /* Opcode: Destroy P1 * * ** ** Delete an entire database table or index whose root page in the database ** file is given by P1. */ case OP_Destroy: { sqliteBtreeDropTable(pBt, pOp->p1); break; } /* Opcode: Reorganize P1 * * ** ** Compress, optimize, and tidy up table or index whose root page in the ** database file is P1. |
︙ | ︙ | |||
3111 3112 3113 3114 3115 3116 3117 | /* If we reach end-of-file, or if anything goes wrong, jump here. ** This code will cause a jump to P2 */ fileread_jump: pc = pOp->p2 - 1; break; } | | | | 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 | /* If we reach end-of-file, or if anything goes wrong, jump here. ** This code will cause a jump to P2 */ fileread_jump: pc = pOp->p2 - 1; break; } /* Opcode: FileColumn P1 * * ** ** Push onto the stack the P1-th field of the most recently read line ** from the input file. */ case OP_FileColumn: { int i = pOp->p1; char *z; VERIFY( if( NeedStack(p, p->tos+1) ) goto no_mem; ) if( VERIFY( i>=0 && i<p->nField && ) p->azField ){ z = p->azField[i]; }else{ z = 0; |
︙ | ︙ | |||
3624 3625 3626 3627 3628 3629 3630 | } #endif } cleanup: Cleanup(p); if( rc!=SQLITE_OK && (db->flags & SQLITE_InTrans)!=0 ){ | | | | 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 | } #endif } cleanup: Cleanup(p); if( rc!=SQLITE_OK && (db->flags & SQLITE_InTrans)!=0 ){ sqliteBtreeRollback(pBt); sqliteRollbackInternalChanges(db); db->flags &= ~SQLITE_InTrans; } return rc; /* Jump to here if a malloc() fails. It's hard to get a malloc() ** to fail on a modern VM computer, so this code is untested. */ no_mem: sqliteSetString(pzErrMsg, "out or memory", 0); rc = SQLITE_NOMEM; goto cleanup; /* Jump to here for any other kind of fatal error. The "rc" variable ** should hold the error number. */ abort_due_to_error: sqliteSetString(pzErrMsg, sqliteErrStr(rc), 0); goto cleanup; /* Jump to here if a operator is encountered that requires more stack ** operands than are currently available on the stack. */ not_enough_stack: |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
23 24 25 26 27 28 29 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** ** $Id: vdbe.h,v 1.20 2001/09/13 14:46:11 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include <stdio.h> /* ** A single VDBE is an opaque structure named "Vdbe". Only routines |
︙ | ︙ | |||
120 121 122 123 124 125 126 | #define OP_SortNext 41 #define OP_SortKey 42 #define OP_SortCallback 43 #define OP_SortClose 44 #define OP_FileOpen 45 #define OP_FileRead 46 | | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | #define OP_SortNext 41 #define OP_SortKey 42 #define OP_SortCallback 43 #define OP_SortClose 44 #define OP_FileOpen 45 #define OP_FileRead 46 #define OP_FileColumn 47 #define OP_FileClose 48 #define OP_AggReset 49 #define OP_AggFocus 50 #define OP_AggIncr 51 #define OP_AggNext 52 #define OP_AggSet 53 |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. Also found here are subroutines ** to generate VDBE code to evaluate expressions. ** | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. Also found here are subroutines ** to generate VDBE code to evaluate expressions. ** ** $Id: where.c,v 1.17 2001/09/13 14:46:11 drh Exp $ */ #include "sqliteInt.h" /* ** The query generator uses an array of instances of this structure to ** help it analyze the subexpressions of the WHERE clause. Each WHERE ** clause subexpression is separated from the others by an AND operator. |
︙ | ︙ | |||
296 297 298 299 300 301 302 | /* Open all tables in the pTabList and all indices in aIdx[]. */ for(i=0; i<pTabList->nId; i++){ sqliteVdbeAddOp(v, OP_Open, base+i, pTabList->a[i].pTab->tnum, pTabList->a[i].pTab->zName, 0); if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){ | | | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | /* Open all tables in the pTabList and all indices in aIdx[]. */ for(i=0; i<pTabList->nId; i++){ sqliteVdbeAddOp(v, OP_Open, base+i, pTabList->a[i].pTab->tnum, pTabList->a[i].pTab->zName, 0); if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){ sqliteVdbeAddOp(v, OP_Open, base+pTabList->nId+i, aIdx[i]->tnum, aIdx[i]->zName, 0); } } memcpy(pWInfo->aIdx, aIdx, sizeof(aIdx)); /* Generate the code to do the search */ |
︙ | ︙ | |||
347 348 349 350 351 352 353 | break; } } sqliteVdbeAddOp(v, OP_AddImm, 0, 0, 0, 0); if( i==pTabList->nId-1 && pushKey ){ haveKey = 1; }else{ | | | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | break; } } sqliteVdbeAddOp(v, OP_AddImm, 0, 0, 0, 0); if( i==pTabList->nId-1 && pushKey ){ haveKey = 1; }else{ sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0, 0, 0); haveKey = 0; } }else if( pIdx==0 ){ /* Case 2: There was no usable index. We must do a complete ** scan of the table. */ cont = sqliteVdbeMakeLabel(v); |
︙ | ︙ | |||
388 389 390 391 392 393 394 | } sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_BeginIdx, base+pTabList->nId+i, 0, 0, 0); sqliteVdbeAddOp(v, OP_NextIdx, base+pTabList->nId+i, brk, 0, cont); if( i==pTabList->nId-1 && pushKey ){ haveKey = 1; }else{ | | | | | 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 424 425 426 | } sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_BeginIdx, base+pTabList->nId+i, 0, 0, 0); sqliteVdbeAddOp(v, OP_NextIdx, base+pTabList->nId+i, brk, 0, cont); if( i==pTabList->nId-1 && pushKey ){ haveKey = 1; }else{ sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0, 0, 0); haveKey = 0; } } loopMask |= 1<<idx; /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. */ for(j=0; j<nExpr; j++){ if( aExpr[j].p==0 ) continue; if( (aExpr[j].prereqRight & loopMask)!=aExpr[j].prereqRight ) continue; if( (aExpr[j].prereqLeft & loopMask)!=aExpr[j].prereqLeft ) continue; if( haveKey ){ haveKey = 0; sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0, 0, 0); } sqliteExprIfFalse(pParse, aExpr[j].p, cont); aExpr[j].p = 0; } brk = cont; } pWInfo->iContinue = cont; if( pushKey && !haveKey ){ sqliteVdbeAddOp(v, OP_Recno, base, 0, 0, 0); } sqliteFree(aOrder); return pWInfo; } /* ** Generate the end of the WHERE loop. |
︙ | ︙ |
Changes to test/btree2.test.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # # $Id: btree2.test,v 1.5 2001/09/13 14:46:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl if {[info commands btree_open]!=""} { |
︙ | ︙ | |||
284 285 286 287 288 289 290 291 | # Repeat this test sequence on database of various sizes # set testno 2 foreach {N L} { 10 2 50 2 200 3 } { | > < | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | # Repeat this test sequence on database of various sizes # set testno 2 foreach {N L} { 10 2 50 2 200 3 2000 5 } { puts "**** N=$N L=$L ****" set hash [md5file test2.bt] do_test btree2-$testno.1 [subst -nocommands { set ::c2 [btree_cursor $::b 2] set ::c3 [btree_cursor $::b 3] set ::c4 [btree_cursor $::b 4] set ::c5 [btree_cursor $::b 5] |
︙ | ︙ |