SQLite

Check-in [545cfb3b63]
Login

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

Overview
Comment:Initial check-in of code that inserts tokenizations of the values for bound parameters into the output of sqlite3_trace().
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 545cfb3b63f482036ae152e6ebcce86d373585a8
User & Date: drh 2009-11-25 18:03:43.000
Context
2009-11-25
19:35
Get trace with parameter insertion working for UTF16 databases. (check-in: 01d5451af0 user: drh tags: trunk)
18:03
Initial check-in of code that inserts tokenizations of the values for bound parameters into the output of sqlite3_trace(). (check-in: 545cfb3b63 user: drh tags: trunk)
16:53
Enhance the %q, %Q, and %w printf conversions so that the precisions specifies the length of the input. (check-in: 3ba773132d user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to Makefile.in.
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
        memjournal.lo \
        mutex.lo mutex_noop.lo mutex_os2.lo mutex_unix.lo mutex_w32.lo \
        notify.lo opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \
        pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
        random.lo resolve.lo rowset.lo select.lo status.lo \
        table.lo tokenize.lo trigger.lo update.lo \
        util.lo vacuum.lo \
        vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo \
        walker.lo where.lo utf.lo vtab.lo

# Object files for the amalgamation.
#
OBJS1 = sqlite3.lo

# Determine the real value of LIBOBJ based on the 'configure' script







|







171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
        memjournal.lo \
        mutex.lo mutex_noop.lo mutex_os2.lo mutex_unix.lo mutex_w32.lo \
        notify.lo opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \
        pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
        random.lo resolve.lo rowset.lo select.lo status.lo \
        table.lo tokenize.lo trigger.lo update.lo \
        util.lo vacuum.lo \
        vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbetrace.lo \
        walker.lo where.lo utf.lo vtab.lo

# Object files for the amalgamation.
#
OBJS1 = sqlite3.lo

# Determine the real value of LIBOBJ based on the 'configure' script
268
269
270
271
272
273
274

275
276
277
278
279
280
281
  $(TOP)/src/vacuum.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/vdbe.h \
  $(TOP)/src/vdbeapi.c \
  $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbeblob.c \
  $(TOP)/src/vdbemem.c \

  $(TOP)/src/vdbeInt.h \
  $(TOP)/src/vtab.c \
  $(TOP)/src/walker.c \
  $(TOP)/src/where.c

# Generated source code files
#







>







268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  $(TOP)/src/vacuum.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/vdbe.h \
  $(TOP)/src/vdbeapi.c \
  $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbeblob.c \
  $(TOP)/src/vdbemem.c \
  $(TOP)/src/vdbetrace.c \
  $(TOP)/src/vdbeInt.h \
  $(TOP)/src/vtab.c \
  $(TOP)/src/walker.c \
  $(TOP)/src/where.c

# Generated source code files
#
357
358
359
360
361
362
363

364
365
366
367
368
369
370
  $(TOP)/src/tokenize.c \
  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/vdbeapi.c \
  $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbemem.c \

  $(TOP)/src/where.c \
  parse.c

# Source code to the actual test files.
#
TESTSRC = \
  $(TOP)/src/test1.c \







>







358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
  $(TOP)/src/tokenize.c \
  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/vdbeapi.c \
  $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbemem.c \
  $(TOP)/src/vdbetrace.c \
  $(TOP)/src/where.c \
  parse.c

# Source code to the actual test files.
#
TESTSRC = \
  $(TOP)/src/test1.c \
725
726
727
728
729
730
731



732
733
734
735
736
737
738

vdbeblob.lo:	$(TOP)/src/vdbeblob.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbeblob.c

vdbemem.lo:	$(TOP)/src/vdbemem.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbemem.c




vtab.lo:	$(TOP)/src/vtab.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c

walker.lo:	$(TOP)/src/walker.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/walker.c

where.lo:	$(TOP)/src/where.c $(HDR)







>
>
>







727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743

vdbeblob.lo:	$(TOP)/src/vdbeblob.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbeblob.c

vdbemem.lo:	$(TOP)/src/vdbemem.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbemem.c

vdbetrace.lo:	$(TOP)/src/vdbetrace.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbetrace.c

vtab.lo:	$(TOP)/src/vtab.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c

walker.lo:	$(TOP)/src/walker.c $(HDR)
	$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/walker.c

where.lo:	$(TOP)/src/where.c $(HDR)
Changes to main.mk.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
         memjournal.o \
         mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \
         notify.o opcodes.o os.o os_os2.o os_unix.o os_win.o \
         pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \
         random.o resolve.o rowset.o rtree.o select.o status.o \
         table.o tokenize.o trigger.o \
         update.o util.o vacuum.o \
         vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o \
         walker.o where.o utf.o vtab.o



# All of the source code files.
#
SRC = \







|







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
         memjournal.o \
         mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \
         notify.o opcodes.o os.o os_os2.o os_unix.o os_win.o \
         pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \
         random.o resolve.o rowset.o rtree.o select.o status.o \
         table.o tokenize.o trigger.o \
         update.o util.o vacuum.o \
         vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbetrace.o \
         walker.o where.o utf.o vtab.o



# All of the source code files.
#
SRC = \
150
151
152
153
154
155
156

157
158
159
160
161
162
163
  $(TOP)/src/vacuum.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/vdbe.h \
  $(TOP)/src/vdbeapi.c \
  $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbeblob.c \
  $(TOP)/src/vdbemem.c \

  $(TOP)/src/vdbeInt.h \
  $(TOP)/src/vtab.c \
  $(TOP)/src/walker.c \
  $(TOP)/src/where.c

# Source code for extensions
#







>







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  $(TOP)/src/vacuum.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/vdbe.h \
  $(TOP)/src/vdbeapi.c \
  $(TOP)/src/vdbeaux.c \
  $(TOP)/src/vdbeblob.c \
  $(TOP)/src/vdbemem.c \
  $(TOP)/src/vdbetrace.c \
  $(TOP)/src/vdbeInt.h \
  $(TOP)/src/vtab.c \
  $(TOP)/src/walker.c \
  $(TOP)/src/where.c

# Source code for extensions
#
Changes to src/printf.c.
953
954
955
956
957
958
959












  sqlite3VXPrintf(&acc, 0, zFormat, ap);
  va_end(ap);
  sqlite3StrAccumFinish(&acc);
  fprintf(stdout,"%s", zBuf);
  fflush(stdout);
}
#endif



















