Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Many problems fixed. Many problems yet to go. (CVS 242) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
62c7bd11bcf6438cdcbf66fa67a2bf4a |
User & Date: | drh 2001-09-13 21:53:09.000 |
Context
2001-09-13
| ||
21:53 | Many problems fixed. Many problems yet to go. (CVS 1722) (check-in: 3dfe1711e6 user: drh tags: trunk) | |
21:53 | Many problems fixed. Many problems yet to go. (CVS 242) (check-in: 62c7bd11bc user: drh tags: trunk) | |
16:18 | It runs. Simple tables can be created. INSERT and SELECT work. Much more testing is needed, however. (CVS 241) (check-in: 9ac8399c99 user: drh tags: trunk) | |
Changes
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.24 2001/09/13 21:53:09 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. |
︙ | ︙ | |||
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 | int nNew; /* Number of pages in apNew[] */ int nDiv; /* Number of cells in apDiv[] */ int i, j, k; /* Loop counters */ int idx; /* Index of pPage in pParent->apCell[] */ int nxDiv; /* Next divider slot in pParent->apCell[] */ int rc; /* The return code */ int iCur; /* apCell[iCur] is the cell of the cursor */ int totalSize; /* Total bytes for all cells */ int subtotal; /* Subtotal of bytes in cells on one page */ int cntNew[4]; /* Index in apCell[] of cell after i-th page */ int szNew[4]; /* Combined size of cells place on i-th page */ MemPage *extraUnref = 0; /* A page that needs to be unref-ed */ Pgno pgno; /* Page number */ Cell *apCell[MX_CELL*3+5]; /* All cells from pages being balanceed */ | > | 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 | int nNew; /* Number of pages in apNew[] */ int nDiv; /* Number of cells in apDiv[] */ int i, j, k; /* Loop counters */ int idx; /* Index of pPage in pParent->apCell[] */ int nxDiv; /* Next divider slot in pParent->apCell[] */ int rc; /* The return code */ int iCur; /* apCell[iCur] is the cell of the cursor */ MemPage *pOldCurPage; /* The cursor originally points to this page */ int totalSize; /* Total bytes for all cells */ int subtotal; /* Subtotal of bytes in cells on one page */ int cntNew[4]; /* Index in apCell[] of cell after i-th page */ int szNew[4]; /* Combined size of cells place on i-th page */ MemPage *extraUnref = 0; /* A page that needs to be unref-ed */ Pgno pgno; /* Page number */ Cell *apCell[MX_CELL*3+5]; /* All cells from pages being balanceed */ |
︙ | ︙ | |||
1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 | rc = sqlitepager_get(pBt->pPager, pgnoChild, (void**)&pChild); if( rc ) return rc; memcpy(pPage, pChild, SQLITE_PAGE_SIZE); pPage->isInit = 0; rc = initPage(pPage, sqlitepager_pagenumber(pPage), 0); assert( rc==SQLITE_OK ); reparentChildPages(pBt->pPager, pPage); freePage(pBt, pChild, pgnoChild); sqlitepager_unref(pChild); }else{ relinkCellList(pPage); } return SQLITE_OK; } | > > > > > | 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 | rc = sqlitepager_get(pBt->pPager, pgnoChild, (void**)&pChild); if( rc ) return rc; memcpy(pPage, pChild, SQLITE_PAGE_SIZE); pPage->isInit = 0; rc = initPage(pPage, sqlitepager_pagenumber(pPage), 0); assert( rc==SQLITE_OK ); reparentChildPages(pBt->pPager, pPage); if( pCur && pCur->pPage==pChild ){ sqlitepager_unref(pChild); pCur->pPage = pPage; sqlitepager_ref(pPage); } freePage(pBt, pChild, pgnoChild); sqlitepager_unref(pChild); }else{ relinkCellList(pPage); } return SQLITE_OK; } |
︙ | ︙ | |||
1756 1757 1758 1759 1760 1761 1762 | rc = allocatePage(pBt, &pChild, &pgnoChild); if( rc ) return rc; assert( sqlitepager_iswriteable(pChild) ); copyPage(pChild, pPage); pChild->pParent = pPage; sqlitepager_ref(pPage); pChild->isOverfull = 1; | | | | 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 | rc = allocatePage(pBt, &pChild, &pgnoChild); if( rc ) return rc; assert( sqlitepager_iswriteable(pChild) ); copyPage(pChild, pPage); pChild->pParent = pPage; sqlitepager_ref(pPage); pChild->isOverfull = 1; if( pCur && pCur->pPage==pPage ){ sqlitepager_unref(pPage); pCur->pPage = pChild; }else{ extraUnref = pChild; } zeroPage(pPage); pPage->u.hdr.rightChild = pgnoChild; pParent = pPage; |
︙ | ︙ | |||
1792 1793 1794 1795 1796 1797 1798 | } if( idx<0 ){ return SQLITE_CORRUPT; } /* ** Initialize variables so that it will be safe to jump | | | 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 | } if( idx<0 ){ return SQLITE_CORRUPT; } /* ** Initialize variables so that it will be safe to jump ** directly to balance_cleanup at any moment. */ nOld = nNew = 0; sqlitepager_ref(pParent); /* ** Find sibling pages to pPage and the Cells in pParent that divide ** the siblings. An attempt is made to find one sibling on either |
︙ | ︙ | |||
1832 1833 1834 1835 1836 1837 1838 | if( rc ) goto balance_cleanup; nOld++; } /* ** Set iCur to be the index in apCell[] of the cell that the cursor ** is pointing to. We will need this later on in order to keep the | | > > > | | > > > > | > > | | > | | 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 | if( rc ) goto balance_cleanup; nOld++; } /* ** Set iCur to be the index in apCell[] of the cell that the cursor ** is pointing to. We will need this later on in order to keep the ** cursor pointing at the same cell. If pCur points to a page that ** has no involvement with this rebalancing, then set iCur to a large ** number so that the iCur==j tests always fail in the main cell ** distribution loop below. */ if( pCur ){ iCur = 0; for(i=0; i<nOld; i++){ if( pCur->pPage==apOld[i] ){ iCur += pCur->idx; break; } iCur += apOld[i]->nCell; if( i<nOld-1 && pCur->pPage==pParent && pCur->idx==idxDiv[i] ){ break; } iCur++; } pOldCurPage = pCur->pPage; } /* ** Make copies of the content of pPage and its siblings into aOld[]. ** The rest of this function will use data from the copies rather ** that the original pages since the original pages will be in the ** process of being overwritten. |
︙ | ︙ | |||
1961 1962 1963 1964 1965 1966 1967 | apNew[nNew-1]->u.hdr.rightChild = apOld[nOld-1]->u.hdr.rightChild; if( nxDiv==pParent->nCell ){ pParent->u.hdr.rightChild = pgnoNew[nNew-1]; }else{ pParent->apCell[nxDiv]->h.leftChild = pgnoNew[nNew-1]; } if( pCur ){ | | > | | 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 | apNew[nNew-1]->u.hdr.rightChild = apOld[nOld-1]->u.hdr.rightChild; if( nxDiv==pParent->nCell ){ pParent->u.hdr.rightChild = pgnoNew[nNew-1]; }else{ pParent->apCell[nxDiv]->h.leftChild = pgnoNew[nNew-1]; } if( pCur ){ assert( pOldCurPage!=0 ); sqlitepager_ref(pCur->pPage); sqlitepager_unref(pOldCurPage); } /* ** Reparent children of all cells. */ for(i=0; i<nNew; i++){ reparentChildPages(pBt->pPager, apNew[i]); } reparentChildPages(pBt->pPager, pParent); /* ** balance the parent page. */ rc = balance(pBt, pParent, pCur); /* ** Cleanup before returning. */ balance_cleanup: if( extraUnref ){ sqlitepager_unref(extraUnref); |
︙ | ︙ | |||
2018 2019 2020 2021 2022 2023 2024 | Cell newCell; int rc; int loc; int szNew; MemPage *pPage; Btree *pBt = pCur->pBt; | | | 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 | Cell newCell; int rc; int loc; int szNew; MemPage *pPage; Btree *pBt = pCur->pBt; if( !pCur->pBt->inTrans || nKey+nData==0 ){ return SQLITE_ERROR; /* Must start a transaction first */ } rc = sqliteBtreeMoveto(pCur, pKey, nKey, &loc); if( rc ) return rc; pPage = pCur->pPage; rc = sqlitepager_write(pPage); if( rc ) return rc; |
︙ | ︙ | |||
2103 2104 2105 2106 2107 2108 2109 | if( rc ) return rc; pCur->bSkipNext = 1; dropCell(leafCur.pPage, leafCur.idx, szNext); rc = balance(pCur->pBt, leafCur.pPage, 0); releaseTempCursor(&leafCur); }else{ dropCell(pPage, pCur->idx, cellSize(pCell)); | | | > > | 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 | if( rc ) return rc; pCur->bSkipNext = 1; dropCell(leafCur.pPage, leafCur.idx, szNext); rc = balance(pCur->pBt, leafCur.pPage, 0); releaseTempCursor(&leafCur); }else{ dropCell(pPage, pCur->idx, cellSize(pCell)); if( pCur->idx>=pPage->nCell ){ pCur->idx = pPage->nCell-1; if( pCur->idx<0 ){ pCur->idx = 0; } pCur->bSkipNext = 0; }else{ pCur->bSkipNext = 1; } rc = balance(pCur->pBt, pPage, pCur); } return rc; } |
︙ | ︙ | |||
2248 2249 2250 2251 2252 2253 2254 | /****************************************************************************** ** The complete implementation of the BTree subsystem is above this line. ** All the code the follows is for testing and troubleshooting the BTree ** subsystem. None of the code that follows is used during normal operation. ** All of the following code is omitted unless the library is compiled with ** the -DSQLITE_TEST=1 compiler option. ******************************************************************************/ | | | 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 | /****************************************************************************** ** The complete implementation of the BTree subsystem is above this line. ** All the code the follows is for testing and troubleshooting the BTree ** subsystem. None of the code that follows is used during normal operation. ** All of the following code is omitted unless the library is compiled with ** the -DSQLITE_TEST=1 compiler option. ******************************************************************************/ #if 1 /* ** Print a disassembly of the given page on standard output. This routine ** is used for debugging and testing only. */ int sqliteBtreePageDump(Btree *pBt, int pgno, int recursive){ int rc; |
︙ | ︙ |
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 | ** DROP TABLE ** CREATE INDEX ** DROP INDEX ** creating expressions and ID lists ** COPY ** VACUUM ** ** $Id: build.c,v 1.32 2001/09/13 21:53: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 |
︙ | ︙ | |||
235 236 237 238 239 240 241 242 243 244 245 246 247 248 | pNext = pIndex->pNext; sqliteDeleteIndex(db, pIndex); } sqliteFree(pTable->zName); sqliteFree(pTable->aCol); sqliteFree(pTable); } /* ** Check all Tables and Indexes in the internal hash table and commit ** any additions or deletions to those hash tables. ** ** When executing CREATE TABLE and CREATE INDEX statements, the Table ** and Index structures are created and added to the hash tables, but | > > > > > > > > > > > > > > > > > > > > | 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 | pNext = pIndex->pNext; sqliteDeleteIndex(db, pIndex); } sqliteFree(pTable->zName); sqliteFree(pTable->aCol); sqliteFree(pTable); } /* ** Unlink the given table from the hash tables and the delete the ** table structure and all its indices. */ static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *pTable){ if( pTable->zName && db ){ int h = sqliteHashNoCase(pTable->zName, 0) % N_HASH; if( db->apTblHash[h]==pTable ){ db->apTblHash[h] = pTable->pHash; }else{ Table *p; for(p=db->apTblHash[h]; p && p->pHash!=pTable; p=p->pHash){} if( p && p->pHash==pTable ){ p->pHash = pTable->pHash; } } } sqliteDeleteTable(db, pTable); } /* ** Check all Tables and Indexes in the internal hash table and commit ** any additions or deletions to those hash tables. ** ** When executing CREATE TABLE and CREATE INDEX statements, the Table ** and Index structures are created and added to the hash tables, but |
︙ | ︙ | |||
258 259 260 261 262 263 264 | 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 ){ | | | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | 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 ){ sqliteUnlinkAndDeleteTable(db, pTable); }else if( pTable->isCommit==0 ){ pTable->isCommit = 1; } } } for(i=0; i<N_HASH; i++){ Index *pIndex, *pNext; |
︙ | ︙ | |||
294 295 296 297 298 299 300 | 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 ){ | | | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | 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 ){ sqliteUnlinkAndDeleteTable(db, pTable); }else if( pTable->isDelete ){ pTable->isDelete = 0; } } } for(i=0; i<N_HASH; i++){ Index *pIndex, *pNext; |
︙ | ︙ | |||
469 470 471 472 473 474 475 | p->tnum = pParse->newTnum; } /* If not initializing, then create the table on disk. */ if( !pParse->initFlag ){ static VdbeOp addTable[] = { | | | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 | p->tnum = pParse->newTnum; } /* If not initializing, then create the table on disk. */ if( !pParse->initFlag ){ static VdbeOp addTable[] = { { OP_Open, 0, 2, MASTER_NAME}, { OP_NewRecno, 0, 0, 0}, { OP_String, 0, 0, "table" }, { OP_String, 0, 0, 0}, /* 3 */ { OP_CreateTable, 0, 0, 0}, { OP_String, 0, 0, 0}, /* 5 */ { OP_String, 0, 0, 0}, /* 6 */ { OP_MakeRecord, 5, 0, 0}, |
︙ | ︙ | |||
491 492 493 494 495 496 497 498 499 500 501 502 503 504 | 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); } } } /* | > > > > > > > > > | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 | 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( p->pIndex ){ /* If the table has a primary key, create an index in the database ** for that key. */ Index *pIndex = p->pIndex; assert( pIndex->pNext==0 ); assert( pIndex->tnum==0 ); sqliteVdbeAddOp(v, OP_CreateIndex, 0, 0, 0, 0), sqliteVdbeIndexRootAddr(v, &pIndex->tnum); } if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } } } /* |
︙ | ︙ | |||
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | ** 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 ){ sqliteSetString(&pParse->zErrMsg, "table ", pTable->zName, " may not be dropped", 0); pParse->nErr++; return; } /* Generate code to remove the table from the master table ** on disk. */ v = sqliteGetVdbe(pParse); if( v ){ static VdbeOp dropTable[] = { | > | | < | | > | | | | 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 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | ** 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; sqlite *db = pParse->db; if( pParse->nErr || sqlite_malloc_failed ) return; pTable = sqliteTableFromToken(pParse, pName); if( pTable==0 ) return; if( pTable->readOnly ){ sqliteSetString(&pParse->zErrMsg, "table ", pTable->zName, " may not be dropped", 0); pParse->nErr++; return; } /* Generate code to remove the table from the master table ** on disk. */ v = sqliteGetVdbe(pParse); if( v ){ static VdbeOp dropTable[] = { { OP_Open, 0, 2, MASTER_NAME}, { OP_Rewind, 0, 0, 0}, { OP_String, 0, 0, 0}, /* 2 */ { OP_Next, 0, ADDR(9), 0}, /* 3 */ { OP_Dup, 0, 0, 0}, { OP_Column, 0, 3, 0}, { OP_Ne, 0, ADDR(3), 0}, { OP_Delete, 0, 0, 0}, { OP_Goto, 0, ADDR(3), 0}, { OP_Destroy, 0, 0, 0}, /* 9 */ { OP_Close, 0, 0, 0}, }; Index *pIdx; if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); sqliteVdbeChangeP3(v, base+2, pTable->zName, 0); sqliteVdbeChangeP1(v, base+9, pTable->tnum); for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, 0, 0, 0); } if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); } } /* Mark the in-memory Table structure as being deleted. The actually ** 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; 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 |
︙ | ︙ | |||
716 717 718 719 720 721 722 723 | ** index with the current table contents. ** ** The initFlag is 0 when the user first enters a CREATE INDEX ** command. The initFlag is 1 when a database is opened and ** CREATE INDEX statements are read out of the master table. In ** the latter case the index already exists on disk, which is why ** we don't want to recreate it. */ | > > > > > > > | | | > > | | < < > | | > | 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 | ** index with the current table contents. ** ** The initFlag is 0 when the user first enters a CREATE INDEX ** command. The initFlag is 1 when a database is opened and ** CREATE INDEX statements are read out of the master table. In ** the latter case the index already exists on disk, which is why ** we don't want to recreate it. ** ** If pTable==0 it means this index is generated as a primary key ** and those does not have a CREATE INDEX statement to add to the ** master table. Also, since primary keys are created at the same ** time as tables, the table will be empty so there is no need to ** initialize the index. Hence, skip all the code generation if ** pTable==0. */ else if( pParse->initFlag==0 && pTable!=0 ){ static VdbeOp addTable[] = { { OP_Open, 2, 2, MASTER_NAME}, { OP_NewRecno, 2, 0, 0}, { OP_String, 0, 0, "index"}, { OP_String, 0, 0, 0}, /* 3 */ { OP_CreateIndex, 1, 0, 0}, { OP_Dup, 0, 0, 0}, { OP_Open, 1, 0, 0}, /* 6 */ { OP_String, 0, 0, 0}, /* 7 */ { OP_String, 0, 0, 0}, /* 8 */ { OP_MakeRecord, 5, 0, 0}, { OP_Put, 2, 0, 0}, { OP_Close, 2, 0, 0}, }; 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); } 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+6, pIndex->zName, 0); sqliteVdbeChangeP3(v, base+7, pTab->zName, 0); sqliteVdbeChangeP3(v, base+8, pStart->z, n); } sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0); lbl1 = sqliteVdbeMakeLabel(v); lbl2 = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Rewind, 0, 0, 0, 0); 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); |
︙ | ︙ | |||
808 809 810 811 812 813 814 | return; } /* Generate code to remove the index and from the master table */ v = sqliteGetVdbe(pParse); if( v ){ static VdbeOp dropIndex[] = { | | | < | | | 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 | return; } /* Generate code to remove the index and from the master table */ v = sqliteGetVdbe(pParse); if( v ){ static VdbeOp dropIndex[] = { { OP_Open, 0, 2, MASTER_NAME}, { OP_Rewind, 0, 0, 0}, { OP_String, 0, 0, 0}, /* 2 */ { OP_Next, 0, ADDR(8), 0}, /* 3 */ { OP_Dup, 0, 0, 0}, { OP_Column, 0, 1, 0}, { OP_Ne, 0, ADDR(3), 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. |
︙ | ︙ |
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.12 2001/09/13 21:53:10 drh Exp $ */ #include "sqliteInt.h" /* ** Process a DELETE FROM statement. */ void sqliteDeleteFrom( |
︙ | ︙ | |||
92 93 94 95 96 97 98 | if( v==0 ) goto delete_from_cleanup; if( (pParse->db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } /* Special case: A DELETE without a WHERE clause deletes everything. | | | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | if( v==0 ) goto delete_from_cleanup; if( (pParse->db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); } /* Special case: A DELETE without a WHERE clause deletes everything. ** It is easier just to clear all information the database tables directly. */ if( pWhere==0 ){ sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, 0, 0, 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, 0, 0, 0); } } /* The usual case: There is a WHERE clause so we have to scan through ** the table an pick which records to delete. */ else{ |
︙ | ︙ | |||
131 132 133 134 135 136 137 | sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, 0, 0); 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); | < < | > | | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, 0, 0); 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); sqliteVdbeAddOp(v, OP_MoveTo, base, 0, 0, 0); if( pTab->pIndex ){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ int j; sqliteVdbeAddOp(v, OP_Recno, base, 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); } } |
︙ | ︙ |
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.34 2001/09/13 21:53:10 drh Exp $ */ #include "sqliteInt.h" #if defined(HAVE_USLEEP) && HAVE_USLEEP #include <unistd.h> #endif /* |
︙ | ︙ | |||
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | 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); if( sqlite_malloc_failed ){ goto no_mem_on_open; }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ sqlite_close(db); return 0; }else /* if( pzErrMsg ) */{ sqliteFree(*pzErrMsg); *pzErrMsg = 0; } return db; | > > | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | default: { if( pzErrMsg ){ sqliteSetString(pzErrMsg, "unable to open database: ", zFilename, 0); } } } sqliteFree(db); sqliteStrRealloc(pzErrMsg); return 0; } /* Assume file format 1 unless the database says otherwise */ db->file_format = 1; /* Attempt to read the schema */ rc = sqliteInit(db, pzErrMsg); if( sqlite_malloc_failed ){ goto no_mem_on_open; }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ sqlite_close(db); sqliteStrRealloc(pzErrMsg); return 0; }else /* if( pzErrMsg ) */{ sqliteFree(*pzErrMsg); *pzErrMsg = 0; } return db; |
︙ | ︙ |
Changes to src/random.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | ************************************************************************* ** This file contains code to implement a pseudo-random number ** generator (PRNG) for SQLite. ** ** Random numbers are used by some of the database backends in order ** to generate random integer keys for tables or random filenames. ** | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | ************************************************************************* ** This file contains code to implement a pseudo-random number ** generator (PRNG) for SQLite. ** ** Random numbers are used by some of the database backends in order ** to generate random integer keys for tables or random filenames. ** ** $Id: random.c,v 1.3 2001/09/13 21:53:10 drh Exp $ */ #include "sqliteInt.h" #include <time.h> /* ** Get a single 8-bit random value from the RC4 PRNG. */ |
︙ | ︙ | |||
83 84 85 86 87 88 89 | */ prng_state.i = (prng_state.i + 1) & 0xff; prng_state.j = (prng_state.j + prng_state.s[prng_state.i]) & 0xff; t = prng_state.s[prng_state.i]; prng_state.s[prng_state.i] = prng_state.s[prng_state.j]; prng_state.s[prng_state.j] = t; t = prng_state.s[prng_state.i] + prng_state.s[prng_state.j]; | | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | */ prng_state.i = (prng_state.i + 1) & 0xff; prng_state.j = (prng_state.j + prng_state.s[prng_state.i]) & 0xff; t = prng_state.s[prng_state.i]; prng_state.s[prng_state.i] = prng_state.s[prng_state.j]; prng_state.s[prng_state.j] = t; t = prng_state.s[prng_state.i] + prng_state.s[prng_state.j]; return prng_state.s[t & 0xff]; } /* ** Return a random 32-bit integer. The integer is generated by making ** 4 calls to sqliteRandomByte(). */ int sqliteRandomInteger(void){ |
︙ | ︙ |
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.35 2001/09/13 21:53:10 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ |
︙ | ︙ | |||
178 179 180 181 182 183 184 185 186 187 188 189 190 191 | /* 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. */ if( eDest==SRT_Except ){ sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_Delete, iParm, 0, 0, 0); }else /* If we are creating a set for an "expr IN (SELECT ...)" construct, ** then there should be a single item on the stack. Write this ** item into the set table with bogus data. */ | > | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | /* 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. */ if( eDest==SRT_Except ){ sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0, 0, 0); sqliteVdbeAddOp(v, OP_MoveTo, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_Delete, iParm, 0, 0, 0); }else /* If we are creating a set for an "expr IN (SELECT ...)" construct, ** then there should be a single item on the stack. Write this ** item into the set table with bogus data. */ |
︙ | ︙ |
Changes to src/test3.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | ** http://www.hwaci.com/drh/ ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** http://www.hwaci.com/drh/ ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test3.c,v 1.10 2001/09/13 21:53:10 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" #include "btree.h" #include "tcl.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
711 712 713 714 715 716 717 | " ID\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; sqliteBtreeKeySize(pCur, &n); zBuf = malloc( n+1 ); rc = sqliteBtreeKey(pCur, 0, n, zBuf); | | > > | | 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 | " ID\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; sqliteBtreeKeySize(pCur, &n); zBuf = malloc( n+1 ); rc = sqliteBtreeKey(pCur, 0, n, zBuf); if( rc!=n ){ char zMsg[100]; free(zBuf); sprintf(zMsg, "truncated key: got %d of %d bytes", rc, n); Tcl_AppendResult(interp, zMsg, 0); return TCL_ERROR; } zBuf[n] = 0; Tcl_AppendResult(interp, zBuf, 0); free(zBuf); return SQLITE_OK; } |
︙ | ︙ | |||
747 748 749 750 751 752 753 | " ID\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; sqliteBtreeDataSize(pCur, &n); zBuf = malloc( n+1 ); rc = sqliteBtreeData(pCur, 0, n, zBuf); | | > > | | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | " ID\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; sqliteBtreeDataSize(pCur, &n); zBuf = malloc( n+1 ); rc = sqliteBtreeData(pCur, 0, n, zBuf); if( rc!=n ){ char zMsg[100]; free(zBuf); sprintf(zMsg, "truncated data: got %d of %d bytes", rc, n); Tcl_AppendResult(interp, zMsg, 0); return TCL_ERROR; } zBuf[n] = 0; Tcl_AppendResult(interp, zBuf, 0); free(zBuf); return SQLITE_OK; } |
︙ | ︙ |
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 52 53 54 55 | ** 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.64 2001/09/13 21:53:10 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include <unistd.h> /* ** SQL is translated into a sequence of instructions to be ** executed by a virtual machine. Each instruction is an instance ** of the following structure. */ typedef struct VdbeOp Op; |
︙ | ︙ | |||
871 872 873 874 875 876 877 | */ static char *zOpName[] = { 0, "Transaction", "Commit", "Rollback", "Open", "OpenTemp", "Close", "MoveTo", "Fcnt", "NewRecno", "Put", "Distinct", "Found", "NotFound", "Delete", "Column", "KeyAsData", "Recno", "FullKey", "Rewind", "Next", | | | | | | | | | | | | | | | | | | | | | | 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 | */ static char *zOpName[] = { 0, "Transaction", "Commit", "Rollback", "Open", "OpenTemp", "Close", "MoveTo", "Fcnt", "NewRecno", "Put", "Distinct", "Found", "NotFound", "Delete", "Column", "KeyAsData", "Recno", "FullKey", "Rewind", "Next", "Destroy", "Clear", "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. |
︙ | ︙ | |||
1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 | /* Opcode: Open P1 P2 P3 ** ** Open a new cursor for the database table whose root page is ** P2 in the main database file. Give the new cursor an identifier ** of P1. The P1 values need not be contiguous but all P1 values ** should be small integers. It is an error for P1 to be negative. ** ** The P3 value is the name of the table or index being opened. ** The P3 value is not actually used by this opcode and may be ** omitted. But the code generator usually inserts the index or ** table name into P3 to make the code easier to read. */ case OP_Open: { int busy = 0; int i = pOp->p1; 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); } memset(&p->aCsr[i], 0, sizeof(Cursor)); do{ | > > > > > > > > > > > > > > > | | 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 | /* Opcode: Open P1 P2 P3 ** ** Open a new cursor for the database table whose root page is ** P2 in the main database file. Give the new cursor an identifier ** of P1. The P1 values need not be contiguous but all P1 values ** should be small integers. It is an error for P1 to be negative. ** ** If P2==0 then take the root page number from the top of the stack. ** ** The P3 value is the name of the table or index being opened. ** The P3 value is not actually used by this opcode and may be ** omitted. But the code generator usually inserts the index or ** table name into P3 to make the code easier to read. */ case OP_Open: { int busy = 0; int i = pOp->p1; int tos = p->tos; int p2 = pOp->p2; if( p2<=0 ){ if( tos<0 ) goto not_enough_stack; Integerify(p, tos); p2 = p->aStack[tos].i; POPSTACK; if( p2<2 ){ sqliteSetString(pzErrMsg, "root page number less than 2", 0); rc = SQLITE_INTERNAL; goto cleanup; } } 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); } memset(&p->aCsr[i], 0, sizeof(Cursor)); do{ rc = sqliteBtreeCursor(pBt, 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; |
︙ | ︙ | |||
2236 2237 2238 2239 2240 2241 2242 | POPSTACK; POPSTACK; break; } /* Opcode: Delete P1 * * ** | > > | > > | < < < < < < < < < < < < < < < | 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 | POPSTACK; POPSTACK; break; } /* Opcode: Delete P1 * * ** ** Delete the record at which the P1 cursor is currently pointing. ** ** The cursor will be left pointing at either the next or the previous ** record in the table. If it is left pointing at the next record, then ** the next OP_Next will be a no-op. Hence it is OK to delete a record ** from within an OP_Next loop. */ case OP_Delete: { int i = pOp->p1; if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){ rc = sqliteBtreeDelete(p->aCsr[i].pCursor); } break; } /* Opcode: KeyAsData P1 P2 * ** ** Turn the key-as-data mode for cursor P1 either on (if P2==1) or ** off (if P2==0). In key-as-data mode, the OP_Field opcode pulls |
︙ | ︙ | |||
2299 2300 2301 2302 2303 2304 2305 | */ case OP_Column: { int amt, offset, nCol, payloadSize; int aHdr[10]; static const int mxHdr = sizeof(aHdr)/sizeof(aHdr[0]); int i = pOp->p1; int p2 = pOp->p2; | | | | 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 | */ case OP_Column: { int amt, offset, nCol, payloadSize; int aHdr[10]; static const int mxHdr = sizeof(aHdr)/sizeof(aHdr[0]); int i = pOp->p1; int p2 = pOp->p2; int tos = p->tos+1; BtCursor *pCrsr; char *z; VERIFY( if( NeedStack(p, tos+1) ) 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. */ |
︙ | ︙ | |||
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 | z = sqliteMalloc( amt ); if( z==0 ) goto no_mem; (*xRead)(pCrsr, offset, amt, z); aStack[tos].flags = STK_Str | STK_Dyn; zStack[tos] = z; aStack[tos].n = amt; } } break; } /* Opcode: Recno P1 * * ** ** Push onto the stack an integer which is the first 4 bytes of the | > | 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 | z = sqliteMalloc( amt ); if( z==0 ) goto no_mem; (*xRead)(pCrsr, offset, amt, z); aStack[tos].flags = STK_Str | STK_Dyn; zStack[tos] = z; aStack[tos].n = amt; } p->tos = tos; } break; } /* Opcode: Recno P1 * * ** ** Push onto the stack an integer which is the first 4 bytes of the |
︙ | ︙ | |||
2526 2527 2528 2529 2530 2531 2532 | 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; | > > > > | | > | 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 | 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; if( pCrsr->atFirst ){ pCrsr->atFirst = 0; res = 0; }else{ 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; |
︙ | ︙ | |||
2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 | ** 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: CreateTable * * * ** ** Allocate a new table in the main database file. Push the page number ** for the root page of the new table onto the stack. ** ** The root page number is also written to a memory location which has | > > > > > > > > > > > | 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 | ** 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: Clear P1 * * ** ** Delete all contents of the database table or index whose root page ** in the database file is given by P1. But, unlike OP_Destroy, do not ** remove the table or index from the database file. */ case OP_Clear: { sqliteBtreeClearTable(pBt, pOp->p1); break; } /* Opcode: CreateTable * * * ** ** Allocate a new table in the main database file. Push the page number ** for the root page of the new table onto the stack. ** ** The root page number is also written to a memory location which has |
︙ | ︙ | |||
2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 | break; } /* Opcode: CreateIndex * * * ** ** Allocate a new Index in the main database file. Push the page number ** for the root page of the new table onto the stack. ** ** The root page number is also written to a memory location which has ** be set up by the parser. The difference between CreateTable and ** CreateIndex is that each writes its root page number into a different ** memory location. This writing of the page number into a memory location ** is used by the SQL parser to record the page number in its internal ** data structures. | > > | 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 | break; } /* Opcode: CreateIndex * * * ** ** Allocate a new Index in the main database file. Push the page number ** for the root page of the new table onto the stack. ** ** If P1>=0 then open a cursor named P1 on the newly created index. ** ** The root page number is also written to a memory location which has ** be set up by the parser. The difference between CreateTable and ** CreateIndex is that each writes its root page number into a different ** memory location. This writing of the page number into a memory location ** is used by the SQL parser to record the page number in its internal ** data structures. |
︙ | ︙ | |||
3680 3681 3682 3683 3684 3685 3686 | fprintf(p->trace,"\n"); } #endif } cleanup: Cleanup(p); | | | 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 | fprintf(p->trace,"\n"); } #endif } cleanup: Cleanup(p); if( (p->pTableRoot || p->pIndexRoot) && rc==SQLITE_OK ){ rc = SQLITE_INTERNAL; sqliteSetString(pzErrMsg, "table or index root page not set", 0); } if( rc!=SQLITE_OK && (db->flags & SQLITE_InTrans)!=0 ){ sqliteBtreeRollback(pBt); sqliteRollbackInternalChanges(db); db->flags &= ~SQLITE_InTrans; |
︙ | ︙ |
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.21 2001/09/13 21:53:10 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include <stdio.h> /* ** A single VDBE is an opaque structure named "Vdbe". Only routines |
︙ | ︙ | |||
90 91 92 93 94 95 96 | #define OP_KeyAsData 16 #define OP_Recno 17 #define OP_FullKey 18 #define OP_Rewind 19 #define OP_Next 20 #define OP_Destroy 21 | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 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 | #define OP_KeyAsData 16 #define OP_Recno 17 #define OP_FullKey 18 #define OP_Rewind 19 #define OP_Next 20 #define OP_Destroy 21 #define OP_Clear 22 #define OP_CreateIndex 23 #define OP_CreateTable 24 #define OP_Reorganize 25 #define OP_BeginIdx 26 #define OP_NextIdx 27 #define OP_PutIdx 28 #define OP_DeleteIdx 29 #define OP_MemLoad 30 #define OP_MemStore 31 #define OP_ListOpen 32 #define OP_ListWrite 33 #define OP_ListRewind 34 #define OP_ListRead 35 #define OP_ListClose 36 #define OP_SortOpen 37 #define OP_SortPut 38 #define OP_SortMakeRec 39 #define OP_SortMakeKey 40 #define OP_Sort 41 #define OP_SortNext 42 #define OP_SortKey 43 #define OP_SortCallback 44 #define OP_SortClose 45 #define OP_FileOpen 46 #define OP_FileRead 47 #define OP_FileColumn 48 #define OP_FileClose 49 #define OP_AggReset 50 #define OP_AggFocus 51 #define OP_AggIncr 52 #define OP_AggNext 53 #define OP_AggSet 54 #define OP_AggGet 55 #define OP_SetInsert 56 #define OP_SetFound 57 #define OP_SetNotFound 58 #define OP_SetClear 59 #define OP_MakeRecord 60 #define OP_MakeKey 61 #define OP_MakeIdxKey 62 #define OP_Goto 63 #define OP_If 64 #define OP_Halt 65 #define OP_ColumnCount 66 #define OP_ColumnName 67 #define OP_Callback 68 #define OP_Integer 69 #define OP_String 70 #define OP_Null 71 #define OP_Pop 72 #define OP_Dup 73 #define OP_Pull 74 #define OP_Add 75 #define OP_AddImm 76 #define OP_Subtract 77 #define OP_Multiply 78 #define OP_Divide 79 #define OP_Min 80 #define OP_Max 81 #define OP_Like 82 #define OP_Glob 83 #define OP_Eq 84 #define OP_Ne 85 #define OP_Lt 86 #define OP_Le 87 #define OP_Gt 88 #define OP_Ge 89 #define OP_IsNull 90 #define OP_NotNull 91 #define OP_Negative 92 #define OP_And 93 #define OP_Or 94 #define OP_Not 95 #define OP_Concat 96 #define OP_Noop 97 #define OP_Strlen 98 #define OP_Substr 99 #define OP_MAX 99 /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ Vdbe *sqliteVdbeCreate(sqlite*); void sqliteVdbeCreateCallback(Vdbe*, int*); |
︙ | ︙ |
Changes to test/all.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 | # Author contact information: # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file runs all tests. # | | < < < < < < < < | | | | < | 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 | # Author contact information: # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file runs all tests. # # $Id: all.test,v 1.8 2001/09/13 21:53:10 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl rename finish_test really_finish_test proc finish_test {} {memleak_check} if {[file exists ./sqlite_test_count]} { set COUNT [exec cat ./sqlite_test_count] } else { set COUNT 3 } # LeakList will hold a list of the number of unfreed mallocs after # each round of the test. This number should be constant. If it # grows, it may mean there is a memory leak in the library. # set LeakList {} for {set Counter 0} {$Counter<$COUNT} {incr Counter} { foreach testfile [lsort -dictionary [glob $testdir/*.test]] { if {[file tail $testfile]=="all.test"} continue if {[file tail $testfile]=="malloc.test"} continue source $testfile } if {[info exists Leak]} { lappend LeakList $Leak } } # Do one last test to look for a memory leak in the library. This will |
︙ | ︙ | |||
77 78 79 80 81 82 83 | break } } puts " Ok" } if {[file readable $testdir/malloc.test]} { | < < | < | 68 69 70 71 72 73 74 75 76 77 78 | break } } puts " Ok" } if {[file readable $testdir/malloc.test]} { source $testdir/malloc.test } really_finish_test |
Deleted test/dbbe.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/index.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 file is testing the CREATE INDEX statement. # | | < | < | | 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 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE INDEX statement. # # $Id: index.test,v 1.11 2001/09/13 21:53:10 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a basic index and verify it is added to sqlite_master # do_test index-1.1 { execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)} execsql {CREATE INDEX index1 ON test1(f1)} execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } {index1 test1} do_test index-1.1b { execsql {SELECT name, sql, tbl_name, type FROM sqlite_master WHERE name='index1'} } {index1 {CREATE INDEX index1 ON test1(f1)} test1 index} do_test index-1.1c { db close sqlite db test.db execsql {SELECT name, sql, tbl_name, type FROM sqlite_master WHERE name='index1'} } {index1 {CREATE INDEX index1 ON test1(f1)} test1 index} do_test index-1.1d { db close sqlite db test.db execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } {index1 test1} # Verify that the index dies with the table # do_test index-1.2 { execsql {DROP TABLE test1} |
︙ | ︙ | |||
97 98 99 100 101 102 103 | execsql $sql } execsql {SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='test1' ORDER BY name} } $r | < < < < < < < < < < < < < < < | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | execsql $sql } execsql {SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='test1' ORDER BY name} } $r # Verify that all the indices go away when we drop the table. # do_test index-3.3 { execsql {DROP TABLE test1} execsql {SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='test1' ORDER BY name} } {} # Create a table and insert values into that table. Then create # an index on that table. Verify that we can select values # from the table correctly using the index. # # Note that the index names "index9" and "indext" are chosen because # they both have the same hash. |
︙ | ︙ | |||
224 225 226 227 228 229 230 | do_test index-7.1 { execsql {CREATE TABLE test1(f1 int, f2 int primary key)} for {set i 1} {$i<20} {incr i} { execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])" } execsql {SELECT count(*) FROM test1} } {19} | < < < < | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | do_test index-7.1 { execsql {CREATE TABLE test1(f1 int, f2 int primary key)} for {set i 1} {$i<20} {incr i} { execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])" } execsql {SELECT count(*) FROM test1} } {19} do_test index-7.2 { execsql {SELECT f1 FROM test1 WHERE f2=65536} } {16} do_test index-7.3 { set code [execsql {EXPLAIN SELECT f1 FROM test1 WHERE f2=65536}] expr {[lsearch $code test1__primary_key]>0} } {1} |
︙ | ︙ |
Changes to test/select2.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 file is testing the SELECT statement. # | | | 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 file is testing the SELECT statement. # # $Id: select2.test,v 1.12 2001/09/13 21:53:10 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table with some data # execsql {CREATE TABLE tbl1(f1 int, f2 int)} |
︙ | ︙ | |||
108 109 110 111 112 113 114 | } {1} do_test select2-3.2e { execsql {SELECT fcnt() FROM tbl2 WHERE f2=1000} } {1} # omit the time-dependent tests # | < | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | } {1} do_test select2-3.2e { execsql {SELECT fcnt() FROM tbl2 WHERE f2=1000} } {1} # omit the time-dependent tests # do_probtest select2-3.2f { set t1 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE 1000=f2}} 1] 0] set t2 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE f2=1000}} 1] 0] expr {$t1*0.7<$t2 && $t2*0.7<$t1} } {1} # Make sure queries run faster with an index than without |
︙ | ︙ |
Changes to test/table.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 file is testing the CREATE TABLE statement. # | | | 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 file is testing the CREATE TABLE statement. # # $Id: table.test,v 1.10 2001/09/13 21:53:10 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a basic table and verify it is added to sqlite_master # do_test table-1.1 { |
︙ | ︙ | |||
41 42 43 44 45 46 47 | SELECT sql FROM sqlite_master WHERE type!='meta' } } {{CREATE TABLE test1 ( one varchar(10), two text )}} | < < < < < < < < < < < < | 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 | SELECT sql FROM sqlite_master WHERE type!='meta' } } {{CREATE TABLE test1 ( one varchar(10), two text )}} # Verify the other fields of the sqlite_master file. # do_test table-1.3 { execsql {SELECT name, tbl_name, type FROM sqlite_master WHERE type!='meta'} } {test1 test1 table} # Close and reopen the database. Verify that everything is # still the same. # do_test table-1.4 { db close sqlite db testdb execsql {SELECT name, tbl_name, type from sqlite_master WHERE type!='meta'} } {test1 test1 table} # Drop the database and make sure it disappears. # do_test table-1.5 { execsql {DROP TABLE test1} execsql {SELECT * FROM sqlite_master WHERE type!='meta'} } {} # Verify that the file associated with the database is gone. # do_test table-1.5 { lsort [glob -nocomplain testdb/*.tbl] } {testdb/sqlite_master.tbl} # Close and reopen the database. Verify that the table is # still gone. # do_test table-1.6 { db close sqlite db testdb execsql {SELECT name FROM sqlite_master WHERE type!='meta'} } {} # Repeat the above steps, but this time quote the table name. |
︙ | ︙ | |||
123 124 125 126 127 128 129 | set v [catch {execsql {CREATE TABLE test2(two text)}} msg] lappend v $msg } {1 {table test2 already exists}} do_test table-2.1b { set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg] lappend v $msg } {1 {table sqlite_master already exists}} | < < | 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 | set v [catch {execsql {CREATE TABLE test2(two text)}} msg] lappend v $msg } {1 {table test2 already exists}} do_test table-2.1b { set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg] lappend v $msg } {1 {table sqlite_master already exists}} do_test table-2.1c { db close sqlite db testdb set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg] lappend v $msg } {1 {table sqlite_master already exists}} do_test table-2.1d { execsql {DROP TABLE test2; SELECT name FROM sqlite_master WHERE type!='meta'} } {} # Verify that we cannot make a table with the same name as an index # do_test table-2.2a { execsql {CREATE TABLE test2(one text); CREATE INDEX test3 ON test2(one)} set v [catch {execsql {CREATE TABLE test3(two text)}} msg] lappend v $msg } {1 {there is already an index named test3}} do_test table-2.2b { db close sqlite db testdb set v [catch {execsql {CREATE TABLE test3(two text)}} msg] lappend v $msg } {1 {there is already an index named test3}} do_test table-2.2c { |
︙ | ︙ | |||
202 203 204 205 206 207 208 | set v [catch {execsql {CREATE TABLE biG(xyz foo)}} msg] lappend v $msg } {1 {table biG already exists}} do_test table-3.4 { set v [catch {execsql {CREATE TABLE bIg(xyz foo)}} msg] lappend v $msg } {1 {table bIg already exists}} | < | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | set v [catch {execsql {CREATE TABLE biG(xyz foo)}} msg] lappend v $msg } {1 {table biG already exists}} do_test table-3.4 { set v [catch {execsql {CREATE TABLE bIg(xyz foo)}} msg] lappend v $msg } {1 {table bIg already exists}} do_test table-3.5 { db close sqlite db testdb set v [catch {execsql {CREATE TABLE Big(xyz foo)}} msg] lappend v $msg } {1 {table Big already exists}} do_test table-3.6 { |
︙ | ︙ | |||
231 232 233 234 235 236 237 | append sql "field$k text," } append sql "last_field text)" execsql $sql } execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } $r | < | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | append sql "field$k text," } append sql "last_field text)" execsql $sql } execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } $r do_test table-4.1b { db close sqlite db testdb execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } $r # Drop the even numbered tables |
︙ | ︙ | |||
293 294 295 296 297 298 299 | execsql {CREATE TABLE test1(f1 int)} execsql {EXPLAIN DROP TABLE test1} execsql {SELECT name FROM sqlite_master WHERE type!='meta'} } {test1} # Create a table with a goofy name # | < | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | execsql {CREATE TABLE test1(f1 int)} execsql {EXPLAIN DROP TABLE test1} execsql {SELECT name FROM sqlite_master WHERE type!='meta'} } {test1} # Create a table with a goofy name # do_test table-6.1 { execsql {CREATE TABLE 'Spaces In This Name!'(x int)} execsql {INSERT INTO 'spaces in this name!' VALUES(1)} set list [glob -nocomplain testdb/spaces*.tbl] } {testdb/spaces+in+this+name+.tbl} # Try using keywords as table names or column names. |
︙ | ︙ |
Changes to test/tester.tcl.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements some common TCL routines used for regression # testing the SQLite library # | | | 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 some common TCL routines used for regression # testing the SQLite library # # $Id: tester.tcl,v 1.16 2001/09/13 21:53:10 drh Exp $ # Make sure tclsqlite was compiled correctly. Abort now with an # error message if not. # if {[sqlite -tcl-uses-utf]} { if {"\u1234"=="u1234"} { puts stderr "***** BUILD PROBLEM *****" |
︙ | ︙ | |||
50 51 52 53 54 55 56 | puts stderr "and try again.\n**************************" exit 1 } } # Create a test database # | < < < < < < < < < < | < | < < < < < < < < | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | puts stderr "and try again.\n**************************" exit 1 } } # Create a test database # file delete -force ./test.db file delete -force ./test.db-journal sqlite db ./test.db # Abort early if this script has been run before. # if {[info exists nTest]} return # Set the test counters to zero # |
︙ | ︙ | |||
105 106 107 108 109 110 111 | set go 1 break } } } if {!$go} return incr nTest | | > > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | set go 1 break } } } if {!$go} return incr nTest puts -nonewline $name... flush stdout if {[catch {uplevel #0 "$cmd;\n"} result]} { puts "\nError: $result" incr nErr if {$nErr>10} {puts "*** Giving up..."; exit 1} } elseif {[string compare $result $expected]} { puts "\nExpected: \[$expected\]\n Got: \[$result\]" incr nErr if {$nErr>10} {puts "*** Giving up..."; exit 1} } else { puts " Ok" } } # Invoke this procedure on a test that is probabilistic # and might fail sometimes. |
︙ | ︙ | |||
140 141 142 143 144 145 146 | set go 1 break } } } if {!$go} return incr nTest | | < < < < < < < < < < < < < < < < < < < < < < < | 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 152 | set go 1 break } } } if {!$go} return incr nTest puts -nonewline $name... flush stdout if {[catch {uplevel #0 "$cmd;\n"} result]} { puts "\nError: $result" incr nErr } elseif {[string compare $result $expected]} { puts "\nExpected: \[$expected\]\n Got: \[$result\]" puts "NOTE: The results of the previous test depend on system load" puts "and processor speed. The test may sometimes fail even if the" puts "library is working correctly." incr nProb } else { puts " Ok" } } # The procedure uses the special "sqlite_malloc_stat" command # (which is only available if SQLite is compiled with -DMEMORY_DEBUG=1) # to see how many malloc()s have not been free()ed. The number # of surplus malloc()s is stored in the global variable $::Leak. # If the value in $::Leak grows, it may mean there is a memory leak # in the library. # |
︙ | ︙ |
Changes to test/vacuum.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 file is testing the VACUUM statement. # | | | 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 file is testing the VACUUM statement. # # $Id: vacuum.test,v 1.4 2001/09/13 21:53:10 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Try to vacuum a non-existant table. # do_test vacuum-1.1 { |
︙ | ︙ | |||
49 50 51 52 53 54 55 | execsql {CREATE INDEX index1 ON test1(a)} execsql {INSERT INTO test1 VALUES(1)} execsql {INSERT INTO test1 VALUES(1)} execsql {INSERT INTO test1 VALUES(2)} execsql {INSERT INTO test1 VALUES(3)} execsql {INSERT INTO test2 VALUES(4)} | < < | 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 | execsql {CREATE INDEX index1 ON test1(a)} execsql {INSERT INTO test1 VALUES(1)} execsql {INSERT INTO test1 VALUES(1)} execsql {INSERT INTO test1 VALUES(2)} execsql {INSERT INTO test1 VALUES(3)} execsql {INSERT INTO test2 VALUES(4)} do_test vacuum-1.3 { set b1 [file mtime testdb/test1.tbl] set b2 [file mtime testdb/test2.tbl] set b3 [file mtime testdb/index1.tbl] after 1000 execsql {VACUUM test1} set a1 [file mtime testdb/test1.tbl] set a2 [file mtime testdb/test2.tbl] set a3 [file mtime testdb/index1.tbl] expr {$a1>$b1 && $a2==$b2 && $a3==$b3} } {1} if {$::tcl_platform(platform)!="windows"} { do_test vacuum-1.4 { set b1 [file mtime testdb/test1.tbl] set b2 [file mtime testdb/test2.tbl] set b3 [file mtime testdb/index1.tbl] after 1000 execsql {VACUUM} set a1 [file mtime testdb/test1.tbl] |
︙ | ︙ |