]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Evaluate typeof(X) and length(Y) where X is any column and Y is a blob column
authordrh <drh@noemail.net>
Wed, 28 Mar 2012 01:34:47 +0000 (01:34 +0000)
committerdrh <drh@noemail.net>
Wed, 28 Mar 2012 01:34:47 +0000 (01:34 +0000)
without actually loading X and Y from disk.

FossilOrigin-Name: b899dbeb60752843287e2c6ad3577e1d00f0d587

manifest
manifest.uuid
src/delete.c
src/expr.c
src/func.c
src/select.c
src/sqliteInt.h
src/vdbe.c
src/where.c
test/func.test
test/pager1.test

index 87409f9e290e66364c2f79a93317aabe2a2dbc68..c78d6a8b74bb6af0b27ed788ae41d9c3f42a271d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Increase\sthe\sversion\snumber\sto\s3.7.12
-D 2012-03-25T17:25:38.638
+C Evaluate\stypeof(X)\sand\slength(Y)\swhere\sX\sis\sany\scolumn\sand\sY\sis\sa\sblob\scolumn\nwithout\sactually\sloading\sX\sand\sY\sfrom\sdisk.
+D 2012-03-28T01:34:47.425
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -133,11 +133,11 @@ F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33
 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
-F src/delete.c 51d32f0a9c880663e54ce309f52e40c325d5e112
-F src/expr.c 00675123e0beec98f999aa4594d2cbe1fec33c1b
+F src/delete.c 4c20ea4f6213b3bc1c6a510586864b679946e05e
+F src/expr.c 86711d201e6ee0e795571900edf20722d008e3ab
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
-F src/func.c e75f41c421f00762ab9da7dc8fb90af3972cf99f
+F src/func.c c6b3c94320253a35bda43fb69cc292618e3285d6
 F src/global.c 4cfdca5cb0edd33c4d021baec4ede958cb2c793b
 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
 F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
@@ -180,11 +180,11 @@ F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
 F src/resolve.c 3d3e80a98f203ac6b9329e9621e29eda85ddfd40
 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
-F src/select.c 44ccdcb5d2a1c48622c179b2d72167b716388581
+F src/select.c f6f141cb1ea13f1e6564d3e162700e4937baa2a1
 F src/shell.c 3179db5d4ff33d62d59a024dbfd2a116390ef7b0
 F src/sqlite.h.in 11a883919b0baf4ffaa7550cfeef99be613ec2bf
 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
-F src/sqliteInt.h e65429a6f19b41720561b9434b2192574a91cfa2
+F src/sqliteInt.h 3756ece33f1e7f8fe2adf8e523566825c809316e
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -240,7 +240,7 @@ F src/update.c d3076782c887c10e882996550345da9c4c9f9dea
 F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
 F src/util.c 4f6cfad661b2e3454b0cdd5b1b9d39a54942d0e3
 F src/vacuum.c bfd53f9bd20a8fdb70b0fa8e77182b866875c0d8
-F src/vdbe.c 32720e873ed0a23e6ee928b676cd995864b984d6
+F src/vdbe.c b91a9135fa4ecd73805cfda7b051dbcc155a0fb8
 F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb
 F src/vdbeInt.h 6ff4180a05683566a8835d12f7ec504b22932c82
 F src/vdbeapi.c 3662b6a468a2a4605a15dfab313baa6dff81ad91
@@ -253,7 +253,7 @@ F src/vtab.c ab90fb600a3f5e4b7c48d22a4cdb2d6b23239847
 F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146
 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
-F src/where.c 6baab5dfcf4472552c0346d04f6fd2f4f8539c78
+F src/where.c 44d78f5811594065ebbb5354da7f9e6b8b1306d6
 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
@@ -497,7 +497,7 @@ F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659
 F test/fts4aa.test 6e7f90420b837b2c685f3bcbe84c868492d40a68
 F test/fts4content.test 17b2360f7d1a9a7e5aa8022783f5c5731b6dfd4f
 F test/fts4langid.test 2081c357bb6f170f34ef8e08c6abb88002b95c69
-F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca
+F test/func.test 6966ad939b8fccc7d48d18e0c1fc8cd1a9f197e6
 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
 F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
 F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6
@@ -626,7 +626,7 @@ F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
 F test/null.test a8b09b8ed87852742343b33441a9240022108993
 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
 F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
