blob: 88935beeac96240598c9df0afca34e1f656545fd [file] [log] [blame]
drhc7bc4fd2009-11-25 18:03:42 +00001/*
2** 2009 November 25
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11*************************************************************************
12**
13** This file contains code used to insert the values of host parameters
14** (aka "wildcards") into the SQL text output by sqlite3_trace().
drh7e02e5e2011-12-06 19:44:51 +000015**
drh678a9aa2011-12-10 15:55:01 +000016** The Vdbe parse-tree explainer is also found here.
drhc7bc4fd2009-11-25 18:03:42 +000017*/
18#include "sqliteInt.h"
19#include "vdbeInt.h"
20
21#ifndef SQLITE_OMIT_TRACE
22
23/*
24** zSql is a zero-terminated string of UTF-8 SQL text. Return the number of
25** bytes in this text up to but excluding the first character in
26** a host parameter. If the text contains no host parameters, return
27** the total number of bytes in the text.
28*/
drh5f18a222009-11-26 14:01:53 +000029static int findNextHostParameter(const char *zSql, int *pnToken){
drhc7bc4fd2009-11-25 18:03:42 +000030 int tokenType;
31 int nTotal = 0;
32 int n;
33
drh5f18a222009-11-26 14:01:53 +000034 *pnToken = 0;
drhc7bc4fd2009-11-25 18:03:42 +000035 while( zSql[0] ){
36 n = sqlite3GetToken((u8*)zSql, &tokenType);
37 assert( n>0 && tokenType!=TK_ILLEGAL );
drh5f18a222009-11-26 14:01:53 +000038 if( tokenType==TK_VARIABLE ){
39 *pnToken = n;
40 break;
41 }
drhc7bc4fd2009-11-25 18:03:42 +000042 nTotal += n;
43 zSql += n;
44 }
45 return nTotal;
46}
47
48/*
dan27381bd2011-01-22 13:32:29 +000049** This function returns a pointer to a nul-terminated string in memory
50** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the
51** string contains a copy of zRawSql but with host parameters expanded to
52** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1,
53** then the returned string holds a copy of zRawSql with "-- " prepended
54** to each line of text.
drhc7bc4fd2009-11-25 18:03:42 +000055**
drh936c6d72013-04-02 13:56:53 +000056** If the SQLITE_TRACE_SIZE_LIMIT macro is defined to an integer, then
57** then long strings and blobs are truncated to that many bytes. This
58** can be used to prevent unreasonably large trace strings when dealing
59** with large (multi-megabyte) strings and blobs.
60**
drhc7bc4fd2009-11-25 18:03:42 +000061** The calling function is responsible for making sure the memory returned
62** is eventually freed.
63**
64** ALGORITHM: Scan the input string looking for host parameters in any of
65** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within
66** string literals, quoted identifier names, and comments. For text forms,
67** the host parameter index is found by scanning the perpared
68** statement for the corresponding OP_Variable opcode. Once the host
69** parameter index is known, locate the value in p->aVar[]. Then render
70** the value as a literal in place of the host parameter name.
71*/
72char *sqlite3VdbeExpandSql(
73 Vdbe *p, /* The prepared statement being evaluated */
74 const char *zRawSql /* Raw text of the SQL statement */
75){
76 sqlite3 *db; /* The database connection */
drh1e634992009-11-28 13:46:51 +000077 int idx = 0; /* Index of a host parameter */
drhc7bc4fd2009-11-25 18:03:42 +000078 int nextIndex = 1; /* Index of next ? host parameter */
79 int n; /* Length of a token prefix */
drh5f18a222009-11-26 14:01:53 +000080 int nToken; /* Length of the parameter token */
drhc7bc4fd2009-11-25 18:03:42 +000081 int i; /* Loop counter */
drhc7bc4fd2009-11-25 18:03:42 +000082 Mem *pVar; /* Value of a host parameter */
drhc7bc4fd2009-11-25 18:03:42 +000083 StrAccum out; /* Accumulate the output here */
84 char zBase[100]; /* Initial working space */
85
86 db = p->db;
87 sqlite3StrAccumInit(&out, zBase, sizeof(zBase),
88 db->aLimit[SQLITE_LIMIT_LENGTH]);
89 out.db = db;
dan27381bd2011-01-22 13:32:29 +000090 if( db->vdbeExecCnt>1 ){
91 while( *zRawSql ){
92 const char *zStart = zRawSql;
93 while( *(zRawSql++)!='\n' && *zRawSql );
94 sqlite3StrAccumAppend(&out, "-- ", 3);
shanehcef83682011-04-07 03:41:01 +000095 sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
drhc7bc4fd2009-11-25 18:03:42 +000096 }
dan27381bd2011-01-22 13:32:29 +000097 }else{
98 while( zRawSql[0] ){
99 n = findNextHostParameter(zRawSql, &nToken);
100 assert( n>0 );
101 sqlite3StrAccumAppend(&out, zRawSql, n);
102 zRawSql += n;
103 assert( zRawSql[0] || nToken==0 );
104 if( nToken==0 ) break;
105 if( zRawSql[0]=='?' ){
106 if( nToken>1 ){
107 assert( sqlite3Isdigit(zRawSql[1]) );
108 sqlite3GetInt32(&zRawSql[1], &idx);
109 }else{
110 idx = nextIndex;
111 }
112 }else{
113 assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
114 testcase( zRawSql[0]==':' );
115 testcase( zRawSql[0]=='$' );
116 testcase( zRawSql[0]=='@' );
117 idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
118 assert( idx>0 );
119 }
120 zRawSql += nToken;
121 nextIndex = idx + 1;
122 assert( idx>0 && idx<=p->nVar );
123 pVar = &p->aVar[idx-1];
124 if( pVar->flags & MEM_Null ){
125 sqlite3StrAccumAppend(&out, "NULL", 4);
126 }else if( pVar->flags & MEM_Int ){
127 sqlite3XPrintf(&out, "%lld", pVar->u.i);
128 }else if( pVar->flags & MEM_Real ){
129 sqlite3XPrintf(&out, "%!.15g", pVar->r);
130 }else if( pVar->flags & MEM_Str ){
drhda8caa02013-04-22 23:38:50 +0000131 int nOut; /* Number of bytes of the string text to include in output */
drhc1bd1b32009-11-25 19:35:23 +0000132#ifndef SQLITE_OMIT_UTF16
dan27381bd2011-01-22 13:32:29 +0000133 u8 enc = ENC(db);
drh936c6d72013-04-02 13:56:53 +0000134 Mem utf8;
dan27381bd2011-01-22 13:32:29 +0000135 if( enc!=SQLITE_UTF8 ){
dan27381bd2011-01-22 13:32:29 +0000136 memset(&utf8, 0, sizeof(utf8));
137 utf8.db = db;
138 sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
139 sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
drh936c6d72013-04-02 13:56:53 +0000140 pVar = &utf8;
dan27381bd2011-01-22 13:32:29 +0000141 }
drh936c6d72013-04-02 13:56:53 +0000142#endif
drhda8caa02013-04-22 23:38:50 +0000143 nOut = pVar->n;
drh936c6d72013-04-02 13:56:53 +0000144#ifdef SQLITE_TRACE_SIZE_LIMIT
145 if( n>SQLITE_TRACE_SIZE_LIMIT ){
drhda8caa02013-04-22 23:38:50 +0000146 nOut = SQLITE_TRACE_SIZE_LIMIT;
147 while( nOut<pVar->n && (pVar->z[n]&0xc0)==0x80 ){ n++; }
drh936c6d72013-04-02 13:56:53 +0000148 }
149#endif
drhda8caa02013-04-22 23:38:50 +0000150 sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
drh936c6d72013-04-02 13:56:53 +0000151#ifdef SQLITE_TRACE_SIZE_LIMIT
drhda8caa02013-04-22 23:38:50 +0000152 if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-n);
drh936c6d72013-04-02 13:56:53 +0000153#endif
154#ifndef SQLITE_OMIT_UTF16
155 if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
156#endif
dan27381bd2011-01-22 13:32:29 +0000157 }else if( pVar->flags & MEM_Zero ){
158 sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
159 }else{
drhda8caa02013-04-22 23:38:50 +0000160 int nOut; /* Number of bytes of the blob to include in output */
dan27381bd2011-01-22 13:32:29 +0000161 assert( pVar->flags & MEM_Blob );
162 sqlite3StrAccumAppend(&out, "x'", 2);
drhda8caa02013-04-22 23:38:50 +0000163 nOut = pVar->n;
drh936c6d72013-04-02 13:56:53 +0000164#ifdef SQLITE_TRACE_SIZE_LIMIT
drhda8caa02013-04-22 23:38:50 +0000165 if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT;
drh936c6d72013-04-02 13:56:53 +0000166#endif
drhda8caa02013-04-22 23:38:50 +0000167 for(i=0; i<nOut; i++){
dan27381bd2011-01-22 13:32:29 +0000168 sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
169 }
170 sqlite3StrAccumAppend(&out, "'", 1);
drh936c6d72013-04-02 13:56:53 +0000171#ifdef SQLITE_TRACE_SIZE_LIMIT
drhda8caa02013-04-22 23:38:50 +0000172 if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-n);
drh936c6d72013-04-02 13:56:53 +0000173#endif
drhc1bd1b32009-11-25 19:35:23 +0000174 }
drhc7bc4fd2009-11-25 18:03:42 +0000175 }
176 }
177 return sqlite3StrAccumFinish(&out);
178}
179
180#endif /* #ifndef SQLITE_OMIT_TRACE */
drh7e02e5e2011-12-06 19:44:51 +0000181
182/*****************************************************************************
183** The following code implements the data-structure explaining logic
184** for the Vdbe.
185*/
186
drh678a9aa2011-12-10 15:55:01 +0000187#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
drh7e02e5e2011-12-06 19:44:51 +0000188
189/*
190** Allocate a new Explain object
191*/
192void sqlite3ExplainBegin(Vdbe *pVdbe){
193 if( pVdbe ){
mistachkin84ee0af2012-05-21 05:02:22 +0000194 Explain *p;
drh7e02e5e2011-12-06 19:44:51 +0000195 sqlite3BeginBenignMalloc();
dan6809c962012-07-30 14:53:54 +0000196 p = (Explain *)sqlite3MallocZero( sizeof(Explain) );
drh7e02e5e2011-12-06 19:44:51 +0000197 if( p ){
drh7e02e5e2011-12-06 19:44:51 +0000198 p->pVdbe = pVdbe;
199 sqlite3_free(pVdbe->pExplain);
200 pVdbe->pExplain = p;
201 sqlite3StrAccumInit(&p->str, p->zBase, sizeof(p->zBase),
202 SQLITE_MAX_LENGTH);
203 p->str.useMalloc = 2;
204 }else{
205 sqlite3EndBenignMalloc();
206 }
207 }
208}
209
210/*
211** Return true if the Explain ends with a new-line.
212*/
213static int endsWithNL(Explain *p){
214 return p && p->str.zText && p->str.nChar
215 && p->str.zText[p->str.nChar-1]=='\n';
216}
217
218/*
219** Append text to the indentation
220*/
221void sqlite3ExplainPrintf(Vdbe *pVdbe, const char *zFormat, ...){
222 Explain *p;
223 if( pVdbe && (p = pVdbe->pExplain)!=0 ){
224 va_list ap;
225 if( p->nIndent && endsWithNL(p) ){
226 int n = p->nIndent;
227 if( n>ArraySize(p->aIndent) ) n = ArraySize(p->aIndent);
228 sqlite3AppendSpace(&p->str, p->aIndent[n-1]);
229 }
230 va_start(ap, zFormat);
231 sqlite3VXPrintf(&p->str, 1, zFormat, ap);
232 va_end(ap);
233 }
234}
235
236/*
237** Append a '\n' if there is not already one.
238*/
239void sqlite3ExplainNL(Vdbe *pVdbe){
240 Explain *p;
241 if( pVdbe && (p = pVdbe->pExplain)!=0 && !endsWithNL(p) ){
242 sqlite3StrAccumAppend(&p->str, "\n", 1);
243 }
244}
245
246/*
247** Push a new indentation level. Subsequent lines will be indented
248** so that they begin at the current cursor position.
249*/
250void sqlite3ExplainPush(Vdbe *pVdbe){
251 Explain *p;
252 if( pVdbe && (p = pVdbe->pExplain)!=0 ){
253 if( p->str.zText && p->nIndent<ArraySize(p->aIndent) ){
254 const char *z = p->str.zText;
255 int i = p->str.nChar-1;
256 int x;
257 while( i>=0 && z[i]!='\n' ){ i--; }
258 x = (p->str.nChar - 1) - i;
259 if( p->nIndent && x<p->aIndent[p->nIndent-1] ){
260 x = p->aIndent[p->nIndent-1];
261 }
262 p->aIndent[p->nIndent] = x;
263 }
264 p->nIndent++;
265 }
266}
267
268/*
269** Pop the indentation stack by one level.
270*/
271void sqlite3ExplainPop(Vdbe *p){
272 if( p && p->pExplain ) p->pExplain->nIndent--;
273}
274
275/*
276** Free the indentation structure
277*/
278void sqlite3ExplainFinish(Vdbe *pVdbe){
279 if( pVdbe && pVdbe->pExplain ){
280 sqlite3_free(pVdbe->zExplain);
281 sqlite3ExplainNL(pVdbe);
282 pVdbe->zExplain = sqlite3StrAccumFinish(&pVdbe->pExplain->str);
283 sqlite3_free(pVdbe->pExplain);
284 pVdbe->pExplain = 0;
285 sqlite3EndBenignMalloc();
286 }
287}
288
289/*
290** Return the explanation of a virtual machine.
291*/
292const char *sqlite3VdbeExplanation(Vdbe *pVdbe){
293 return (pVdbe && pVdbe->zExplain) ? pVdbe->zExplain : 0;
294}
295#endif /* defined(SQLITE_DEBUG) */