Index: mkopcodeh.awk ================================================================== --- mkopcodeh.awk +++ mkopcodeh.awk @@ -86,10 +86,12 @@ END { cnt = 0 max = 0 print "/* Automatically generated. Do not edit */" print "/* See the mkopcodeh.awk script for details */" + op["OP_Noop"] = -1; + op["OP_Explain"] = -1; for(name in op){ if( op[name]<0 ){ cnt++ while( used[cnt] ) cnt++ op[name] = cnt Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -11,11 +11,11 @@ ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.282 2008/01/16 17:46:38 drh Exp $ +** $Id: test1.c,v 1.283 2008/01/19 20:11:26 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include #include @@ -4218,28 +4218,86 @@ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int i; + sqlite3_vfs *pMain; sqlite3_vfs *apVfs[20]; + sqlite3_vfs one, two; + + sqlite3_vfs_unregister(0); /* Unregister of NULL is harmless */ + one.zName = "__one"; + two.zName = "__two"; + + /* Calling sqlite3_vfs_register with 2nd argument of 0 does not + ** change the default VFS + */ + pMain = sqlite3_vfs_find(0); + sqlite3_vfs_register(&one, 0); + assert( pMain==0 || pMain==sqlite3_vfs_find(0) ); + sqlite3_vfs_register(&two, 0); + assert( pMain==0 || pMain==sqlite3_vfs_find(0) ); + + /* We can find a VFS by its name */ + assert( sqlite3_vfs_find("__one")==&one ); + assert( sqlite3_vfs_find("__two")==&two ); + /* Calling sqlite_vfs_register with non-zero second parameter changes the + ** default VFS, even if the 1st parameter is an existig VFS that is + ** previously registered as the non-default. + */ + sqlite3_vfs_register(&one, 1); + assert( sqlite3_vfs_find("__one")==&one ); + assert( sqlite3_vfs_find("__two")==&two ); + assert( sqlite3_vfs_find(0)==&one ); + sqlite3_vfs_register(&two, 1); + assert( sqlite3_vfs_find("__one")==&one ); + assert( sqlite3_vfs_find("__two")==&two ); + assert( sqlite3_vfs_find(0)==&two ); + if( pMain ){ + sqlite3_vfs_register(pMain, 1); + assert( sqlite3_vfs_find("__one")==&one ); + assert( sqlite3_vfs_find("__two")==&two ); + assert( sqlite3_vfs_find(0)==pMain ); + } + + /* Unlink the default VFS. Repeat until there are no more VFSes + ** registered. + */ for(i=0; izName) ); sqlite3_vfs_unregister(apVfs[i]); assert( 0==sqlite3_vfs_find(apVfs[i]->zName) ); } } assert( 0==sqlite3_vfs_find(0) ); + + /* Relink all VFSes in reverse order. */ for(i=sizeof(apVfs)/sizeof(apVfs[0])-1; i>=0; i--){ if( apVfs[i] ){ sqlite3_vfs_register(apVfs[i], 1); assert( apVfs[i]==sqlite3_vfs_find(0) ); assert( apVfs[i]==sqlite3_vfs_find(apVfs[i]->zName) ); } } + + /* Unregister out sample VFSes. */ + sqlite3_vfs_unregister(&one); + sqlite3_vfs_unregister(&two); + + /* Unregistering a VFS that is not currently registered is harmless */ + sqlite3_vfs_unregister(&one); + sqlite3_vfs_unregister(&two); + assert( sqlite3_vfs_find("__one")==0 ); + assert( sqlite3_vfs_find("__two")==0 ); + + /* We should be left with the original default VFS back as the + ** original */ + assert( sqlite3_vfs_find(0)==pMain ); + return TCL_OK; } /* ** tclcmd: save_prng_state Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -41,11 +41,11 @@ ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.700 2008/01/19 03:35:59 drh Exp $ +** $Id: vdbe.c,v 1.701 2008/01/19 20:11:26 drh Exp $ */ #include "sqliteInt.h" #include #include "vdbeInt.h" @@ -2694,39 +2694,46 @@ ** Use the value in register P3 as a key. Reposition ** cursor P1 so that it points to the smallest entry that is greater ** than or equal to the key in register P3. ** If there are no records greater than or equal to the key and P2 ** is not zero, then jump to P2. +** +** A special feature of this opcode (and different from the +** related OP_MoveGt, OP_MoveLt, and OP_MoveLe) is that if P2 is +** zero and P1 is an SQL table (a b-tree with integer keys) then +** the seek is deferred until it is actually needed. It might be +** the case that the cursor is never accessed. By deferring the +** seek, we avoid unnecessary seeks. ** ** See also: Found, NotFound, Distinct, MoveLt, MoveGt, MoveLe */ /* Opcode: MoveGt P1 P2 P3 * * ** ** Use the value in register P3 as a key. Reposition ** cursor P1 so that it points to the smallest entry that is greater ** than the key in register P3. -** If there are no records greater than the key and P2 is not zero, +** If there are no records greater than the key ** then jump to P2. ** ** See also: Found, NotFound, Distinct, MoveLt, MoveGe, MoveLe */ /* Opcode: MoveLt P1 P2 P3 * * ** ** Use the value in register P3 as a key. Reposition ** cursor P1 so that it points to the largest entry that is less ** than the key in register P3. -** If there are no records less than the key and P2 is not zero, +** If there are no records less than the key ** then jump to P2. ** ** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLe */ /* Opcode: MoveLe P1 P2 P3 * * ** ** Use the value in register P3 as a key. Reposition ** cursor P1 so that it points to the largest entry that is less than ** or equal to the key. -** If there are no records less than or eqal to the key and P2 is not zero, +** If there are no records less than or eqal to the key ** then jump to P2. ** ** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt */ case OP_MoveLt: /* jump, in3 */ @@ -2744,12 +2751,14 @@ oc = pOp->opcode; pC->nullRow = 0; *pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe; if( pC->isTable ){ i64 iKey = sqlite3VdbeIntValue(pIn3); - if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){ + if( pOp->p2==0 ){ + assert( pOp->opcode==OP_MoveGe ); pC->movetoTarget = iKey; + pC->rowidIsValid = 0; pC->deferredMoveto = 1; break; } rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, 0, &res); if( rc!=SQLITE_OK ){ @@ -2791,16 +2800,13 @@ ** see if this is the case. */ res = sqlite3BtreeEof(pC->pCursor); } } + assert( pOp->p2>0 ); if( res ){ - if( pOp->p2>0 ){ - pc = pOp->p2 - 1; - }else{ - pC->nullRow = 1; - } + pc = pOp->p2 - 1; } } break; } @@ -3004,11 +3010,11 @@ ** the following jump is taken. (In other words, do not stress over ** the error that valgrind sometimes shows on the next statement when ** running ioerr.test and similar failure-recovery test scripts.) */ if( res!=0 ){ pc = pOp->p2 - 1; - pC->rowidIsValid = 0; + assert( pC->rowidIsValid==0 ); } } break; } @@ -3154,23 +3160,21 @@ if( pC->useRandomRowid ){ assert( pOp->p3==0 ); /* SQLITE_FULL must have occurred prior to this */ v = db->priorNewRowid; cnt = 0; do{ - if( v==0 || cnt>2 ){ + if( cnt==0 && (v&0xffffff)==v ){ + v++; + }else{ sqlite3Randomness(sizeof(v), &v); if( cnt<5 ) v &= 0xffffff; - }else{ - unsigned char r; - sqlite3Randomness(1, &r); - v += r + 1; } if( v==0 ) continue; x = intToKey(v); rx = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)x, 0, &res); cnt++; - }while( cnt<1000 && rx==SQLITE_OK && res==0 ); + }while( cnt<100 && rx==SQLITE_OK && res==0 ); db->priorNewRowid = v; if( rx==SQLITE_OK && res==0 ){ rc = SQLITE_FULL; goto abort_due_to_error; } @@ -3292,50 +3296,49 @@ ** a record from within an Next loop. ** ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is ** incremented (otherwise not). ** -** If P1 is a pseudo-table, then this instruction is a no-op. +** P1 must not be pseudo-table. It has to be a real table with +** multiple rows. +** +** If P4 is not NULL, then it is the name of the table that P1 is +** pointing to. The update hook will be invoked, if it exists. +** If P4 is not NULL then the P1 cursor must have been positioned +** using OP_NotFound prior to invoking this opcode. */ case OP_Delete: { int i = pOp->p1; + i64 iKey; Cursor *pC; + assert( i>=0 && inCursor ); pC = p->apCsr[i]; assert( pC!=0 ); - if( pC->pCursor!=0 ){ - i64 iKey; - - /* If the update-hook will be invoked, set iKey to the rowid of the - ** row being deleted. - */ - if( db->xUpdateCallback && pOp->p4.z ){ - assert( pC->isTable ); - if( pC->rowidIsValid ){ - iKey = pC->lastRowid; - }else{ - rc = sqlite3BtreeKeySize(pC->pCursor, &iKey); - if( rc ){ - goto abort_due_to_error; - } - iKey = keyToInt(iKey); - } - } - - rc = sqlite3VdbeCursorMoveto(pC); - if( rc ) goto abort_due_to_error; - rc = sqlite3BtreeDelete(pC->pCursor); - pC->nextRowidValid = 0; - pC->cacheStatus = CACHE_STALE; - - /* Invoke the update-hook if required. */ - if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){ - const char *zDb = db->aDb[pC->iDb].zName; - const char *zTbl = pOp->p4.z; - db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey); - assert( pC->iDb>=0 ); - } + assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */ + + /* If the update-hook will be invoked, set iKey to the rowid of the + ** row being deleted. + */ + if( db->xUpdateCallback && pOp->p4.z ){ + assert( pC->isTable ); + assert( pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */ + iKey = pC->lastRowid; + } + + rc = sqlite3VdbeCursorMoveto(pC); + if( rc ) goto abort_due_to_error; + rc = sqlite3BtreeDelete(pC->pCursor); + pC->nextRowidValid = 0; + pC->cacheStatus = CACHE_STALE; + + /* Invoke the update-hook if required. */ + if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){ + const char *zDb = db->aDb[pC->iDb].zName; + const char *zTbl = pOp->p4.z; + db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey); + assert( pC->iDb>=0 ); } if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; break; } @@ -4711,14 +4714,23 @@ } break; } #endif -/* An other opcode is illegal... + +/* Opcode: Noop * * * * * +** +** Do nothing. This instruction is often useful as a jump +** destination. +*/ +/* +** The magic Explain opcode are only inserted when explain==2 (which +** is to say when the EXPLAIN QUERY PLAN syntax is used.) +** This opcode records information from the optimizer. It is the +** the same as a no-op. This opcodesnever appears in a real VM program. */ -default: { - assert( 0 ); +default: { /* This is really OP_Noop and OP_Explain */ break; } /***************************************************************************** ** The cases of the switch statement above this line should all be indented Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -509,18 +509,20 @@ ** ** If addr<0 then change P4 on the most recently inserted instruction. */ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ Op *pOp; - assert( p==0 || p->magic==VDBE_MAGIC_INIT ); - if( p==0 || p->aOp==0 || p->db->mallocFailed ){ + assert( p!=0 ); + assert( p->magic==VDBE_MAGIC_INIT ); + if( p->aOp==0 || p->db->mallocFailed ){ if (n != P4_KEYINFO) { freeP4(n, (void*)*(char**)&zP4); } return; } - if( addr<0 || addr>=p->nOp ){ + assert( addrnOp ); + if( addr<0 ){ addr = p->nOp - 1; if( addr<0 ) return; } pOp = &p->aOp[addr]; freeP4(pOp->p4type, pOp->p4.p); @@ -538,17 +540,23 @@ nField = ((KeyInfo*)zP4)->nField; nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField; pKeyInfo = sqlite3_malloc( nByte ); pOp->p4.pKeyInfo = pKeyInfo; if( pKeyInfo ){ - unsigned char *aSortOrder; memcpy(pKeyInfo, zP4, nByte); + /* In the current implementation, P4_KEYINFO is only ever used on + ** KeyInfo structures that have no aSortOrder component. Elements + ** with an aSortOrder always use P4_KEYINFO_HANDOFF. So we do not + ** need to bother with duplicating the aSortOrder. */ + assert( pKeyInfo->aSortOrder==0 ); +#if 0 aSortOrder = pKeyInfo->aSortOrder; if( aSortOrder ){ pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField]; memcpy(pKeyInfo->aSortOrder, aSortOrder, nField); } +#endif pOp->p4type = P4_KEYINFO; }else{ p->db->mallocFailed = 1; pOp->p4type = P4_NOTUSED; } Index: src/where.c ================================================================== --- src/where.c +++ src/where.c @@ -14,11 +14,11 @@ ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.283 2008/01/17 16:22:15 drh Exp $ +** $Id: where.c,v 1.284 2008/01/19 20:11:26 drh Exp $ */ #include "sqliteInt.h" /* ** The number of bits in a Bitmask. "BMS" means "BitMask Size". @@ -2554,11 +2554,11 @@ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1); sqlite3VdbeAddOp2(v, OP_IsNull, r1, cont); } if( !omitTable ){ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1); - sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); + sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); /* Deferred seek */ } sqlite3ReleaseTempReg(pParse, r1); /* Record the instruction used to terminate the loop. */ @@ -2629,11 +2629,11 @@ pLevel->op = OP_Next; } if( !omitTable ){ r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1); - sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); + sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); /* Deferred seek */ sqlite3ReleaseTempReg(pParse, r1); } pLevel->p1 = iIdxCur; pLevel->p2 = start; }else{ Index: test/all.test ================================================================== --- test/all.test +++ test/all.test @@ -8,11 +8,11 @@ # May you share freely, never taking more than you give. # #*********************************************************************** # This file runs all tests. # -# $Id: all.test,v 1.52 2007/11/27 14:46:42 drh Exp $ +# $Id: all.test,v 1.53 2008/01/19 20:11:26 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl rename finish_test really_finish_test proc finish_test {} { @@ -90,10 +90,11 @@ } foreach testfile [lsort -dictionary [glob $testdir/*.test]] { set tail [file tail $testfile] if {[lsearch -exact $EXCLUDE $tail]>=0} continue if {[llength $INCLUDE]>0 && [lsearch -exact $INCLUDE $tail]<0} continue + reset_prng_state source $testfile catch {db close} if {$sqlite_open_file_count>0} { puts "$tail did not close all files: $sqlite_open_file_count" incr nErr Index: test/cast.test ================================================================== --- test/cast.test +++ test/cast.test @@ -9,11 +9,11 @@ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CAST operator. # -# $Id: cast.test,v 1.8 2007/08/13 15:18:28 drh Exp $ +# $Id: cast.test,v 1.9 2008/01/19 20:11:26 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if the build includes the CAST operator @@ -180,10 +180,42 @@ execsql {SELECT CAST('123.5abc' AS numeric)} } 123.5 do_test cast-1.53 { execsql {SELECT CAST('123.5abc' AS integer)} } 123 + +do_test case-1.60 { + execsql {SELECT CAST(null AS REAL)} +} {{}} +do_test case-1.61 { + execsql {SELECT typeof(CAST(null AS REAL))} +} {null} +do_test case-1.62 { + execsql {SELECT CAST(1 AS REAL)} +} {1.0} +do_test case-1.63 { + execsql {SELECT typeof(CAST(1 AS REAL))} +} {real} +do_test case-1.64 { + execsql {SELECT CAST('1' AS REAL)} +} {1.0} +do_test case-1.65 { + execsql {SELECT typeof(CAST('1' AS REAL))} +} {real} +do_test case-1.66 { + execsql {SELECT CAST('abc' AS REAL)} +} {0.0} +do_test case-1.67 { + execsql {SELECT typeof(CAST('abc' AS REAL))} +} {real} +do_test case-1.68 { + execsql {SELECT CAST(x'31' AS REAL)} +} {1.0} +do_test case-1.69 { + execsql {SELECT typeof(CAST(x'31' AS REAL))} +} {real} + # Ticket #1662. Ignore leading spaces in numbers when casting. # do_test cast-2.1 { execsql {SELECT CAST(' 123' AS integer)} Index: test/expr.test ================================================================== --- test/expr.test +++ test/expr.test @@ -9,11 +9,11 @@ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing expressions. # -# $Id: expr.test,v 1.60 2008/01/16 18:20:42 danielk1977 Exp $ +# $Id: expr.test,v 1.61 2008/01/19 20:11:26 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table to work with. @@ -70,10 +70,11 @@ test_expr expr-1.42 {i1=1, i2=2} {i1|i2} {3} test_expr expr-1.42b {i1=1, i2=2} {4|2} {6} test_expr expr-1.43 {i1=1, i2=2} {i1&i2} {0} test_expr expr-1.43b {i1=1, i2=2} {4&5} {4} test_expr expr-1.44 {i1=1} {~i1} {-2} +test_expr expr-1.44b {i1=NULL} {~i1} {{}} test_expr expr-1.45 {i1=1, i2=3} {i1<>i2} {4} test_expr expr-1.47 {i1=9999999999, i2=8888888888} {i1i2} 1 @@ -139,10 +140,12 @@ test_expr expr-1.104 {i1=0} {(-9223372036854775808.0 % -1)} 0.0 test_expr expr-1.105 {i1=0} {(-9223372036854775808.0 / -1)>1} 1 test_expr expr-1.106 {i1=0} {(1<<63)/-1} -9223372036854775808 test_expr expr-1.107 {i1=0} {(1<<63)%-1} 0 +test_expr expr-1.108 {i1=0} {1%0} {{}} +test_expr expr-1.109 {i1=0} {1/0} {{}} test_expr expr-2.1 {r1=1.23, r2=2.34} {r1+r2} 3.57 test_expr expr-2.2 {r1=1.23, r2=2.34} {r1-r2} -1.11 test_expr expr-2.3 {r1=1.23, r2=2.34} {r1*r2} 2.8782 set tcl_precision 15 @@ -167,10 +170,12 @@ test_expr expr-2.22 {r1=1.23, r2=2.34} {min(r1,r2,r1+r2,r1-r2)} {-1.11} test_expr expr-2.23 {r1=1.23, r2=2.34} {max(r1,r2,r1+r2,r1-r2)} {3.57} test_expr expr-2.24 {r1=25.0, r2=11.0} {r1%r2} 3.0 test_expr expr-2.25 {r1=1.23, r2=NULL} {coalesce(r1+r2,99.0)} 99.0 test_expr expr-2.26 {r1=1e300, r2=1e300} {coalesce((r1*r2)*0.0,99.0)} 99.0 +test_expr expr-2.27 {r1=1.1, r2=0.0} {r1/r2} {{}} +test_expr expr-2.28 {r1=1.1, r2=0.0} {r1%r2} {{}} test_expr expr-3.1 {t1='abc', t2='xyz'} {t1