/ Check-in [110c000d]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:The sqlite3_trace() callback now prints a message as each trigger fires within a statement. (CVS 4709)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:110c000d86bd4a0b4b946c62d11a435426b02d16
User & Date: drh 2008-01-12 21:35:57
Context
2008-01-13
19:02
Fix some issues with out-of-memory recovery. (CVS 4710) check-in: 23181f86 user: drh tags: trunk
2008-01-12
21:35
The sqlite3_trace() callback now prints a message as each trigger fires within a statement. (CVS 4709) check-in: 110c000d user: drh tags: trunk
19:03
Continuing work toward converting the VM to a register machine. (CVS 4708) check-in: 426f31ec user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/build.c.

    18     18   **     CREATE INDEX
    19     19   **     DROP INDEX
    20     20   **     creating ID lists
    21     21   **     BEGIN TRANSACTION
    22     22   **     COMMIT
    23     23   **     ROLLBACK
    24     24   **
    25         -** $Id: build.c,v 1.464 2008/01/12 12:48:08 drh Exp $
           25  +** $Id: build.c,v 1.465 2008/01/12 21:35:57 drh Exp $
    26     26   */
    27     27   #include "sqliteInt.h"
    28     28   #include <ctype.h>
    29     29   
    30     30   /*
    31     31   ** This routine is called when a new SQL statement is beginning to
    32     32   ** be parsed.  Initialize the pParse structure as needed.
................................................................................
   180    180         ** shared-cache feature is enabled.
   181    181         */
   182    182         codeTableLocks(pParse);
   183    183         sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
   184    184       }
   185    185   
   186    186   #ifndef SQLITE_OMIT_TRACE
   187         -    /* Add a No-op that contains the complete text of the compiled SQL
   188         -    ** statement as its P4 argument.  This does not change the functionality
   189         -    ** of the program. 
   190         -    **
   191         -    ** This is used to implement sqlite3_trace().
   192         -    */
   193         -    sqlite3VdbeAddOp4(v, OP_Noop, 0, 0, 0,
   194         -                      pParse->zSql, pParse->zTail-pParse->zSql);
          187  +    if( !db->init.busy ){
          188  +      /* Change the P4 argument of the first opcode (which will always be
          189  +      ** an OP_Trace) to be the complete text of the current SQL statement.
          190  +      */
          191  +      VdbeOp *pOp = sqlite3VdbeGetOp(v, 0);
          192  +      if( pOp && pOp->opcode==OP_Trace ){
          193  +        sqlite3VdbeChangeP4(v, 0, pParse->zSql, pParse->zTail-pParse->zSql);
          194  +      }
          195  +    }
   195    196   #endif /* SQLITE_OMIT_TRACE */
   196    197     }
   197    198   
   198    199   
   199    200     /* Get the VDBE program ready for execution
   200    201     */
   201    202     if( v && pParse->nErr==0 && !db->mallocFailed ){

Changes to src/pragma.c.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains code used to implement the PRAGMA command.
    13     13   **
    14         -** $Id: pragma.c,v 1.165 2008/01/10 23:50:11 drh Exp $
           14  +** $Id: pragma.c,v 1.166 2008/01/12 21:35:57 drh Exp $
    15     15   */
    16     16   #include "sqliteInt.h"
    17     17   #include <ctype.h>
    18     18   
    19     19   /* Ignore this whole file if pragmas are disabled
    20     20   */
    21     21   #if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER)
................................................................................
   246    246     char *zLeft = 0;       /* Nul-terminated UTF-8 string <id> */
   247    247     char *zRight = 0;      /* Nul-terminated UTF-8 string <value>, or NULL */
   248    248     const char *zDb = 0;   /* The database name */
   249    249     Token *pId;            /* Pointer to <id> token */
   250    250     int iDb;               /* Database index for <database> */
   251    251     sqlite3 *db = pParse->db;
   252    252     Db *pDb;
   253         -  Vdbe *v = sqlite3GetVdbe(pParse);
          253  +  Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db);
   254    254     if( v==0 ) return;
   255    255     pParse->nMem = 1;
   256    256   
   257    257     /* Interpret the [database.] part of the pragma statement. iDb is the
   258    258     ** index of the database this pragma is being applied to in db.aDb[]. */
   259    259     iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
   260    260     if( iDb<0 ) return;