-F test/pager1.test cf8f40cf77b5c4f762b1e8492390d61b46a81623
+F test/pager1.test eb6d64d2e148dc4bfc6420605bee3717e2d5f10c
 F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1
 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
 F test/pagerfault.test 452f2cc23e3bfcfa935f4442aec1da4fe1dc0442
@@ -993,7 +993,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
-P 30b8dd326d28c0c08543989e376011ea41773a7e
-R 9c26fe2aaab0d138abb3ef6a21a226f0
+P d95f9fb713c7ba4e570556d835fbd77e574afdea
+R 89de5eb864ab0dd31529150cd7eba40a
 U drh
-Z 54613266ba9e6cb2a27d5ad8392e74a5
+Z 999e726acb9e2120206bfa344ce7af80
index 5306c9df0b54310e36be8be55c692338d3299e33..e1ec8508a4d65ad80a82181dd2c4bfd853e3d7f9 100644 (file)
@@ -1 +1 @@
-d95f9fb713c7ba4e570556d835fbd77e574afdea
\ No newline at end of file
+b899dbeb60752843287e2c6ad3577e1d00f0d587
\ No newline at end of file
index f666b90c83523830f21b9116a41375578d910d70..eead4856b1479b687680c20d2781066eaf3405bc 100644 (file)
@@ -374,7 +374,7 @@ void sqlite3DeleteFrom(
         pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK
     );
     if( pWInfo==0 ) goto delete_from_cleanup;
-    regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid);
+    regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0);
     sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
     if( db->flags & SQLITE_CountRows ){
       sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
index 79dd8f49618d14bfa46cc78fb644797791dcb7b8..b76a8afe12655f08c712624cb08deada62ff8b58 100644 (file)
@@ -2032,15 +2032,6 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
   */
 #ifndef NDEBUG
   for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
-#if 0 /* This code wold remove the entry from the cache if it existed */
-    if( p->iReg && p->iTable==iTab && p->iColumn==iCol ){
-      cacheEntryClear(pParse, p);
-      p->iLevel = pParse->iCacheLevel;
-      p->iReg = iReg;
-      p->lru = pParse->iCacheCnt++;
-      return;
-    }
-#endif
     assert( p->iReg==0 || p->iTable!=iTab || p->iColumn!=iCol );
   }
 #endif
@@ -2175,7 +2166,8 @@ int sqlite3ExprCodeGetColumn(
   Table *pTab,     /* Description of the table we are reading from */
   int iColumn,     /* Index of the table column */
   int iTable,      /* The cursor pointing to the table */
-  int iReg         /* Store results here */
+  int iReg,        /* Store results here */
+  u8 p5            /* P5 value for OP_Column */
 ){
   Vdbe *v = pParse->pVdbe;
   int i;
@@ -2190,7 +2182,11 @@ int sqlite3ExprCodeGetColumn(
   }  
   assert( v!=0 );
   sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg);
-  sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
+  if( p5 ){
+    sqlite3VdbeChangeP5(v, p5);
+  }else{   
+    sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
+  }
   return iReg;
 }
 
@@ -2318,7 +2314,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
         inReg = pExpr->iColumn + pParse->ckBase;
       }else{
         inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
-                                 pExpr->iColumn, pExpr->iTable, target);
+                                 pExpr->iColumn, pExpr->iTable, target,
+                                 pExpr->op2);
       }
       break;
     }
