]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Modify the trace callback mechanism so that SQL commands executed from within virtual...
authordan <dan@noemail.net>
Sat, 22 Jan 2011 13:32:29 +0000 (13:32 +0000)
committerdan <dan@noemail.net>
Sat, 22 Jan 2011 13:32:29 +0000 (13:32 +0000)
FossilOrigin-Name: a764915b87564fa91ee68e9b1f41394ce0f1fc7e

install-sh [changed mode: 0644->0755]
manifest
manifest.uuid
src/sqliteInt.h
src/vdbeapi.c
src/vdbetrace.c
test/trace2.test [new file with mode: 0644]

old mode 100644 (file)
new mode 100755 (executable)
index 5dfc84f214fb603391dd90a37c7f73ad5a8841cb..61daaed0f0110312958624354380980df7d44443 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Change\ssqlite3StrAccumAppend()\sto\suse\srealloc\sinstead\sof\smalloc.
-D 2011-01-21T18:25:30
+C Modify\sthe\strace\scallback\smechanism\sso\sthat\sSQL\scommands\sexecuted\sfrom\swithin\svirtual\stable\sor\suser\sfunction\scallbacks\sare\spassed\sto\sthe\strace\scallback\swithout\sparameter\sexpansion\sand\senclosed\sin\sSQL\scomments.
+D 2011-01-22T13:32:30
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in de6498556d536ae60bb8bb10e8c1ba011448658c
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -97,7 +97,7 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
 F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
-F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
+F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
 F main.mk 05d0f3475dd331896bd607cfb45c5e21b94589ad
 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
@@ -178,7 +178,7 @@ F src/select.c 8a7ba246b0b4bb45df7fbc52681728a0e3deaaa7
 F src/shell.c 83c6f0cc5a79a081c7b9ddfe4f557b47e0bad976
 F src/sqlite.h.in 45ae5d463b5b341420b3cbc236fb1dfb5c0cd1a8
 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
-F src/sqliteInt.h 3ef5fc89a4c9755a08a68de107493785a284e27c
+F src/sqliteInt.h 45926deaf59b1ce3f55d21d5f91a8cecb6a7eb4c
 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
 F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -231,11 +231,11 @@ F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f
 F src/vdbe.c 5d310eaf1a4d8383602126fa82e01291ab7d3cf3
 F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
 F src/vdbeInt.h 6e6f28e9bccc6c703dca1372fd661c57b5c15fb0
-F src/vdbeapi.c 69c82283ab2b64c0c37a07799d771d4058330743
+F src/vdbeapi.c 8e9324fd35eb70d0b5904bd1af40f2598744dc4d
 F src/vdbeaux.c 33448d23b857654dd69ed2103611f5c733606f68
 F src/vdbeblob.c 18955f0ee6b133cd08e1592010cb9a6b11e9984c
 F src/vdbemem.c 411649a35686f54268ccabeda175322c4697f5a6
-F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
+F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
 F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
 F src/wal.c dbca424f71678f663a286ab2a98f947af1d412a7
 F src/wal.h c1aac6593a0b02b15dc625987e619edeab39292e
@@ -786,6 +786,7 @@ F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
 F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
 F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
 F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5
+F test/trace2.test 092bc2c5776272700450d60a36919921095bdc21
 F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
 F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22
 F test/trans3.test d728abaa318ca364dc370e06576aa7e5fbed7e97
@@ -896,7 +897,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 503ad889da675b3dd83da7338e2902e42f69acac
-R 581c91bca4bed9e9c246127dfff2a86d
+P 380f61df0754ceec6b3f6a758d04e951cce8c3d9
+R 90a5119ad79fbdf46155bfdda925f6c3
 U dan
