aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c12
-rw-r--r--src/sqlite.h.in71
-rw-r--r--src/sqlite3ext.h5
-rw-r--r--src/sqliteInt.h2
-rw-r--r--src/test1.c21
-rw-r--r--src/vdbe.c24
-rw-r--r--src/vdbeapi.c2
-rw-r--r--src/vdbeaux.c15
-rw-r--r--src/vdbetrace.c2
9 files changed, 97 insertions, 57 deletions
diff --git a/src/main.c b/src/main.c
index 5969738f6..2e996b554 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 07d85b254..8b9aa7402 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.
**
** <dl>
-** [[SQLITE_TRACE_SQL]] <dt>SQLITE_TRACE_SQL</dt>
-** <dd>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]] <dt>SQLITE_TRACE_STMT</dt>
-** <dd>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.
+** <dd>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]] <dt>SQLITE_TRACE_PROFILE</dt>
** <dd>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]] <dt>SQLITE_TRACE_ROW</dt>
** <dd>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.
** </dl>
*/
-#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 8bcfc6852..4d5023292 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 225d7b287..0be494751 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 5ce818bf7..a1fdcb5cf 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 788353602..cdbd7301b 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 a602fad38..883e5c95b 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 63609d72d..355021e97 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -73,6 +73,21 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt){
}
/*
+** 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.
*/
void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
diff --git a/src/vdbetrace.c b/src/vdbetrace.c
index 07235c931..7311bc35c 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 ){