Changes to src/select.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle SELECT statements in SQLite.
    14     14   **
    15         -** $Id: select.c,v 1.399 2008/01/12 19:03:49 drh Exp $
           15  +** $Id: select.c,v 1.400 2008/01/12 21:35:57 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   
    20     20   /*
    21     21   ** Delete all the content of a Select structure but do not deallocate
    22     22   ** the select structure itself.
................................................................................
  1718   1718   ** Get a VDBE for the given parser context.  Create a new one if necessary.
  1719   1719   ** If an error occurs, return NULL and leave a message in pParse.
  1720   1720   */
  1721   1721   Vdbe *sqlite3GetVdbe(Parse *pParse){
  1722   1722     Vdbe *v = pParse->pVdbe;
  1723   1723     if( v==0 ){
  1724   1724       v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db);
         1725  +#ifndef SQLITE_OMIT_TRACE
         1726  +    if( v ){
         1727  +      sqlite3VdbeAddOp0(v, OP_Trace);
         1728  +    }
         1729  +#endif
  1725   1730     }
  1726   1731     return v;
  1727   1732   }
  1728   1733   
  1729   1734   
  1730   1735   /*
  1731   1736   ** Compute the iLimit and iOffset fields of the SELECT based on the

Changes to src/trigger.c.

   802    802    
   803    803       if( fire_this ){
   804    804         int endTrigger;
   805    805         Expr * whenExpr;
   806    806         AuthContext sContext;
   807    807         NameContext sNC;
   808    808   
          809  +#ifndef SQLITE_OMIT_TRACE
          810  +      sqlite3VdbeAddOp4(pParse->pVdbe, OP_Trace, 0, 0, 0,
          811  +                        sqlite3_mprintf("-- TRIGGER %s", p->name),
          812  +                        P4_DYNAMIC);
          813  +#endif
   809    814         memset(&sNC, 0, sizeof(sNC));
   810    815         sNC.pParse = pParse;
   811    816   
   812    817         /* Push an entry on to the trigger stack */
   813    818         trigStackEntry.pTrigger = p;
   814    819         trigStackEntry.newIdx = newIdx;
   815    820         trigStackEntry.oldIdx = oldIdx;

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.694 2008/01/12 19:03:49 drh Exp $
           46  +** $Id: vdbe.c,v 1.695 2008/01/12 21:35:57 drh Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include <ctype.h>
    50     50   #include "vdbeInt.h"
    51     51   
    52     52   /*
    53     53   ** The following global variable is incremented every time a cursor
................................................................................
  5054   5054         assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
  5055   5055         db->lastRowid = rowid;
  5056   5056       }
  5057   5057     }
  5058   5058     break;
  5059   5059   }
  5060   5060   #endif /* SQLITE_OMIT_VIRTUALTABLE */
         5061  +
         5062  +#ifndef SQLITE_OMIT_TRACE
         5063  +/* Opcode: Trace * * * P4 *
         5064  +**
         5065  +** If tracing is enabled (by the sqlite3_trace()) interface, then
         5066  +** the UTF-8 string contained in P4 is emitted on the trace callback.
         5067  +*/
         5068  +case OP_Trace: {
         5069  +  if( pOp->p4.z ){
         5070  +    if( db->xTrace ){
         5071  +      db->xTrace(db->pTraceArg, pOp->p4.z);
         5072  +    }
         5073  +#ifdef SQLITE_DEBUG
         5074  +    if( (db->flags & SQLITE_SqlTrace)!=0 ){
         5075  +      sqlite3DebugPrintf("SQL-trace: %s\n", pOp->p4.z);
         5076  +    }
         5077  +#endif /* SQLITE_DEBUG */
         5078  +  }
         5079  +  break;
         5080  +}
         5081  +#endif
  5061   5082   
  5062   5083   /* An other opcode is illegal...
  5063   5084   */
  5064   5085   default: {
  5065   5086     assert( 0 );
  5066   5087     break;
  5067   5088   }