-Z 1951ee9d42233f0fe4bd03e6cd0ae9e1
+Z 22ba801a4079136db1b6273b2820344e
index 37337becbb714b6eeb72b05b0770079a2de61917..302247b035f5bf23d1bd4eade381a0d1303432f8 100644 (file)
@@ -1 +1 @@
-380f61df0754ceec6b3f6a758d04e951cce8c3d9
\ No newline at end of file
+a764915b87564fa91ee68e9b1f41394ce0f1fc7e
\ No newline at end of file
index 5233e99f09116bb0fac01786d8838effdf02132d..41c46fa269c9de56a9f18c1ae68cc38a2edc2c43 100644 (file)
@@ -816,6 +816,7 @@ struct sqlite3 {
   struct Vdbe *pVdbe;           /* List of active virtual machines */
   int activeVdbeCnt;            /* Number of VDBEs currently executing */
   int writeVdbeCnt;             /* Number of active VDBEs that are writing */
+  int vdbeExecCnt;              /* Number of nested calls to VdbeExec() */
   void (*xTrace)(void*,const char*);        /* Trace function */
   void *pTraceArg;                          /* Argument to the trace function */
   void (*xProfile)(void*,const char*,u64);  /* Profiling function */
index ca454acc20c7a8b3270c0d8cd6de102ca8e141d9..5578b868e1e87f2c5c1942b1ebcc71aeeb49b8e6 100644 (file)
@@ -410,7 +410,9 @@ static int sqlite3Step(Vdbe *p){
   }else
 #endif /* SQLITE_OMIT_EXPLAIN */
   {
+    db->vdbeExecCnt++;
     rc = sqlite3VdbeExec(p);
+    db->vdbeExecCnt--;
   }
 
 #ifndef SQLITE_OMIT_TRACE
index 0d6b21211ce2e0394f5a35b1eb2969f5a322e612..b422fa9eb1002cffc000d660e730b870e6e70a18 100644 (file)
@@ -44,9 +44,12 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
 }
 
 /*
-** Return a pointer to a string in memory obtained form sqlite3DbMalloc() which
-** holds a copy of zRawSql but with host parameters expanded to their
-** current bindings.
+** This function returns a pointer to a nul-terminated string in memory
+** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the
+** string contains a copy of zRawSql but with host parameters expanded to 
+** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1, 
+** then the returned string holds a copy of zRawSql with "-- " prepended
+** to each line of text.
 **
 ** The calling function is responsible for making sure the memory returned
 ** is eventually freed.
@@ -77,63 +80,72 @@ char *sqlite3VdbeExpandSql(
   sqlite3StrAccumInit(&out, zBase, sizeof(zBase), 
                       db->aLimit[SQLITE_LIMIT_LENGTH]);
   out.db = db;
-  while( zRawSql[0] ){
-    n = findNextHostParameter(zRawSql, &nToken);
-    assert( n>0 );
-    sqlite3StrAccumAppend(&out, zRawSql, n);
-    zRawSql += n;
-    assert( zRawSql[0] || nToken==0 );
-    if( nToken==0 ) break;
-    if( zRawSql[0]=='?' ){
-      if( nToken>1 ){
-        assert( sqlite3Isdigit(zRawSql[1]) );
-        sqlite3GetInt32(&zRawSql[1], &idx);
+  if( db->vdbeExecCnt>1 ){
+    while( *zRawSql ){
+      const char *zStart = zRawSql;
+      while( *(zRawSql++)!='\n' && *zRawSql );
+      sqlite3StrAccumAppend(&out, "-- ", 3);
+      sqlite3StrAccumAppend(&out, zStart, zRawSql-zStart);
+    }
+  }else{
+    while( zRawSql[0] ){
+      n = findNextHostParameter(zRawSql, &nToken);
+      assert( n>0 );
+      sqlite3StrAccumAppend(&out, zRawSql, n);
+      zRawSql += n;
+      assert( zRawSql[0] || nToken==0 );
+      if( nToken==0 ) break;
+      if( zRawSql[0]=='?' ){
+        if( nToken>1 ){
+          assert( sqlite3Isdigit(zRawSql[1]) );
+          sqlite3GetInt32(&zRawSql[1], &idx);
+        }else{
+          idx = nextIndex;
+        }
       }else{
-        idx = nextIndex;
+        assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
+        testcase( zRawSql[0]==':' );
+        testcase( zRawSql[0]=='$' );
+        testcase( zRawSql[0]=='@' );
+        idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
+        assert( idx>0 );
       }
-    }else{
-      assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
-      testcase( zRawSql[0]==':' );
-      testcase( zRawSql[0]=='$' );
-      testcase( zRawSql[0]=='@' );
-      idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
-      assert( idx>0 );
-    }
-    zRawSql += nToken;
-    nextIndex = idx + 1;
-    assert( idx>0 && idx<=p->nVar );
-    pVar = &p->aVar[idx-1];
-    if( pVar->flags & MEM_Null ){
-      sqlite3StrAccumAppend(&out, "NULL", 4);
-    }else if( pVar->flags & MEM_Int ){
-      sqlite3XPrintf(&out, "%lld", pVar->u.i);
-    }else if( pVar->flags & MEM_Real ){
-      sqlite3XPrintf(&out, "%!.15g", pVar->r);
-    }else if( pVar->flags & MEM_Str ){
+      zRawSql += nToken;
+      nextIndex = idx + 1;
+      assert( idx>0 && idx<=p->nVar );
+      pVar = &p->aVar[idx-1];
+      if( pVar->flags & MEM_Null ){
+        sqlite3StrAccumAppend(&out, "NULL", 4);
+      }else if( pVar->flags & MEM_Int ){
+        sqlite3XPrintf(&out, "%lld", pVar->u.i);
+      }else if( pVar->flags & MEM_Real ){
+        sqlite3XPrintf(&out, "%!.15g", pVar->r);
+      }else if( pVar->flags & MEM_Str ){
 #ifndef SQLITE_OMIT_UTF16
-      u8 enc = ENC(db);
-      if( enc!=SQLITE_UTF8 ){
-        Mem utf8;
-        memset(&utf8, 0, sizeof(utf8));
-        utf8.db = db;
-        sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
-        sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
-        sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
-        sqlite3VdbeMemRelease(&utf8);
-      }else
+        u8 enc = ENC(db);
+        if( enc!=SQLITE_UTF8 ){
+          Mem utf8;
+          memset(&utf8, 0, sizeof(utf8));
+          utf8.db = db;
+          sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
+          sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
+          sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
+          sqlite3VdbeMemRelease(&utf8);
+        }else
 #endif
-      {
-        sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
-      }
-    }else if( pVar->flags & MEM_Zero ){
-      sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
-    }else{
-      assert( pVar->flags & MEM_Blob );
-      sqlite3StrAccumAppend(&out, "x'", 2);
-      for(i=0; i<pVar->n; i++){
-        sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
+        {
+          sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
+        }
+      }else if( pVar->flags & MEM_Zero ){
+        sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
+      }else{
+        assert( pVar->flags & MEM_Blob );
+        sqlite3StrAccumAppend(&out, "x'", 2);
+        for(i=0; i<pVar->n; i++){
+          sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
+        }
+        sqlite3StrAccumAppend(&out, "'", 1);
       }
-      sqlite3StrAccumAppend(&out, "'", 1);
     }
   }
   return sqlite3StrAccumFinish(&out);
diff --git a/test/trace2.test b/test/trace2.test
new file mode 100644 (file)
index 0000000..2cf50d0
--- /dev/null
@@ -0,0 +1,152 @@
+# 2011 Jan 21
+#
+# 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.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+# This file implements tests for the "sqlite3_trace()" API. Specifically,
+# it tests the special handling of nested SQL statements (those executed
+# by virtual table or user function callbacks). These statements are treated
+# differently in two respects:
+#
+#   1. Each line of the statement is prefixed with "-- " to turn it into
+#      an SQL comment.
+#
+#   2. Parameter expansion is not performed.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+ifcapable !trace { finish_test ; return }
+set ::testprefix trace2
+
+proc sql {zSql} { db one $zSql }
+proc trace {zSql} { lappend ::trace $zSql }
+
+db func sql sql
+db trace trace
+
+proc do_trace_test {tn sql expected} {
+  # Test that the list of string passed to the trace callback when $sql
+  # is executed is equivalent to the list of strings in $expected.
+  #
+  set ::trace [list]
+  execsql $sql
+  uplevel do_test $tn [list {set ::trace}] [list [list {*}$expected]]
+}
+
+proc do_trace_select_test {tn sql expected} {
+
+  uplevel [list do_trace_test ${tn}.a $sql $expected]
+
+  # Now execute each SQL statement passed to the trace callback in the
+  # block above. Check that this causes the same set of strings to be
+  # passed to the trace callback again. i.e. that executing the output
+  # of the trace callback is equivalent to the SQL script in $sql.
+  #
+  set sqllist $::trace
+  set ::trace [list]
+  foreach item $sqllist { execsql $item }
+  uplevel do_test $tn.b [list {set ::trace}] [list $sqllist]
+}
+
+do_trace_select_test 1.1  {
+  SELECT 1, 2, 3;
+} {
+  "SELECT 1, 2, 3;"
+}
+
+do_trace_select_test 1.2  {
+  SELECT sql('SELECT 1, 2, 3');
+} {
+  "SELECT sql('SELECT 1, 2, 3');"
+  "-- SELECT 1, 2, 3"
+}
+
+do_trace_select_test 1.3  {
+  SELECT sql('SELECT 1, 
+    2, 
+    3'
+  );
+} {
+  "SELECT sql('SELECT 1, 
+    2, 
+    3'
+  );"
+  "-- SELECT 1, 
+--     2, 
+--     3"
+}
+
+do_trace_select_test 1.4  {
+  SELECT sql('SELECT 1, 
+
+
+    3'
+  );
+} {
+  "SELECT sql('SELECT 1, 
+
+
+    3'
+  );"
+  "-- SELECT 1, 
+-- 
+-- 
+--     3"
+}
+
+do_trace_select_test 1.5  {
+  SELECT $var, sql('SELECT 1, 
+    $var, 
+    3'
+  );
+} {
+  "SELECT NULL, sql('SELECT 1, 
+    $var, 
+    3'
+  );"
+  "-- SELECT 1, 
+--     $var, 
+--     3"
+}
+
+ifcapable fts3 {
+  do_execsql_test 2.1 {
+    CREATE VIRTUAL TABLE x1 USING fts4;
+    INSERT INTO x1 VALUES('Cloudy, with a high near 16');
+    INSERT INTO x1 VALUES('Wind chill values as low as -13');
+  }
+
+  do_trace_test 2.2 {
+    INSERT INTO x1 VALUES('North northwest wind between 8 and 14 mph');
+  } {
+    "INSERT INTO x1 VALUES('North northwest wind between 8 and 14 mph');" 
+    "-- INSERT INTO 'main'.'x1_content' VALUES(?,?)" 
+    "-- REPLACE INTO 'main'.'x1_docsize' VALUES(?,?)" 
+    "-- SELECT value FROM 'main'.'x1_stat' WHERE id=0" 
+    "-- REPLACE INTO 'main'.'x1_stat' VALUES(0,?)" 
+    "-- SELECT (SELECT max(idx) FROM 'main'.'x1_segdir' WHERE level = ?) + 1" 
+    "-- SELECT coalesce((SELECT max(blockid) FROM 'main'.'x1_segments') + 1, 1)"
+    "-- INSERT INTO 'main'.'x1_segdir' VALUES(?,?,?,?,?,?)"
+  }
+
+  do_trace_test 2.3 {
+    INSERT INTO x1(x1) VALUES('optimize');
+  } {
+    "INSERT INTO x1(x1) VALUES('optimize');"
+    "-- SELECT count(*), max(level) FROM 'main'.'x1_segdir'"
+    "-- SELECT idx, start_block, leaves_end_block, end_block, root FROM 'main'.'x1_segdir' ORDER BY level DESC, idx ASC"
+    "-- SELECT coalesce((SELECT max(blockid) FROM 'main'.'x1_segments') + 1, 1)"
+    "-- DELETE FROM 'main'.'x1_segdir'"
+    "-- INSERT INTO 'main'.'x1_segdir' VALUES(?,?,?,?,?,?)"
+  }
+}
+
+finish_test