@@ -2595,6 +2592,23 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
 
       if( pFarg ){
         r1 = sqlite3GetTempRange(pParse, nFarg);
+
+        /* For length() and typeof() functions with a column argument,
+        ** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG
+        ** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
+        ** loading.
+        */
+        if( (pDef->flags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
+          assert( nFarg==1 );
+          assert( pFarg->a[0].pExpr!=0 );
+          if( pFarg->a[0].pExpr->op==TK_COLUMN ){
+            assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
+            assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
+            testcase( pDef->flags==SQLITE_FUNC_LENGTH );
+            pFarg->a[0].pExpr->op2 = pDef->flags;
+          }
+        }
+
         sqlite3ExprCachePush(pParse);     /* Ticket 2ea2425d34be */
         sqlite3ExprCodeExprList(pParse, pFarg, r1, 1);
         sqlite3ExprCachePop(pParse, 1);   /* Ticket 2ea2425d34be */
index c66ad28aba5914eb25870176d8edbc94ba09e9d5..6ffc7184b0404568f44f183d0fad21c414d020e8 100644 (file)
@@ -1542,8 +1542,8 @@ void sqlite3RegisterGlobalFunctions(void){
     FUNCTION(max,               -1, 1, 1, minmaxFunc       ),
     FUNCTION(max,                0, 1, 1, 0                ),
     AGGREGATE(max,               1, 1, 1, minmaxStep,      minMaxFinalize ),
-    FUNCTION(typeof,             1, 0, 0, typeofFunc       ),
-    FUNCTION(length,             1, 0, 0, lengthFunc       ),
+    FUNCTION2(typeof,            1, 0, 0, typeofFunc,  SQLITE_FUNC_TYPEOF),
+    FUNCTION2(length,            1, 0, 0, lengthFunc,  SQLITE_FUNC_LENGTH),
     FUNCTION(substr,             2, 0, 0, substrFunc       ),
     FUNCTION(substr,             3, 0, 0, substrFunc       ),
     FUNCTION(abs,                1, 0, 0, absFunc          ),
@@ -1555,11 +1555,9 @@ void sqlite3RegisterGlobalFunctions(void){
     FUNCTION(lower,              1, 0, 0, lowerFunc        ),
     FUNCTION(coalesce,           1, 0, 0, 0                ),
     FUNCTION(coalesce,           0, 0, 0, 0                ),
-/*  FUNCTION(coalesce,          -1, 0, 0, ifnullFunc       ), */
-    {-1,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"coalesce",0,0},
+    FUNCTION2(coalesce,         -1, 0, 0, ifnullFunc,  SQLITE_FUNC_COALESCE),
     FUNCTION(hex,                1, 0, 0, hexFunc          ),
-/*  FUNCTION(ifnull,             2, 0, 0, ifnullFunc       ), */
-    {2,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"ifnull",0,0},
+    FUNCTION2(ifnull,            2, 0, 0, ifnullFunc,  SQLITE_FUNC_COALESCE),
     FUNCTION(random,             0, 0, 0, randomFunc       ),
     FUNCTION(randomblob,         1, 0, 0, randomBlob       ),
     FUNCTION(nullif,             2, 0, 1, nullifFunc       ),
index 3efe014d8b66a84a4c3949d4c40da633d31a8a50..c22501367239879fa93a4432ba52815770db4a73 100644 (file)
@@ -4228,7 +4228,7 @@ int sqlite3Select(
             int r2;
 
             r2 = sqlite3ExprCodeGetColumn(pParse, 
-                               pCol->pTab, pCol->iColumn, pCol->iTable, r1);
+                               pCol->pTab, pCol->iColumn, pCol->iTable, r1, 0);
             if( r1!=r2 ){
               sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
             }
index 15c3f302e2abb2cc9560cd1f64f950ddc5e5a6fc..deb576d2d79e8fb29bf323fadaf6cb2a1b24dce7 100644 (file)
@@ -1009,14 +1009,18 @@ struct FuncDestructor {
 };
 
 /*
-** Possible values for FuncDef.flags
+** Possible values for FuncDef.flags.  Note that the _LENGTH and _TYPEOF
+** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG.  There
+** are assert() statements in the code to verify this.
 */
 #define SQLITE_FUNC_LIKE     0x01 /* Candidate for the LIKE optimization */
 #define SQLITE_FUNC_CASE     0x02 /* Case-sensitive LIKE-type function */
 #define SQLITE_FUNC_EPHEM    0x04 /* Ephemeral.  Delete with VDBE */
 #define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */
-#define SQLITE_FUNC_COUNT    0x20 /* Built-in count(*) aggregate */
-#define SQLITE_FUNC_COALESCE 0x40 /* Built-in coalesce() or ifnull() function */
+#define SQLITE_FUNC_COUNT    0x10 /* Built-in count(*) aggregate */
+#define SQLITE_FUNC_COALESCE 0x20 /* Built-in coalesce() or ifnull() function */
+#define SQLITE_FUNC_LENGTH   0x40 /* Built-in length() function */
+#define SQLITE_FUNC_TYPEOF   0x80 /* Built-in typeof() function */
 
 /*
 ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -1044,7 +1048,10 @@ struct FuncDestructor {
 **     parameter.
 */
 #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
-  {nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
+  {nArg, SQLITE_UTF8, (bNC*SQLITE_FUNC_NEEDCOLL), \
+   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
+#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
+  {nArg, SQLITE_UTF8, (bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
    SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
 #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
   {nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
@@ -1667,6 +1674,7 @@ struct Expr {
   i16 iRightJoinTable;   /* If EP_FromJoin, the right table of the join */
   u8 flags2;             /* Second set of flags.  EP2_... */
   u8 op2;                /* If a TK_REGISTER, the original value of Expr.op */
+                         /* If TK_COLUMN, the value of p5 for OP_Column */
   AggInfo *pAggInfo;     /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
   Table *pTab;           /* Table for TK_COLUMN expressions. */
 #if SQLITE_MAX_EXPR_DEPTH>0
@@ -1689,7 +1697,7 @@ struct Expr {
 #define EP_FixedDest  0x0200  /* Result needed in a specific register */
 #define EP_IntValue   0x0400  /* Integer value contained in u.iValue */
 #define EP_xIsSelect  0x0800  /* x.pSelect is valid (otherwise x.pList is) */
-#define EP_Hint       0x1000  /* Optimizer hint. Not required for correctness */
+#define EP_Hint       0x1000  /* Not used */
 #define EP_Reduced    0x2000  /* Expr struct is EXPR_REDUCEDSIZE bytes only */
 #define EP_TokenOnly  0x4000  /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
 #define EP_Static     0x8000  /* Held in memory not obtained from malloc() */
@@ -2276,7 +2284,7 @@ struct AuthContext {
 };
 
 /*
-** Bitfield flags for P5 value in OP_Insert and OP_Delete
+** Bitfield flags for P5 value in various opcodes.
 */
 #define OPFLAG_NCHANGE       0x01    /* Set to update db->nChange */
 #define OPFLAG_LASTROWID     0x02    /* Set to update db->lastRowid */
@@ -2284,6 +2292,8 @@ struct AuthContext {
 #define OPFLAG_APPEND        0x08    /* This is likely to be an append */
 #define OPFLAG_USESEEKRESULT 0x10    /* Try to avoid a seek in BtreeInsert() */
 #define OPFLAG_CLEARCACHE    0x20    /* Clear pseudo-table cache in OP_Column */
+#define OPFLAG_LENGTHARG     0x40    /* OP_Column only used for length() */
+#define OPFLAG_TYPEOFARG     0x80    /* OP_Column only used for typeof() */
 
 /*
  * Each trigger present in the database schema is stored as an instance of
@@ -2767,7 +2777,7 @@ void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
 void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
 WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**,ExprList*,u16);
 void sqlite3WhereEnd(WhereInfo*);
-int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
+int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
 void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
 void sqlite3ExprCodeMove(Parse*, int, int, int);
 void sqlite3ExprCodeCopy(Parse*, int, int, int);
index 749830bc0da2cf32f8881e087c609d0a86253455..93032936ae85e6ff2774cb4ccabed60920c55e81 100644 (file)
@@ -2127,6 +2127,11 @@ case OP_NotNull: {            /* same as TK_NOTNULL, jump, in1 */
 ** then the cache of the cursor is reset prior to extracting the column.
 ** The first OP_Column against a pseudo-table after the value of the content
 ** register has changed should have this bit set.
+**
+** If the OPFLAG_LENGTHARG bit is set on P5 then the result is guaranteed
+** to only be used as the argument of a length() or typeof() function and
+** so loading of large blobs and strings can be skipped - all that is necessary
+** is that the size and type information be set.
 */
 case OP_Column: {
   u32 payloadSize;   /* Number of bytes in the record */
@@ -2380,12 +2385,24 @@ case OP_Column: {
       sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest);
     }else{
       len = sqlite3VdbeSerialTypeLen(aType[p2]);
-      sqlite3VdbeMemMove(&sMem, pDest);
-      rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex, &sMem);
-      if( rc!=SQLITE_OK ){
-        goto op_column_out;
+      if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
+       && (((t = aType[p2])>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
+      ){
+        /* Content is irrelevant for the typeof() function and for
+        ** the length(x) function is x is a blob.  So we might as well use
+        ** bogus content rather than reading content from disk.  NULL works
+        ** for text and blob and whatever is in the payloadSize64 variable
+        ** will work for everything else. */
+        zData = t<12 ? (char*)&payloadSize64 : 0;
+      }else{
+        sqlite3VdbeMemMove(&sMem, pDest);
+        rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len,  pC->isIndex,
+                                     &sMem);
+        if( rc!=SQLITE_OK ){
+          goto op_column_out;
+        }
+        zData = sMem.z;
       }
-      zData = sMem.z;
       sqlite3VdbeSerialGet((u8*)zData, aType[p2], pDest);
     }
     pDest->enc = encoding;
index e6083f0033e8885eeed3b01ce098b4c23b29fc6d..2f3dc77e127338eda7fb630ae33fc7ea91fc0a5b 100644 (file)
@@ -4383,7 +4383,7 @@ static Bitmask codeOneLoopStart(
             int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
             int r;
             r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur, 
-                                         regRowid);
+                                         regRowid, 0);
             sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset,
                                  sqlite3VdbeCurrentAddr(v)+2, r, iSet);
           }
index eef05439861b81e924aaaedf5e048284d7bcac17..37631a419fa6ec30bb8bcb6121fb356dc282d129 100644 (file)
@@ -1247,4 +1247,37 @@ do_test func-28.1 {
   }
 } {1 {unknown function: nosuchfunc()}}
 
+# Verify that the length() and typeof() functions do not actually load
+# the content of their argument.
+#
+do_test func-29.1 {
+  db eval {
+    CREATE TABLE t29(id INTEGER PRIMARY KEY, x, y);
+    INSERT INTO t29 VALUES(1, 2, 3), (2, NULL, 4), (3, 4.5, 5);
+    INSERT INTO t29 VALUES(4, randomblob(1000000), 6);
+    INSERT INTO t29 VALUES(5, "hello", 7);
+  }
+  db close
+  sqlite3 db test.db
+  sqlite3_db_status db CACHE_MISS 1
+  db eval {SELECT typeof(x), length(x), typeof(y) FROM t29 ORDER BY id}
+} {integer 1 integer null {} integer real 3 integer blob 1000000 integer text 5 integer}
+do_test func-29.2 {
+  set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1]
+  if {$x<5} {set x 1}
+  set x
+} {1}
+do_test func-29.3 {
+  db close
+  sqlite3 db test.db
+  sqlite3_db_status db CACHE_MISS 1
+  db eval {SELECT typeof(+x) FROM t29 ORDER BY id}
+} {integer null real blob text}
+do_test func-29.4 {
+  set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1]
+  if {$x>100} {set x many}
+  set x
+} {many}
+  
+
 finish_test
index 45253857c3fc42d4204762967793662204338f3f..2ac56dec8ce46dd1c5316ce2b89b5146aa46c6f4 100644 (file)
@@ -1768,7 +1768,7 @@ do_test pager1-18.2 {
   catchsql { SELECT count(*) FROM t1 } db2
 } {1 {database disk image is malformed}}
 db2 close
-do_test pager1-18.3 {
+do_test pager1-18.3.1 {
   execsql {
     CREATE TABLE t2(x);
     INSERT INTO t2 VALUES(a_string(5000));
@@ -1776,13 +1776,38 @@ do_test pager1-18.3 {
   set pgno [expr ([file size test.db] / 1024)-2]
   hexio_write test.db [expr ($pgno-1)*1024] 00000000
   sqlite3 db2 test.db
-  catchsql { SELECT length(x) FROM t2 } db2
+  # even though x is malformed, because typeof() does
+  # not load the content of x, the error is not noticed.
+  catchsql { SELECT typeof(x) FROM t2 } db2
+} {0 text}
+do_test pager1-18.3.2 {
+  # in this case, the value of x is loaded and so the error is
+  # detected
+  catchsql { SELECT length(x||'') FROM t2 } db2
+} {1 {database disk image is malformed}}
+db2 close
+do_test pager1-18.3.3 {
+  execsql {
+    DELETE FROM t2;
+    INSERT INTO t2 VALUES(randomblob(5000));
+  }
+  set pgno [expr ([file size test.db] / 1024)-2]
+  hexio_write test.db [expr ($pgno-1)*1024] 00000000
+  sqlite3 db2 test.db
+  # even though x is malformed, because length() and typeof() do
+  # not load the content of x, the error is not noticed.
+  catchsql { SELECT length(x), typeof(x) FROM t2 } db2
+} {0 {5000 blob}}
+do_test pager1-18.3.4 {
+  # in this case, the value of x is loaded and so the error is
+  # detected
+  catchsql { SELECT length(x||'') FROM t2 } db2
 } {1 {database disk image is malformed}}
 db2 close
 do_test pager1-18.4 {
   hexio_write test.db [expr ($pgno-1)*1024] 90000000
   sqlite3 db2 test.db
-  catchsql { SELECT length(x) FROM t2 } db2
+  catchsql { SELECT length(x||'') FROM t2 } db2
 } {1 {database disk image is malformed}}
 db2 close
 do_test pager1-18.5 {