diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/printf.c | 12 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 | ||||
-rw-r--r-- | src/vdbe.c | 4 | ||||
-rw-r--r-- | src/vdbe.h | 3 | ||||
-rw-r--r-- | src/vdbetrace.c | 132 |
5 files changed, 153 insertions, 1 deletions
diff --git a/src/printf.c b/src/printf.c index fdd1222c2..17edb0907 100644 --- a/src/printf.c +++ b/src/printf.c @@ -957,3 +957,15 @@ void sqlite3DebugPrintf(const char *zFormat, ...){ 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 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a3980a071..3adba1c62 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2517,6 +2517,9 @@ 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*,...); diff --git a/src/vdbe.c b/src/vdbe.c index 35916ea47..97a98b316 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -5632,7 +5632,9 @@ case OP_Trace: { zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); if( zTrace ){ if( db->xTrace ){ - db->xTrace(db->pTraceArg, zTrace); + char *z = sqlite3VdbeExpandSql(p, zTrace); + db->xTrace(db->pTraceArg, z); + sqlite3DbFree(db, z); } #ifdef SQLITE_DEBUG if( (db->flags & SQLITE_SqlTrace)!=0 ){ diff --git a/src/vdbe.h b/src/vdbe.h index 3ac85eafd..f67e903b8 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -203,6 +203,9 @@ 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*); diff --git a/src/vdbetrace.c b/src/vdbetrace.c new file mode 100644 index 000000000..f43fe5532 --- /dev/null +++ b/src/vdbetrace.c @@ -0,0 +1,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 */ |