Modify the trace callback mechanism so that SQL commands executed from within virtual table or user function callbacks are passed to the trace callback without parameter expansion and enclosed in SQL comments.

FossilOrigin-Name: a764915b87564fa91ee68e9b1f41394ce0f1fc7e
This commit is contained in:
dan 2011-01-22 13:32:29 +00:00
parent a9ef7097c7
commit 27381bd519
7 changed files with 234 additions and 66 deletions

0
install-sh Normal file → Executable file
View File

View File

@ -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

View File

@ -1 +1 @@
380f61df0754ceec6b3f6a758d04e951cce8c3d9
a764915b87564fa91ee68e9b1f41394ce0f1fc7e

View 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 */

View 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

View 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);
}else{
idx = nextIndex;
}
}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 );
if( db->vdbeExecCnt>1 ){
while( *zRawSql ){
const char *zStart = zRawSql;
while( *(zRawSql++)!='\n' && *zRawSql );
sqlite3StrAccumAppend(&out, "-- ", 3);
sqlite3StrAccumAppend(&out, zStart, zRawSql-zStart);
}
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 ){
}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{
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 ){
#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);
{
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);
}
}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);
}
}
return sqlite3StrAccumFinish(&out);

152
test/trace2.test Normal file
View File

@ -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