>
>
>
>
>
>
>
>
>
>
>
>
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
  sqlite3VXPrintf(&acc, 0, zFormat, ap);
  va_end(ap);
  sqlite3StrAccumFinish(&acc);
  fprintf(stdout,"%s", zBuf);
  fflush(stdout);
}
#endif

#ifndef SQLITE_OMIT_TRACE
/*
** variable-argument wrapper around sqlite3VXPrintf().
*/
void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){
  va_list ap;
  va_start(ap,zFormat);
  sqlite3VXPrintf(p, 1, zFormat, ap);
  va_end(ap);
}
#endif
Changes to src/sqliteInt.h.
2513
2514
2515
2516
2517
2518
2519



2520
2521
2522
2523
2524
2525
2526
int sqlite3StatusValue(int);
void sqlite3StatusAdd(int, int);
void sqlite3StatusSet(int, int);

int sqlite3IsNaN(double);

void sqlite3VXPrintf(StrAccum*, int, const char*, va_list);



char *sqlite3MPrintf(sqlite3*,const char*, ...);
char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
char *sqlite3MAppendf(sqlite3*,char*,const char*,...);
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
  void sqlite3DebugPrintf(const char*, ...);
#endif
#if defined(SQLITE_TEST)







>
>
>







2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
int sqlite3StatusValue(int);
void sqlite3StatusAdd(int, int);
void sqlite3StatusSet(int, int);

int sqlite3IsNaN(double);

void sqlite3VXPrintf(StrAccum*, int, const char*, va_list);
#ifndef SQLITE_OMIT_TRACE
void sqlite3XPrintf(StrAccum*, const char*, ...);
#endif
char *sqlite3MPrintf(sqlite3*,const char*, ...);
char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
char *sqlite3MAppendf(sqlite3*,char*,const char*,...);
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
  void sqlite3DebugPrintf(const char*, ...);