Changes to src/vdbeapi.c.

   284    284       ** from interrupting a statement that has not yet started.
   285    285       */
   286    286       if( db->activeVdbeCnt==0 ){
   287    287         db->u1.isInterrupted = 0;
   288    288       }
   289    289   
   290    290   #ifndef SQLITE_OMIT_TRACE
   291         -    /* Invoke the trace callback if there is one
   292         -    */
   293         -    if( db->xTrace && !db->init.busy ){
   294         -      assert( p->nOp>0 );
   295         -      assert( p->aOp[p->nOp-1].opcode==OP_Noop );
   296         -      assert( p->aOp[p->nOp-1].p4.z!=0 );
   297         -      assert( p->aOp[p->nOp-1].p4type==P4_DYNAMIC );
   298         -      sqlite3SafetyOff(db);
   299         -      db->xTrace(db->pTraceArg, p->aOp[p->nOp-1].p4.z);
   300         -      if( sqlite3SafetyOn(db) ){
   301         -        p->rc = SQLITE_MISUSE;
   302         -        return SQLITE_MISUSE;
   303         -      }
   304         -    }
   305    291       if( db->xProfile && !db->init.busy ){
   306    292         double rNow;
   307    293         sqlite3OsCurrentTime(db->pVfs, &rNow);
   308    294         p->startTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0;
   309    295       }
   310    296   #endif
   311    297   
   312         -    /* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned
   313         -    ** on in debugging mode.
   314         -    */
   315         -#ifdef SQLITE_DEBUG
   316         -    if( (db->flags & SQLITE_SqlTrace)!=0 ){
   317         -      sqlite3DebugPrintf("SQL-trace: %s\n", p->aOp[p->nOp-1].p4.z);
   318         -    }
   319         -#endif /* SQLITE_DEBUG */
   320         -
   321    298       db->activeVdbeCnt++;
   322    299       p->pc = 0;
   323    300     }
   324    301   #ifndef SQLITE_OMIT_EXPLAIN
   325    302     if( p->explain ){
   326    303       rc = sqlite3VdbeList(p);
   327    304     }else
................................................................................
   333    310     if( sqlite3SafetyOff(db) ){
   334    311       rc = SQLITE_MISUSE;
   335    312     }
   336    313   
   337    314   #ifndef SQLITE_OMIT_TRACE
   338    315     /* Invoke the profile callback if there is one
   339    316     */
   340         -  if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy ){
          317  +  if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->nOp>0
          318  +           && p->aOp[0].opcode==OP_Trace && p->aOp[0].p4.z!=0 ){
   341    319       double rNow;
   342    320       u64 elapseTime;
   343    321   
   344    322       sqlite3OsCurrentTime(db->pVfs, &rNow);
   345    323       elapseTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0 - p->startTime;
   346         -    assert( p->nOp>0 );
   347         -    assert( p->aOp[p->nOp-1].opcode==OP_Noop );
   348         -    assert( p->aOp[p->nOp-1].p4.z!=0 );
   349         -    assert( p->aOp[p->nOp-1].p4type==P4_DYNAMIC );
   350         -    db->xProfile(db->pProfileArg, p->aOp[p->nOp-1].p4.z, elapseTime);
          324  +    db->xProfile(db->pProfileArg, p->aOp[0].p4.z, elapseTime);
   351    325     }
   352    326   #endif
   353    327   
   354    328     sqlite3Error(p->db, rc, 0);
   355    329     p->rc = sqlite3ApiExit(p->db, p->rc);
   356    330   end_of_step:
   357    331     assert( (rc&0xff)==rc );

Changes to src/vdbeaux.c.

   677    677         sqlite3_vtab *pVtab = pOp->p4.pVtab;
   678    678         sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
   679    679         break;
   680    680       }
   681    681   #endif
   682    682       default: {
   683    683         zP4 = pOp->p4.z;
   684         -      if( zP4==0 || pOp->opcode==OP_Noop ){
          684  +      if( zP4==0 ){
   685    685           zP4 = zTemp;
   686    686           zTemp[0] = 0;
   687    687         }
   688    688       }
   689    689     }
   690    690     assert( zP4!=0 );
   691    691     return zP4;
