From: drh Date: Thu, 14 Jul 2016 01:09:08 +0000 (+0000) Subject: Add the sqlite3_expanded_sql() interface. Refinements to the X-Git-Tag: version-3.14.0~57^2~16 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fca760c841227207bb8dd0dd43fb89a100ca18fb;p=thirdparty%2Fsqlite.git Add the sqlite3_expanded_sql() interface. Refinements to the sqlite3_trace_v2() interface to make it more useful. FossilOrigin-Name: 99ee7ee58d45b29a0000492306ddc0b90563ff51 --- diff --git a/manifest b/manifest index a7725c09a7..98c634e400 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Legacy\stests\snow\spassing. -D 2016-07-13T23:18:27.653 +C Add\sthe\ssqlite3_expanded_sql()\sinterface.\s\sRefinements\sto\sthe\nsqlite3_trace_v2()\sinterface\sto\smake\sit\smore\suseful. +D 2016-07-14T01:09:08.369 F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a @@ -348,7 +348,7 @@ F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/insert.c 8f4e9fcbd8e95e85f15647ba8b413b18d556ec2b F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e F src/loadext.c 4237fd37ca589f1d90b3ea925dd9df20da8e0c84 -F src/main.c a3be9a816c72fe658838e33e42afabfff93526f2 +F src/main.c ade3b39f3bde9212b3fabcff2367d29052002df6 F src/malloc.c 1443d1ad95d67c21d77af7ae3f44678252f0efec F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b @@ -385,15 +385,15 @@ F src/resolve.c cca3aa77b95706df5d635a2141a4d1de60ae6598 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac F src/select.c f3c6e9065fb34f6a23af27ec7f1f717ffbfc2ee4 F src/shell.c a8a9e392a6a2777fabf5feb536931cb190f235e5 -F src/sqlite.h.in 0fde7379e6a9d900802976de51cb1256f0fdac59 +F src/sqlite.h.in 6ba80e88ee17b9071f35121271784ecef60df863 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 -F src/sqlite3ext.h 3875aa5b3c4bb5d8d14c387628c5fe852b2846bf -F src/sqliteInt.h 5b8a3e1dc92e7459b69954cce9f653bd2391deb8 +F src/sqlite3ext.h 6fb1639d41907544cb3905c69a348ee64c5da79e +F src/sqliteInt.h 48cd97eb134665348393dfe277b4c14d1085bfc7 F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247 F src/status.c 5b18f9526900f61189ab0b83f1ef41d9f871a2ab F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9 F src/tclsqlite.c 25fbbbb97f76dbfd113153fb63f52d7ecfac5dd0 -F src/test1.c 640f862c490c8eee09a9d02d0d128c6a8a75336d +F src/test1.c 5124aff86fba753a6994e9621696ccfdc8bbf24e F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b F src/test3.c c75c8af0eadb335236c9e61b51044c58a8f7dd59 F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e @@ -449,15 +449,15 @@ F src/update.c 4f05ea8cddfa367d045e03589756c02199e8f9bd F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c F src/util.c 810ec3f22e2d1b62e66c30fe3621ebdedd23584d F src/vacuum.c 544ec90a66a4b0460b7c1baeadbc21b45e6ca0b6 -F src/vdbe.c c6bb62aa69a6faf1197eee36336c6de99bb4733f +F src/vdbe.c 7b5570f77e32766949fd8f9478e4a9bb06e6ab24 F src/vdbe.h 67bc551f7faf04c33493892e4b378aada823ed10 F src/vdbeInt.h c59381049af5c7751a83456c39b80d1a6fde1f9d -F src/vdbeapi.c a466743c8e6de100c11e044b693c9469d2cf598a -F src/vdbeaux.c c90275b0e55a2b32c03dc09314194fe46f2429d8 +F src/vdbeapi.c 460b90f7f0894753d33df377702c1dc9cc5fa21b +F src/vdbeaux.c 6083ff395021ac8c40e1b53798ee6483037e3fb7 F src/vdbeblob.c 83d2d266383157b02e2b809350bb197e89d7895b F src/vdbemem.c 1ecaa5ee0caff07255f25d04e8dc88befb6f88d1 F src/vdbesort.c 91fda3909326860382b0ca8aa251e609c6a9d62c -F src/vdbetrace.c f75c5455d8cf389ef86a8bfdfd3177e0e3692484 +F src/vdbetrace.c d0371769fe66fe4eb85bdcacf82b6f2af50feb9b F src/vtab.c 948d2d4984219eee37a7bf427d6667e21e6eb92e F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 02eeecc265f6ffd0597378f5d8ae9070b62a406a @@ -1505,7 +1505,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cb0062feb018f52689938a58cb76886d431c33f0 -R d7e93f0729616f164eba3e9e1862aa07 +P f33526a341132435cb4185149a784eef6b3a1a2d +R b996b3134868ad007e1e44124ba2e740 U drh -Z a0be5e80cc5b797f562ce4c096d88be2 +Z 809ea44b43d6348d635e64228e5049a8 diff --git a/manifest.uuid b/manifest.uuid index 5103610b4f..6a7d48edff 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f33526a341132435cb4185149a784eef6b3a1a2d \ No newline at end of file +99ee7ee58d45b29a0000492306ddc0b90563ff51 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 5969738f6b..2e996b5545 100644 --- a/src/main.c +++ b/src/main.c @@ -1805,7 +1805,7 @@ int sqlite3_overload_function( ** SQL statement. */ #ifndef SQLITE_OMIT_DEPRECATED -void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ +void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){ void *pOld; #ifdef SQLITE_ENABLE_API_ARMOR @@ -1817,7 +1817,7 @@ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; - db->xTrace = (int(*)(u32,void*,void*,i64))xTrace; + db->xTrace = (int(*)(u32,void*,void*,void*))xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; @@ -1827,10 +1827,10 @@ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ /* Register a trace callback using the version-2 interface. */ int sqlite3_trace_v2( - sqlite3 *db, /* Trace this connection */ - int(*xTrace)(unsigned,void*,void*,sqlite3_int64), /* Callback to invoke */ - unsigned mTrace, /* OPs to be traced */ - void *pArg /* Context */ + sqlite3 *db, /* Trace this connection */ + unsigned mTrace, /* Mask of events to be traced */ + int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */ + void *pArg /* Context */ ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 07d85b254d..8b9aa7402d 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2804,33 +2804,25 @@ SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** The T argument is one of the integer type codes above. ** The C argument is a copy of the context pointer passed in as the ** fourth argument to [sqlite3_trace_v2()]. -** The P argument is a pointer whose meaning depends on T. -** The X argument is an 64-bit integer whose meaning also -** depends on T. +** The P and X arguments are pointers whose meanings depend on T. ** **
-** [[SQLITE_TRACE_SQL]]
SQLITE_TRACE_SQL
-**
An SQLITE_TRACE_SQL callback provides the same functionality -** as the legacy [sqlite3_trace()] callback. -** The P argument is a pointer to the constant UTF-8 string that is text -** describing an SQL statement that is starting to run with all -** [bound parameter] expanded. The X argument is unused. The size -** of the expansion of [bound parameters] is limited by the -** [SQLITE_TRACE_SIZE_LIMIT] compile-time option. -** ** [[SQLITE_TRACE_STMT]]
SQLITE_TRACE_STMT
-**
An SQLITE_TRACE_STMT callback is invoked on the same occasions -** as SQLITE_TRACE_SQL. The difference is that the P argument is a -** pointer to the [prepared statement] rather than an SQL string. -** The X argument is unused. +**
An SQLITE_TRACE_STMT callback is invoked when a prepared statement +** first begins running and possibly at other times during the +** execution of the prepared statement, such as at the start of each +** trigger subprogram. The P argument is a pointer to the +** [prepared statement]. The X argument is a pointer to a string which +** is the expanded SQL text of the prepared statement or a comment that +** indicates the invocation of a trigger. ** ** [[SQLITE_TRACE_PROFILE]]
SQLITE_TRACE_PROFILE
**
An SQLITE_TRACE_PROFILE callback provides approximately the same ** information as is provided by the [sqlite3_profile()] callback. ** The P argument is a pointer to the [prepared statement] and the -** X argument is an estimate of the number of nanosecond for which -** the prepared statement ran. The SQLITE_TRACE_PROFILE callback is -** invoked when the statement finishes. +** X argument points to a 64-bit integer which is the estimated of +** the number of nanosecond that the prepared statement took to run. +** The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. ** ** [[SQLITE_TRACE_ROW]]
SQLITE_TRACE_ROW
**
An SQLITE_TRACE_ROW callback is invoked whenever a prepared @@ -2845,17 +2837,16 @@ SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** and the X argument is unused. **
*/ -#define SQLITE_TRACE_SQL 0x0001 -#define SQLITE_TRACE_STMT 0x0002 -#define SQLITE_TRACE_PROFILE 0x0004 -#define SQLITE_TRACE_ROW 0x0008 -#define SQLITE_TRACE_CLOSE 0x0010 +#define SQLITE_TRACE_STMT 0x01 +#define SQLITE_TRACE_PROFILE 0x02 +#define SQLITE_TRACE_ROW 0x04 +#define SQLITE_TRACE_CLOSE 0x08 /* ** CAPI3REF: SQL Trace Hook ** METHOD: sqlite3 ** -** The sqlite3_trace_v2(D,X,M,P) interface registers a trace callback +** The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback ** function X against [database connection] D, using property mask M ** and context pointer P. If the X callback is ** NULL or if the M mask is zero, then tracing is disabled. The @@ -2874,8 +2865,7 @@ SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** The T argument is one of the [SQLITE_TRACE] ** constants to indicate why the callback was invoked. ** The C argument is a copy of the context pointer. -** The P and X arguments are a pointer and a 64-bit integer -** whose meanings depend on T. +** The P and X arguments are pointers whose meanings depend on T. ** ** The sqlite3_trace_v2() interface is intended to replace the legacy ** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which @@ -2883,8 +2873,8 @@ SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, */ int sqlite3_trace_v2( sqlite3*, - int(*xCallback)(unsigned,void*,void*,sqlite3_int64), unsigned uMask, + int(*xCallback)(unsigned,void*,void*,void*), void *pCtx ); @@ -3506,11 +3496,30 @@ int sqlite3_prepare16_v2( ** CAPI3REF: Retrieving Statement SQL ** METHOD: sqlite3_stmt ** -** ^This interface can be used to retrieve a saved copy of the original -** SQL text used to create a [prepared statement] if that statement was -** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 +** SQL text used to create [prepared statement] P if P was +** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 +** string containing the SQL text of prepared statement P with +** [bound parameters] expanded. +** +** For example, if a prepared statement is created using the SQL +** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 +** and parameter :xyz is unbound, then sqlite3_sql() will return +** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() +** will return "SELECT 2345,NULL". +** +** The [SQLITE_TRACE_SIZE_LIMIT] setting limits the size of a +** bound parameter expansion. +** +** ^The string returned by sqlite3_sql(P) is managed by SQLite and is +** automatically freed when the prepared statement is finalized. +** ^The string returned by sqlite3_expanded_sql(P), on the other hand, +** is obtained from [sqlite3_malloc()] and must be free by the application +** by passing it to [sqlite3_free()]. */ const char *sqlite3_sql(sqlite3_stmt *pStmt); +char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 8bcfc68521..4d5023292b 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -282,8 +282,8 @@ struct sqlite3_api_routines { /* Version 3.12.0 and later */ int (*system_errno)(sqlite3*); /* Version 3.14.0 and later */ - int (*trace_v2)(sqlite3*,int(*)(unsigned,void*,void*,sqlite3_uint64), - unsigned,void*); + int (*trace_v2)(sqlite3*,int(*)(unsigned,void*,void*,void*),unsigned,void*); + char *(*expanded_sql)(sqlite3_stmt*); }; /* @@ -531,6 +531,7 @@ struct sqlite3_api_routines { #define sqlite3_system_errno sqlite3_api->system_errno /* Version 3.14.0 and later */ #define sqlite3_trace_v2 sqlite3_api->trace_v2 +#define sqlite3_expanded_sql sqlite3_api->expanded_sql #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 225d7b2872..0be4947513 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1300,7 +1300,7 @@ struct sqlite3 { int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ - int (*xTrace)(u32,void*,void*,i64); /* Trace function */ + int (*xTrace)(u32,void*,void*,void*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ diff --git a/src/test1.c b/src/test1.c index 5ce818bf74..a1fdcb5cfb 100644 --- a/src/test1.c +++ b/src/test1.c @@ -4386,6 +4386,26 @@ static int test_sql( Tcl_SetResult(interp, (char *)sqlite3_sql(pStmt), TCL_VOLATILE); return TCL_OK; } +static int test_ex_sql( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_stmt *pStmt; + char *z; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "STMT"); + return TCL_ERROR; + } + + if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; + z = sqlite3_expanded_sql(pStmt); + Tcl_SetResult(interp, z, TCL_VOLATILE); + sqlite3_free(z); + return TCL_OK; +} /* ** Usage: sqlite3_column_count STMT @@ -7276,6 +7296,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_changes", test_changes ,0 }, { "sqlite3_step", test_step ,0 }, { "sqlite3_sql", test_sql ,0 }, + { "sqlite3_expanded_sql", test_ex_sql ,0 }, { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, { "sqlite3_stmt_busy", test_stmt_busy ,0 }, diff --git a/src/vdbe.c b/src/vdbe.c index 7883536028..cdbd7301b8 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -6785,27 +6785,21 @@ case OP_Init: { /* jump */ char *z; #ifndef SQLITE_OMIT_TRACE - if( (db->mTrace & (SQLITE_TRACE_SQL|SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 + if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 && !p->doingRerun && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ - if( db->mTrace & (SQLITE_TRACE_SQL|SQLITE_TRACE_LEGACY) ){ - z = sqlite3VdbeExpandSql(p, zTrace); + z = sqlite3VdbeExpandSql(p, zTrace); #ifndef SQLITE_OMIT_DEPRECATED - if( SQLITE_TRACE_LEGACY ){ - void (*x)(void*,const char*); - x = (void(*)(void*,const char*))db->xTrace; - x(db->pTraceArg, z); - }else + if( db->mTrace & SQLITE_TRACE_LEGACY ){ + void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace; + x(db->pTraceArg, z); + }else #endif - { - db->xTrace(SQLITE_TRACE_SQL,db->pTraceArg,z,0); - } - sqlite3DbFree(db, z); - } - if( db->mTrace & SQLITE_TRACE_STMT ){ - (void)db->xTrace(SQLITE_TRACE_STMT,db->pTraceArg,p,0); + { + (void)db->xTrace(SQLITE_TRACE_STMT,db->pTraceArg,p,z); } + sqlite3_free(z); } #ifdef SQLITE_USE_FCNTL_TRACE zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index a602fad383..883e5c95bf 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -71,7 +71,7 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ db->xProfile(db->pProfileArg, p->zSql, iElapse); } if( db->mTrace & SQLITE_TRACE_PROFILE ){ - db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, iElapse); + db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse); } p->startTime = 0; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 63609d72dd..355021e970 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -72,6 +72,21 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt){ return p ? p->zSql : 0; } +/* +** Return the SQL associated with a prepared statement with +** bound parameters expanded. Space to hold the returned string is +** obtained from sqlite3_malloc(). The caller is responsible for +** freeing the returned string by passing it to sqlite3_free(). +** +** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of +** expanded bound parameters. +*/ +char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe *)pStmt; + return p ? sqlite3VdbeExpandSql(p, p->zSql) : 0; + if( p->zSql==0 ) return 0; +} + /* ** Swap all content between two VDBE structures. */ diff --git a/src/vdbetrace.c b/src/vdbetrace.c index 07235c931b..7311bc35c6 100644 --- a/src/vdbetrace.c +++ b/src/vdbetrace.c @@ -84,7 +84,7 @@ char *sqlite3VdbeExpandSql( char zBase[100]; /* Initial working space */ db = p->db; - sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase), + sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); if( db->nVdbeExec>1 ){ while( *zRawSql ){