Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | An attempt to delete a single row using a WHERE clause that specifies the rowid would result in an error if the rowid did not exist. This problem has been resolved. (CVS 338) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
011be9a9d2632d261489005d97c69b0a |
User & Date: | drh 2002-01-04 03:09:29.000 |
Context
2002-01-06
| ||
17:07 | Comment updates most. Also some small changes to the VDBE. (CVS 339) (check-in: 9b0be4fcc1 user: drh tags: trunk) | |
2002-01-04
| ||
03:09 | An attempt to delete a single row using a WHERE clause that specifies the rowid would result in an error if the rowid did not exist. This problem has been resolved. (CVS 338) (check-in: 011be9a9d2 user: drh tags: trunk) | |
2001-12-31
| ||
02:48 | Comment changes. Change the use of BTree so that either the key is an integer or the data is empty. (CVS 337) (check-in: 18e606f748 user: drh tags: trunk) | |
Changes
Changes to VERSION.
|
| | | 1 | 2.2.1 |
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btree.c,v 1.46 2002/01/04 03:09:29 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. |
︙ | ︙ | |||
724 725 726 727 728 729 730 731 732 733 734 735 736 737 | ** Attempt to start a new transaction. ** ** A transaction must be started before attempting any changes ** to the database. None of the following routines will work ** unless a transaction is started first: ** ** sqliteBtreeCreateTable() ** sqliteBtreeClearTable() ** sqliteBtreeDropTable() ** sqliteBtreeInsert() ** sqliteBtreeDelete() ** sqliteBtreeUpdateMeta() */ int sqliteBtreeBeginTrans(Btree *pBt){ | > | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | ** Attempt to start a new transaction. ** ** A transaction must be started before attempting any changes ** to the database. None of the following routines will work ** unless a transaction is started first: ** ** sqliteBtreeCreateTable() ** sqliteBtreeCreateIndex() ** sqliteBtreeClearTable() ** sqliteBtreeDropTable() ** sqliteBtreeInsert() ** sqliteBtreeDelete() ** sqliteBtreeUpdateMeta() */ int sqliteBtreeBeginTrans(Btree *pBt){ |
︙ | ︙ | |||
2223 2224 2225 2226 2227 2228 2229 | } rc = balance(pCur->pBt, pPage, pCur); } return rc; } /* | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2224 2225 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 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 | } rc = balance(pCur->pBt, pPage, pCur); } return rc; } /* ** Create a new BTree table. Write into *piTable the page ** number for the root page of the new table. ** ** In the current implementation, BTree tables and BTree indices are the ** the same. But in the future, we may change this so that BTree tables ** are restricted to having a 4-byte integer key and arbitrary data and ** BTree indices are restricted to having an arbitrary key and no data. */ int sqliteBtreeCreateTable(Btree *pBt, int *piTable){ MemPage *pRoot; Pgno pgnoRoot; int rc; if( !pBt->inTrans ){ return SQLITE_ERROR; /* Must start a transaction first */ } rc = allocatePage(pBt, &pRoot, &pgnoRoot); if( rc ) return rc; assert( sqlitepager_iswriteable(pRoot) ); zeroPage(pRoot); sqlitepager_unref(pRoot); *piTable = (int)pgnoRoot; return SQLITE_OK; } /* ** Create a new BTree index. Write into *piTable the page ** number for the root page of the new index. ** ** In the current implementation, BTree tables and BTree indices are the ** the same. But in the future, we may change this so that BTree tables ** are restricted to having a 4-byte integer key and arbitrary data and ** BTree indices are restricted to having an arbitrary key and no data. */ int sqliteBtreeCreateIndex(Btree *pBt, int *piIndex){ MemPage *pRoot; Pgno pgnoRoot; int rc; if( !pBt->inTrans ){ return SQLITE_ERROR; /* Must start a transaction first */ } rc = allocatePage(pBt, &pRoot, &pgnoRoot); if( rc ) return rc; assert( sqlitepager_iswriteable(pRoot) ); zeroPage(pRoot); sqlitepager_unref(pRoot); *piIndex = (int)pgnoRoot; return SQLITE_OK; } /* ** Erase the given database page and all its children. Return ** the page to the freelist. */ static int clearDatabasePage(Btree *pBt, Pgno pgno, int freePageFlag){ MemPage *pPage; |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** | | > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** ** @(#) $Id: btree.h,v 1.19 2002/01/04 03:09:30 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*); int sqliteBtreeSetCacheSize(Btree*, int); int sqliteBtreeBeginTrans(Btree*); int sqliteBtreeCommit(Btree*); int sqliteBtreeRollback(Btree*); int sqliteBtreeCreateTable(Btree*, int*); int sqliteBtreeCreateIndex(Btree*, int*); int sqliteBtreeDropTable(Btree*, int); int sqliteBtreeClearTable(Btree*, int); int sqliteBtreeCursor(Btree*, int iTable, int wrFlag, BtCursor **ppCur); int sqliteBtreeMoveto(BtCursor*, const void *pKey, int nKey, int *pRes); int sqliteBtreeDelete(BtCursor*); int sqliteBtreeInsert(BtCursor*, const void *pKey, int nKey, |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.36 2002/01/04 03:09:30 drh Exp $ */ #include "sqliteInt.h" /* ** Walk an expression tree. Return 1 if the expression is constant ** and 0 if it involves variables. */ |
︙ | ︙ | |||
240 241 242 243 244 245 246 | 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(). */ | | | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | 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, 1); 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. */ |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** ** $Id: insert.c,v 1.31 2002/01/04 03:09:30 drh Exp $ */ #include "sqliteInt.h" /* ** This routine is call to handle SQL of the following forms: ** ** insert into TABLE (IDLIST) values(EXPRLIST) |
︙ | ︙ | |||
80 81 82 83 84 85 86 | if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); pParse->schemaVerified = 1; } /* Figure out how many columns of data are supplied. If the data | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | if( (db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0); pParse->schemaVerified = 1; } /* Figure out how many columns of data are supplied. If the data ** is coming from a SELECT statement, then this step has to generate ** 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++; |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.53 2002/01/04 03:09:30 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ |
︙ | ︙ | |||
542 543 544 545 546 547 548 | */ unionTab = pParse->nTab++; if( p->pOrderBy && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){ return 1; } if( p->op!=TK_ALL ){ | | | 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | */ unionTab = pParse->nTab++; if( p->pOrderBy && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){ return 1; } if( p->op!=TK_ALL ){ sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 1); sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1); }else{ sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 0); } } /* Code the SELECT statements to our left |
︙ | ︙ | |||
604 605 606 607 608 609 610 | ** by allocating the tables we will need. */ tab1 = pParse->nTab++; tab2 = pParse->nTab++; if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){ return 1; } | | | | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 | ** by allocating the tables we will need. */ tab1 = pParse->nTab++; tab2 = pParse->nTab++; if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){ return 1; } sqliteVdbeAddOp(v, OP_OpenTemp, tab1, 1); sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1); /* Code the SELECTs to our left into temporary table "tab1". */ rc = sqliteSelect(pParse, pPrior, SRT_Union, tab1); if( rc ) return rc; /* Code the current SELECT into temporary table "tab2" */ sqliteVdbeAddOp(v, OP_OpenTemp, tab2, 1); sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1); p->pPrior = 0; rc = sqliteSelect(pParse, p, SRT_Union, tab2); p->pPrior = pPrior; if( rc ) return rc; /* Generate code to take the intersection of the two temporary |
︙ | ︙ | |||
928 929 930 931 932 933 934 | sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_MemStore, iParm, 1); } /* Begin the database scan */ if( isDistinct ){ | | | 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 | sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_MemStore, iParm, 1); } /* Begin the database scan */ if( isDistinct ){ sqliteVdbeAddOp(v, OP_OpenTemp, distinct, 1); } pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0); if( pWInfo==0 ) return 1; /* Use the standard inner loop if we are not dealing with ** aggregates */ |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** ** $Id: vdbe.c,v 1.104 2002/01/04 03:09:30 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveTo or the OP_Next opcode. The test |
︙ | ︙ | |||
2533 2534 2535 2536 2537 2538 2539 | goto abort_due_to_error; } } }while( busy ); break; } | | | | | | > > > > | 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 | goto abort_due_to_error; } } }while( busy ); break; } /* Opcode: OpenTemp P1 P2 * ** ** Open a new cursor that points to a table or index in a temporary ** database file. The temporary file is opened read/write even if ** the main database is read-only. The temporary file is deleted ** when the cursor is closed. ** ** The cursor points to a BTree table if P2==0 and to a BTree index ** if P2==1. A BTree table must have an integer key and can have arbitrary ** data. A BTree index has no data but can have an arbitrary key. ** ** This opcode is used for tables that exist for the duration of a single ** SQL statement only. Tables created using CREATE TEMPORARY TABLE ** are opened using OP_OpenAux or OP_OpenWrAux. "Temporary" in the ** context of this opcode means for the duration of a single SQL statement ** whereas "Temporary" in the context of CREATE TABLE means for the duration ** of the connection to the database. Same word; different meanings. |
︙ | ︙ | |||
2566 2567 2568 2569 2570 2571 2572 | p->nCursor = i+1; } pCx = &p->aCsr[i]; cleanupCursor(pCx); memset(pCx, 0, sizeof(*pCx)); rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt); if( rc==SQLITE_OK ){ | | > > | > > > > > > | 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 | p->nCursor = i+1; } pCx = &p->aCsr[i]; cleanupCursor(pCx); memset(pCx, 0, sizeof(*pCx)); rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt); if( rc==SQLITE_OK ){ rc = sqliteBtreeBeginTrans(pCx->pBt); } if( rc==SQLITE_OK ){ if( pOp->p2 ){ int pgno; rc = sqliteBtreeCreateIndex(pCx->pBt, &pgno); if( rc==SQLITE_OK ){ rc = sqliteBtreeCursor(pCx->pBt, pgno, 1, &pCx->pCursor); } }else{ rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor); } } break; } /* Opcode: Close P1 * * ** ** Close a cursor previously opened as P1. If P1 is not |
︙ | ︙ | |||
3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 | ** for the root page of the new table onto the stack. ** ** The root page number is also written to a memory location that P3 ** points to. This is the mechanism is used to write the root page ** number into the parser's internal data structures that describe the ** new table. ** ** See also: CreateIndex */ /* Opcode: CreateIndex * P2 P3 ** | > > > > | | > | > | > > > | 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 | ** for the root page of the new table onto the stack. ** ** The root page number is also written to a memory location that P3 ** points to. This is the mechanism is used to write the root page ** number into the parser's internal data structures that describe the ** new table. ** ** The difference between a table and an index is this: A table must ** have a 4-byte integer key and can have arbitrary data. An index ** has an arbitrary key but no data. ** ** See also: CreateIndex */ /* Opcode: CreateIndex * P2 P3 ** ** Allocate a new index in the main database file if P2==0 or in the ** auxiliary database file if P2==1. Push the page number of the ** root page of the new index onto the stack. ** ** See documentation on OP_CreateTable for additional information. */ case OP_CreateIndex: case OP_CreateTable: { int i = ++p->tos; int pgno; VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) assert( pOp->p3!=0 && pOp->p3type==P3_POINTER ); if( pOp->opcode==OP_CreateTable ){ rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno); }else{ rc = sqliteBtreeCreateIndex(pOp->p2 ? db->pBeTemp : pBt, &pgno); } if( rc==SQLITE_OK ){ aStack[i].i = pgno; aStack[i].flags = STK_Int; *(u32*)pOp->p3 = pgno; pOp->p3 = 0; } break; |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** 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. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** 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.30 2002/01/04 03:09:30 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. |
︙ | ︙ | |||
435 436 437 438 439 440 441 442 443 444 445 446 447 448 | } aExpr[k].p = 0; brk = pLevel->brk = sqliteVdbeMakeLabel(v); cont = pLevel->cont = brk; sqliteVdbeAddOp(v, OP_MustBeInt, 0, brk); if( i==pTabList->nId-1 && pushKey ){ haveKey = 1; }else{ sqliteVdbeAddOp(v, OP_NotFound, base+idx, brk); haveKey = 0; } pLevel->op = OP_Noop; }else if( pIdx!=0 && pLevel->score%4==0 ){ /* Case 2: All index constraints are equality operators. | > | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | } aExpr[k].p = 0; brk = pLevel->brk = sqliteVdbeMakeLabel(v); cont = pLevel->cont = brk; sqliteVdbeAddOp(v, OP_MustBeInt, 0, brk); if( i==pTabList->nId-1 && pushKey ){ haveKey = 1; sqliteVdbeAddOp(v, OP_Distinct, base+idx, brk); }else{ sqliteVdbeAddOp(v, OP_NotFound, base+idx, brk); haveKey = 0; } pLevel->op = OP_Noop; }else if( pIdx!=0 && pLevel->score%4==0 ){ /* Case 2: All index constraints are equality operators. |
︙ | ︙ |
Changes to test/rowid.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the magic ROWID column that is # found on all tables. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the magic ROWID column that is # found on all tables. # # $Id: rowid.test,v 1.7 2002/01/04 03:09:30 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Basic ROWID functionality tests. # do_test rowid-1.1 { |
︙ | ︙ | |||
258 259 260 261 262 263 264 265 266 | } } {4} do_test rowid-5.1 { execsql {DELETE FROM t1 WHERE _rowid_ IN (SELECT oid FROM t1 WHERE x>8)} execsql {SELECT max(x) FROM t1} } {8} finish_test | > > > > > > > > > > > > > > > > > > > > > | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | } } {4} do_test rowid-5.1 { execsql {DELETE FROM t1 WHERE _rowid_ IN (SELECT oid FROM t1 WHERE x>8)} execsql {SELECT max(x) FROM t1} } {8} # Make sure a "WHERE rowid=X" clause works when there is no ROWID of X. # do_test rowid-6.1 { execsql { SELECT x FROM t1 } } {1 2 3 4 5 6 7 8} do_test rowid-6.2 { for {set ::norow 1} {[execsql {SELECT x FROM t1 WHERE rowid=10}]!=""} \ {incr ::norow} {} execsql [subst { DELETE FROM t1 WHERE rowid=$::norow }] } {} do_test rowid-6.3 { execsql { SELECT x FROM t1 } } {1 2 3 4 5 6 7 8} finish_test |
Changes to www/changes.tcl.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | } proc chng {date desc} { puts "<DT><B>$date</B></DT>" puts "<DD><P><UL>$desc</UL></P></DD>" } chng {2001 Dec 22 (2.2.0)} { <li>Columns of type INTEGER PRIMARY KEY are actually used as the primary key in underlying B-Tree representation of the table.</li> <li>Several obscure, unrelated bugs were found and fixed while implemented the integer primary key change of the previous bullet.</li> <li>Added the ability to specify "*" as part of a larger column list in | > > > > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | } proc chng {date desc} { puts "<DT><B>$date</B></DT>" puts "<DD><P><UL>$desc</UL></P></DD>" } chng {2002 Jan 3 (2.2.1)} { <li>Bug fix: An attempt to delete a single row of a table with a WHERE clause of "ROWID=x" when no such rowid exists was causing an error.</li> } chng {2001 Dec 22 (2.2.0)} { <li>Columns of type INTEGER PRIMARY KEY are actually used as the primary key in underlying B-Tree representation of the table.</li> <li>Several obscure, unrelated bugs were found and fixed while implemented the integer primary key change of the previous bullet.</li> <li>Added the ability to specify "*" as part of a larger column list in |
︙ | ︙ |