................................................................................
   850    850   /*
   851    851   ** Print the SQL that was used to generate a VDBE program.
   852    852   */
   853    853   void sqlite3VdbePrintSql(Vdbe *p){
   854    854     int nOp = p->nOp;
   855    855     VdbeOp *pOp;
   856    856     if( nOp<1 ) return;
   857         -  pOp = &p->aOp[nOp-1];
   858         -  if( pOp->opcode==OP_Noop && pOp->p4.z!=0 ){
          857  +  pOp = &p->aOp[0];
          858  +  if( pOp->opcode==OP_Trace && pOp->p4.z!=0 ){
   859    859       const char *z = pOp->p4.z;
   860    860       while( isspace(*(u8*)z) ) z++;
   861    861       printf("SQL: [%s]\n", z);
   862    862     }
   863    863   }
   864    864   #endif
   865    865   
................................................................................
   868    868   ** Print an IOTRACE message showing SQL content.
   869    869   */
   870    870   void sqlite3VdbeIOTraceSql(Vdbe *p){
   871    871     int nOp = p->nOp;
   872    872     VdbeOp *pOp;
   873    873     if( sqlite3_io_trace==0 ) return;
   874    874     if( nOp<1 ) return;
   875         -  pOp = &p->aOp[nOp-1];
   876         -  if( pOp->opcode==OP_Noop && pOp->p4.p!=0 ){
          875  +  pOp = &p->aOp[0];
          876  +  if( pOp->opcode==OP_Trace && pOp->p4.z!=0 ){
   877    877       int i, j;
   878    878       char z[1000];
   879         -    sqlite3_snprintf(sizeof(z), z, "%s", pOp->p4.p);
          879  +    sqlite3_snprintf(sizeof(z), z, "%s", pOp->p4.z);
   880    880       for(i=0; isspace((unsigned char)z[i]); i++){}
   881    881       for(j=0; z[i]; i++){
   882    882         if( isspace((unsigned char)z[i]) ){
   883    883           if( z[i-1]!=' ' ){
   884    884             z[j++] = ' ';
   885    885           }
   886    886         }else{

Changes to test/trace.test.

     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.
    12     12   #
    13     13   # This file implements tests for the "sqlite3_trace()" API.
    14     14   #
    15         -# $Id: trace.test,v 1.6 2006/01/03 00:33:50 drh Exp $
           15  +# $Id: trace.test,v 1.7 2008/01/12 21:35:57 drh Exp $
    16     16   
    17     17   set testdir [file dirname $argv0]
    18     18   source $testdir/tester.tcl
    19     19   
    20     20   ifcapable !trace {
    21     21     finish_test
    22     22     return
................................................................................
   141    141     execsql {SELECT * FROM t1}
   142    142   } {1 2 2 3 2 3}
   143    143   do_test trace-4.5 {
   144    144     set TRACE_OUT
   145    145   } {SELECT * FROM t1}
   146    146   catch {sqlite3_finalize $STMT}
   147    147   
          148  +# Trigger tracing.
          149  +#
          150  +do_test trace-5.1 {
          151  +  db eval {
          152  +    CREATE TRIGGER r1t1 AFTER UPDATE ON t1 BEGIN
          153  +      UPDATE t2 SET a=new.a WHERE rowid=new.rowid;
          154  +    END;
          155  +    CREATE TRIGGER r1t2 AFTER UPDATE ON t2 BEGIN
          156  +      SELECT 'hello';
          157  +    END;
          158  +  }
          159  +  set TRACE_OUT {}
          160  +  proc trace_proc cmd {
          161  +    lappend ::TRACE_OUT [string trim $cmd]
          162  +  }
          163  +  db eval {
          164  +    UPDATE t1 SET a=a+1;
          165  +  }
          166  +  set TRACE_OUT
          167  +} {{UPDATE t1 SET a=a+1;} {-- TRIGGER r1t1} {-- TRIGGER r1t2} {-- TRIGGER r1t1} {-- TRIGGER r1t2} {-- TRIGGER r1t1} {-- TRIGGER r1t2}}
          168  +
   148    169   finish_test