#endif
#if defined(SQLITE_TEST)
Changes to src/vdbe.c.
5628
5629
5630
5631
5632
5633
5634

5635

5636
5637
5638
5639
5640
5641
5642
*/
case OP_Trace: {
  char *zTrace;

  zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
  if( zTrace ){
    if( db->xTrace ){

      db->xTrace(db->pTraceArg, zTrace);

    }
#ifdef SQLITE_DEBUG
    if( (db->flags & SQLITE_SqlTrace)!=0 ){
      sqlite3DebugPrintf("SQL-trace: %s\n", zTrace);
    }
#endif /* SQLITE_DEBUG */
  }







>
|
>







5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
*/
case OP_Trace: {
  char *zTrace;

  zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
  if( zTrace ){
    if( db->xTrace ){
      char *z = sqlite3VdbeExpandSql(p, zTrace);
      db->xTrace(db->pTraceArg, z);
      sqlite3DbFree(db, z);
    }
#ifdef SQLITE_DEBUG
    if( (db->flags & SQLITE_SqlTrace)!=0 ){
      sqlite3DebugPrintf("SQL-trace: %s\n", zTrace);
    }
#endif /* SQLITE_DEBUG */
  }
Changes to src/vdbe.h.
199
200
201
202
203
204
205



206
207
208
209
210
211
212
sqlite3 *sqlite3VdbeDb(Vdbe*);
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
void sqlite3VdbeProgramDelete(sqlite3 *, SubProgram *, int);
sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8);
void sqlite3VdbeSetVarmask(Vdbe*, int);




UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,char*,int);
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*);
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);


#ifndef NDEBUG







>
>
>







199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
sqlite3 *sqlite3VdbeDb(Vdbe*);
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
void sqlite3VdbeProgramDelete(sqlite3 *, SubProgram *, int);
sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8);
void sqlite3VdbeSetVarmask(Vdbe*, int);
#ifndef SQLITE_OMIT_TRACE
  char *sqlite3VdbeExpandSql(Vdbe*, const char*);
#endif

UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,char*,int);
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*);
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);


#ifndef NDEBUG
Added src/vdbetrace.c.








































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
** 2009 November 25
**
** 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 contains code used to insert the values of host parameters
** (aka "wildcards") into the SQL text output by sqlite3_trace().
*/
#include "sqliteInt.h"
#include "vdbeInt.h"

#ifndef SQLITE_OMIT_TRACE

/*
** zSql is a zero-terminated string of UTF-8 SQL text.  Return the number of
** bytes in this text up to but excluding the first character in
** a host parameter.  If the text contains no host parameters, return
** the total number of bytes in the text.
*/
static int findNextHostParameter(const char *zSql){
  int tokenType;
  int nTotal = 0;
  int n;

  while( zSql[0] ){
    n = sqlite3GetToken((u8*)zSql, &tokenType);
    assert( n>0 && tokenType!=TK_ILLEGAL );
    if( tokenType==TK_VARIABLE ) break;
    nTotal += n;
    zSql += n;
  }
  return nTotal;
}

