From c16a03b54b0cce0924640dd9673caaa166fdb710 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 15 Sep 2004 13:38:10 +0000 Subject: [PATCH] The callback on sqlite3_trace() is invoked the first time sqlite3_step() is called after sqlite3_prepare() or sqlite3_reset(). Ticket #900. (CVS 1960) FossilOrigin-Name: 0cc2f40e6afa157ead45140c4e28a9a33c469b73 --- manifest | 22 +++++++++++----------- manifest.uuid | 2 +- src/build.c | 8 ++++---- src/main.c | 36 +----------------------------------- src/vdbeapi.c | 24 ++++++++++++++++++++++++ src/vdbeaux.c | 10 ++++------ test/trace.test | 37 +++++++++++++++++++++++++++++++++++-- www/capi3ref.tcl | 10 ++++++---- 8 files changed, 86 insertions(+), 63 deletions(-) diff --git a/manifest b/manifest index 7c0ba93100..748e11cf13 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sthe\sencode/decode\sfrom\sthe\sversion\s3.0\ssource\stree.\s(CVS\s1959) -D 2004-09-13T13:46:01 +C The\scallback\son\ssqlite3_trace()\sis\sinvoked\sthe\sfirst\stime\ssqlite3_step()\nis\scalled\safter\ssqlite3_prepare()\sor\ssqlite3_reset().\s\sTicket\s#900.\s(CVS\s1960) +D 2004-09-15T13:38:11 F Makefile.in 9cdfc3af2647055085969968ca2394f24c3c6166 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -30,7 +30,7 @@ F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689 F src/auth.c 65408baa7e6621520882478dfa1e6b8c1d6c1850 F src/btree.c 470e00b08688f065c2e62a6dcd3fb18880e8e309 F src/btree.h 94dfec0a1722d33359b23e7e310f2b64ffedf029 -F src/build.c 662f4e56a64aacadc97c481492b08c842b9ec0f4 +F src/build.c c5ecf114af4ebc2963a03142b6bd6f2284ee35fc F src/date.c eb8d5fa1a6d5cfc09031c8852d10ff742a94b15b F src/delete.c e887f44aae1e33da1643df58abe86cd9cde45ad1 F src/expr.c 9130794d8c86af2cbf2b8cdc66f2158167fd15b1 @@ -39,7 +39,7 @@ F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/insert.c bfd21070c28dd94e58ae918260a6985d2b5e4477 F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b -F src/main.c ac302ed646bdb256b78c87385627b3142357eced +F src/main.c 82a952ef3e5f7bacaa1b20060d0588f8767a6774 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 F src/os.h d1780e0db95cad01f213d48da22ab490eb4fd345 F src/os_common.h cd7eb025fdab7dc91e0e97bf6310f1648205857f @@ -77,8 +77,8 @@ F src/vacuum.c 819a3f411cb8d2d714e55f0805e8c23a642dd7ba F src/vdbe.c b19de04c57b4136a8e0203d5e3b76dd82bded1b5 F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181 F src/vdbeInt.h e09362d6323a725de3c30b0cc381a691e86ed697 -F src/vdbeapi.c 20bf8901592c7f38e8aabb448a913327ab19f0a7 -F src/vdbeaux.c 066766b06836d6dbb8d7ad5d87b539f383e0f10d +F src/vdbeapi.c c7208bb89fc4efc605e20328099a540175e2dae6 +F src/vdbeaux.c 0fbc50cf7aed1ea30c89839ad316446b839cc645 F src/vdbemem.c ef9ac7d32acfe4bce5c5b408b1294c8d9e0cdb56 F src/where.c 12e214870c84546858ddb9f121165a1fbfce6811 F test/all.test 929bfa932b55e75c96fe2203f7650ba451c1862c @@ -175,7 +175,7 @@ F test/tester.tcl 1ff1170dd4203d87f572871080cdb64330dade99 F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35 F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c 97a830d53c24c42290501fdfba4a6e5bdd34748b -F test/trace.test 0ed72787440d97c6de6b6ecb4c022e6f78d5d94a +F test/trace.test b6fb0931e4ac802414977a09109c0b02ee446202 F test/trans.test 29645b344d2b9b6792793562b12340177ddd8f96 F test/trigger1.test dc015c410161f1a6109fd52638dfac852e2a34de F test/trigger2.test a5d06e6e8e1e773cfcb5aaa75ab381b2ff35de63 @@ -216,7 +216,7 @@ F www/arch2b.fig d22a2c9642d584b89d4088b1e51e2bb0f7c04bed F www/audit.tcl 90e09d580f79c7efec0c7d6f447b7ec5c2dce5c0 F www/c_interface.tcl 83b39203e1ded4c2dab97f42edf31279a308efcb F www/capi3.tcl 5c1cb163f4d2a54e2d0e22dcc399dd71245c8b89 -F www/capi3ref.tcl aa6ea82ea34ff71357300b8f1ab9fd8232a9eec8 +F www/capi3ref.tcl 893977e2b1c8ae47a441335bc124cdc6d5fdbe95 F www/changes.tcl 3641bc28b86b40c82d546727da45ea0f0aa9a9f4 F www/common.tcl f786e6be86fb2627ceb30e770e9efa83b9c67a3a F www/conflict.tcl fb8a2ba83746c7fdfd9e52fa7f6aaf5c422b8246 @@ -247,7 +247,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P dd62224ae8d1047db388acdc4b91eb56fb9e966a -R b72a839b56c08880706fc5af1e49a3b1 +P c1f1320be5ce0b6e52491577078ba2b939882fbd +R aecc6b7d054a0a0bc5b475a58b060454 U drh -Z 55b7cec5724fd9cc6c0ba5706bebd5ec +Z 08c3c5131edf3b7397865edadac24eb1 diff --git a/manifest.uuid b/manifest.uuid index 811697a2e5..2e629309fb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c1f1320be5ce0b6e52491577078ba2b939882fbd \ No newline at end of file +0cc2f40e6afa157ead45140c4e28a9a33c469b73 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 937b3264a5..26e20db8c4 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.252 2004/09/08 15:09:41 drh Exp $ +** $Id: build.c,v 1.253 2004/09/15 13:38:11 drh Exp $ */ #include "sqliteInt.h" #include @@ -81,13 +81,13 @@ void sqlite3FinishCoding(Parse *pParse){ sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto); } -#ifndef NDEBUG /* Add a No-op that contains the complete text of the compiled SQL ** statement as its P3 argument. This does not change the functionality - ** of the program. But it does make it easier to debug. + ** of the program. + ** + ** This is used to implement sqlite3_trace() functionality. */ sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql); -#endif } diff --git a/src/main.c b/src/main.c index 6d03eefe4f..195086f9ca 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.259 2004/09/06 17:24:13 drh Exp $ +** $Id: main.c,v 1.260 2004/09/15 13:38:11 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -981,40 +981,6 @@ int sqlite3_prepare( sParse.db = db; sqlite3RunParser(&sParse, zSql, &zErrMsg); - if( db->xTrace && !db->init.busy ){ - /* Trace only the statment that was compiled. - ** Make a copy of that part of the SQL string since zSQL is const - ** and we must pass a zero terminated string to the trace function - ** The copy is unnecessary if the tail pointer is pointing at the - ** beginning or end of the SQL string. - */ - if( sParse.zTail && sParse.zTail!=zSql && *sParse.zTail ){ - char *tmpSql = sqliteStrNDup(zSql, sParse.zTail - zSql); - if( tmpSql ){ - db->xTrace(db->pTraceArg, tmpSql); - sqliteFree(tmpSql); - }else{ - /* If a memory error occurred during the copy, - ** trace entire SQL string and fall through to the - ** sqlite3_malloc_failed test to report the error. - */ - db->xTrace(db->pTraceArg, zSql); - } - }else{ - db->xTrace(db->pTraceArg, zSql); - } - } - - /* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned - ** on in debugging mode. - */ -#ifdef SQLITE_DEBUG - if( (db->flags & SQLITE_SqlTrace)!=0 && sParse.zTail && sParse.zTail!=zSql ){ - sqlite3DebugPrintf("SQL-trace: %.*s\n", sParse.zTail - zSql, zSql); - } -#endif /* SQLITE_DEBUG */ - - if( sqlite3_malloc_failed ){ rc = SQLITE_NOMEM; sqlite3RollbackAll(db); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index f5abe0ee66..15d102f57c 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -150,6 +150,30 @@ int sqlite3_step(sqlite3_stmt *pStmt){ return SQLITE_MISUSE; } if( p->pc<0 ){ + /* Invoke the trace callback if there is one + */ + if( (db = p->db)->xTrace && !db->init.busy ){ + assert( p->nOp>0 ); + assert( p->aOp[p->nOp-1].opcode==OP_Noop ); + assert( p->aOp[p->nOp-1].p3!=0 ); + assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC ); + sqlite3SafetyOff(db); + db->xTrace(db->pTraceArg, p->aOp[p->nOp-1].p3); + if( sqlite3SafetyOn(db) ){ + p->rc = SQLITE_MISUSE; + return SQLITE_MISUSE; + } + } + + /* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned + ** on in debugging mode. + */ +#ifdef SQLITE_DEBUG + if( (db->flags & SQLITE_SqlTrace)!=0 ){ + sqlite3DebugPrintf("SQL-trace: %s\n", p->aOp[p->nOp-1].p3); + } +#endif /* SQLITE_DEBUG */ + db->activeVdbeCnt++; p->pc = 0; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 6c91ffefe2..c04c966c36 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -528,8 +528,8 @@ void sqlite3VdbePrintSql(Vdbe *p){ #ifdef SQLITE_DEBUG int nOp = p->nOp; VdbeOp *pOp; - if( nOp<2 ) return; - pOp = &p->aOp[nOp-2]; + if( nOp<1 ) return; + pOp = &p->aOp[nOp-1]; if( pOp->opcode==OP_Noop && pOp->p3!=0 ){ const char *z = pOp->p3; while( isspace(*(u8*)z) ) z++; @@ -559,11 +559,9 @@ void sqlite3VdbeMakeReady( assert( p!=0 ); assert( p->magic==VDBE_MAGIC_INIT ); - /* Add a HALT instruction to the very end of the program. + /* There should be at least one opcode. */ - if( p->nOp==0 || (p->aOp && p->aOp[p->nOp-1].opcode!=OP_Halt) ){ - sqlite3VdbeAddOp(p, OP_Halt, 0, 0); - } + assert( p->nOp>0 ); /* No instruction ever pushes more than a single element onto the ** stack. And the stack never grows on successive executions of the diff --git a/test/trace.test b/test/trace.test index 011917a3ae..38c6e9c9aa 100644 --- a/test/trace.test +++ b/test/trace.test @@ -12,7 +12,7 @@ # # This file implements tests for the "sqlite3_trace()" API. # -# $Id: trace.test,v 1.2 2004/06/30 02:35:51 danielk1977 Exp $ +# $Id: trace.test,v 1.3 2004/09/15 13:38:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -38,10 +38,43 @@ do_test trace-1.3 { } {1 2} do_test trace-1.4 { set ::stmtlist -} {{CREATE TABLE t1(a,b);} {INSERT INTO t1 VALUES(1,2);} {SELECT * FROM t1;} {}} +} {{CREATE TABLE t1(a,b);} {INSERT INTO t1 VALUES(1,2);} {SELECT * FROM t1;}} do_test trace-1.5 { db trace {} db trace } {} +# If we prepare a statement and execute it multiple times, the trace +# happens on each execution. +# +db close +set DB [sqlite3 db test.db] +do_test trace-2.1 { + set STMT [sqlite3_prepare $DB {INSERT INTO t1 VALUES(2,3)} -1 TAIL] + db trace trace_proc + proc trace_proc sql { + global TRACE_OUT + set TRACE_OUT $sql + } + set TRACE_OUT {} + sqlite3_step $STMT + set TRACE_OUT +} {INSERT INTO t1 VALUES(2,3)} +do_test trace-2.2 { + set TRACE_OUT {} + sqlite3_reset $STMT + set TRACE_OUT +} {} +do_test trace-2.3 { + sqlite3_step $STMT + set TRACE_OUT +} {INSERT INTO t1 VALUES(2,3)} +do_test trace-2.4 { + execsql {SELECT * FROM t1} +} {1 2 2 3 2 3} +do_test trace-2.5 { + set TRACE_OUT +} {SELECT * FROM t1} + + finish_test diff --git a/www/capi3ref.tcl b/www/capi3ref.tcl index df36e807c9..ed6cd2e44d 100644 --- a/www/capi3ref.tcl +++ b/www/capi3ref.tcl @@ -1,4 +1,4 @@ -set rcsid {$Id: capi3ref.tcl,v 1.11 2004/09/07 16:19:54 drh Exp $} +set rcsid {$Id: capi3ref.tcl,v 1.12 2004/09/15 13:38:11 drh Exp $} source common.tcl header {C/C++ Interface For SQLite Version 3} puts { @@ -1006,9 +1006,11 @@ int sqlite3_step(sqlite3_stmt*); api {} { void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); } { - Register a function that is called at every invocation of sqlite3_exec() - or sqlite3_prepare(). This function can be used (for example) to generate - a log file of all SQL executed against a database. This is frequently + Register a function that is called each time an SQL statement is evaluated. + The callback function is invoked on the first call to sqlite3_step() after + calls to sqlite3_prepare() or sqlite3_reset(). + This function can be used (for example) to generate + a log file of all SQL executed against a database. This can be useful when debugging an application that uses SQLite. }