/*
** Return a pointer to a string in memory obtained form sqlite3Malloc() which
** holds a copy of zRawSql but with host parameters expanded to their
** current values.
**
** The calling function is responsible for making sure the memory returned
** is eventually freed.
**
** ALGORITHM:  Scan the input string looking for host parameters in any of
** these forms:  ?, ?N, $A, @A, :A.  Take care to avoid text within
** string literals, quoted identifier names, and comments.  For text forms,
** the host parameter index is found by scanning the perpared
** statement for the corresponding OP_Variable opcode.  Once the host
** parameter index is known, locate the value in p->aVar[].  Then render
** the value as a literal in place of the host parameter name.
*/
char *sqlite3VdbeExpandSql(
  Vdbe *p,                 /* The prepared statement being evaluated */
  const char *zRawSql      /* Raw text of the SQL statement */
){
  sqlite3 *db;             /* The database connection */
  int idx;                 /* Index of a host parameter */
  int nextIndex = 1;       /* Index of next ? host parameter */
  int n;                   /* Length of a token prefix */
  int i;                   /* Loop counter */
  int dummy;               /* For holding a unused return value */
  Mem *pVar;               /* Value of a host parameter */
  VdbeOp *pOp;             /* For looping over opcodes */
  StrAccum out;            /* Accumulate the output here */
  char zBase[100];         /* Initial working space */

  db = p->db;
  sqlite3StrAccumInit(&out, zBase, sizeof(zBase), 
                      db->aLimit[SQLITE_LIMIT_LENGTH]);
  out.db = db;
  while( zRawSql[0] ){
    n = findNextHostParameter(zRawSql);
    assert( n>0 );
    sqlite3StrAccumAppend(&out, zRawSql, n);
    zRawSql += n;
    if( zRawSql[0]==0 ) break;
    if( zRawSql[0]=='?' ){
      zRawSql++;
      if( sqlite3Isdigit(zRawSql[0]) ){
        idx = 0;
        while( sqlite3Isdigit(zRawSql[0]) ){
          idx = idx*10 + zRawSql[0] - '0';
          zRawSql++;
        }
      }else{
        idx = nextIndex;
      }
    }else{
      assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
      n = sqlite3GetToken((u8*)zRawSql, &dummy);
      idx = 0;
      for(i=0, pOp=p->aOp; ALWAYS(i<p->nOp); i++, pOp++){
        if( pOp->opcode!=OP_Variable ) continue;
        if( pOp->p3>1 ) continue;
        if( memcmp(pOp->p4.z, zRawSql, n)==0 && pOp->p4.z[n]==0 ){
          idx = pOp->p1;
          break;
        }
      }
      assert( idx>0 );
      zRawSql += n;
    }
    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 ){
      sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
    }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);
    }
  }
  return sqlite3StrAccumFinish(&out);
}

#endif /* #ifndef SQLITE_OMIT_TRACE */
Changes to test/trace.test.
163
164
165
166
167
168
169
















170
171
    }
    db eval {
      UPDATE t1 SET a=a+1;
    }
    set TRACE_OUT
  } {{UPDATE t1 SET a=a+1;} {-- TRIGGER r1t1} {-- TRIGGER r1t2} {-- TRIGGER r1t1} {-- TRIGGER r1t2} {-- TRIGGER r1t1} {-- TRIGGER r1t2}}
}

















finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
    }
    db eval {
      UPDATE t1 SET a=a+1;
    }
    set TRACE_OUT
  } {{UPDATE t1 SET a=a+1;} {-- TRIGGER r1t1} {-- TRIGGER r1t2} {-- TRIGGER r1t1} {-- TRIGGER r1t2} {-- TRIGGER r1t1} {-- TRIGGER r1t2}}
}

# With 3.6.21, we add the ability to expand host parameters in the trace
# output.  Test this feature.
#
do_test trace-6.1 {
  set ::t6int [expr {3+3}]
  set ::t6real [expr {1.5*4.0}]
  set ::t6str {test-six y'all}
  db eval {SELECT x'3031323334' AS x} {set ::t6blob $x}
  unset -nocomplain t6null
  set TRACE_OUT {}
  execsql {SELECT $::t6int, $::t6real, $t6str, $t6blob, $t6null}
} {6 6.0 {test-six y'all} 01234 {}}
do_test trace-6.2 {
  set TRACE_OUT
} {{SELECT 6, 6.0, 'test-six y''all', x'3031323334', NULL}}

finish_test
Changes to tool/mksqlite3c.tcl.
246
247
248
249
250
251
252

253
254
255
256
257
258
259
   btmutex.c
   btree.c
   backup.c

   vdbemem.c
   vdbeaux.c
   vdbeapi.c

   vdbe.c
   vdbeblob.c
   journal.c
   memjournal.c

   walker.c
   resolve.c







>







246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
   btmutex.c
   btree.c
   backup.c

   vdbemem.c
   vdbeaux.c
   vdbeapi.c
   vdbetrace.c
   vdbe.c
   vdbeblob.c
   journal.c
   memjournal.c

   walker.c
   resolve.c