restructure to allow non-amalgamated builds again
[sqlcipher.git] / src / vdbetrace.c
blobc71a7c41a4384378cc49da968bb5c508372efa4f
1 /*
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.
11 *************************************************************************
13 ** This file contains code used to insert the values of host parameters
14 ** (aka "wildcards") into the SQL text output by sqlite3_trace().
16 ** The Vdbe parse-tree explainer is also found here.
18 #include "sqliteInt.h"
19 #include "vdbeInt.h"
21 #ifndef SQLITE_OMIT_TRACE
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.
29 static int findNextHostParameter(const char *zSql, int *pnToken){
30 int tokenType;
31 int nTotal = 0;
32 int n;
34 *pnToken = 0;
35 while( zSql[0] ){
36 n = sqlite3GetToken((u8*)zSql, &tokenType);
37 assert( n>0 && tokenType!=TK_ILLEGAL );
38 if( tokenType==TK_VARIABLE ){
39 *pnToken = n;
40 break;
42 nTotal += n;
43 zSql += n;
45 return nTotal;
49 ** 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.
56 ** The calling function is responsible for making sure the memory returned
57 ** is eventually freed.
59 ** ALGORITHM: Scan the input string looking for host parameters in any of
60 ** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within
61 ** string literals, quoted identifier names, and comments. For text forms,
62 ** the host parameter index is found by scanning the perpared
63 ** statement for the corresponding OP_Variable opcode. Once the host
64 ** parameter index is known, locate the value in p->aVar[]. Then render
65 ** the value as a literal in place of the host parameter name.
67 char *sqlite3VdbeExpandSql(
68 Vdbe *p, /* The prepared statement being evaluated */
69 const char *zRawSql /* Raw text of the SQL statement */
71 sqlite3 *db; /* The database connection */
72 int idx = 0; /* Index of a host parameter */
73 int nextIndex = 1; /* Index of next ? host parameter */
74 int n; /* Length of a token prefix */
75 int nToken; /* Length of the parameter token */
76 int i; /* Loop counter */
77 Mem *pVar; /* Value of a host parameter */
78 StrAccum out; /* Accumulate the output here */
79 char zBase[100]; /* Initial working space */
81 db = p->db;
82 sqlite3StrAccumInit(&out, zBase, sizeof(zBase),
83 db->aLimit[SQLITE_LIMIT_LENGTH]);
84 out.db = db;
85 if( db->vdbeExecCnt>1 ){
86 while( *zRawSql ){
87 const char *zStart = zRawSql;
88 while( *(zRawSql++)!='\n' && *zRawSql );
89 sqlite3StrAccumAppend(&out, "-- ", 3);
90 sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
92 }else{
93 while( zRawSql[0] ){
94 n = findNextHostParameter(zRawSql, &nToken);
95 assert( n>0 );
96 sqlite3StrAccumAppend(&out, zRawSql, n);
97 zRawSql += n;
98 assert( zRawSql[0] || nToken==0 );
99 if( nToken==0 ) break;
100 if( zRawSql[0]=='?' ){
101 if( nToken>1 ){
102 assert( sqlite3Isdigit(zRawSql[1]) );
103 sqlite3GetInt32(&zRawSql[1], &idx);
104 }else{
105 idx = nextIndex;
107 }else{
108 assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
109 testcase( zRawSql[0]==':' );
110 testcase( zRawSql[0]=='$' );
111 testcase( zRawSql[0]=='@' );
112 idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
113 assert( idx>0 );
115 zRawSql += nToken;
116 nextIndex = idx + 1;
117 assert( idx>0 && idx<=p->nVar );
118 pVar = &p->aVar[idx-1];
119 if( pVar->flags & MEM_Null ){
120 sqlite3StrAccumAppend(&out, "NULL", 4);
121 }else if( pVar->flags & MEM_Int ){
122 sqlite3XPrintf(&out, "%lld", pVar->u.i);
123 }else if( pVar->flags & MEM_Real ){
124 sqlite3XPrintf(&out, "%!.15g", pVar->r);
125 }else if( pVar->flags & MEM_Str ){
126 #ifndef SQLITE_OMIT_UTF16
127 u8 enc = ENC(db);
128 if( enc!=SQLITE_UTF8 ){
129 Mem utf8;
130 memset(&utf8, 0, sizeof(utf8));
131 utf8.db = db;
132 sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
133 sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
134 sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
135 sqlite3VdbeMemRelease(&utf8);
136 }else
137 #endif
139 sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
141 }else if( pVar->flags & MEM_Zero ){
142 sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
143 }else{
144 assert( pVar->flags & MEM_Blob );
145 sqlite3StrAccumAppend(&out, "x'", 2);
146 for(i=0; i<pVar->n; i++){
147 sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
149 sqlite3StrAccumAppend(&out, "'", 1);
153 return sqlite3StrAccumFinish(&out);
156 #endif /* #ifndef SQLITE_OMIT_TRACE */
158 /*****************************************************************************
159 ** The following code implements the data-structure explaining logic
160 ** for the Vdbe.
163 #if defined(SQLITE_ENABLE_TREE_EXPLAIN)
166 ** Allocate a new Explain object
168 void sqlite3ExplainBegin(Vdbe *pVdbe){
169 if( pVdbe ){
170 Explain *p;
171 sqlite3BeginBenignMalloc();
172 p = sqlite3_malloc( sizeof(Explain) );
173 if( p ){
174 memset(p, 0, sizeof(*p));
175 p->pVdbe = pVdbe;
176 sqlite3_free(pVdbe->pExplain);
177 pVdbe->pExplain = p;
178 sqlite3StrAccumInit(&p->str, p->zBase, sizeof(p->zBase),
179 SQLITE_MAX_LENGTH);
180 p->str.useMalloc = 2;
181 }else{
182 sqlite3EndBenignMalloc();
188 ** Return true if the Explain ends with a new-line.
190 static int endsWithNL(Explain *p){
191 return p && p->str.zText && p->str.nChar
192 && p->str.zText[p->str.nChar-1]=='\n';
196 ** Append text to the indentation
198 void sqlite3ExplainPrintf(Vdbe *pVdbe, const char *zFormat, ...){
199 Explain *p;
200 if( pVdbe && (p = pVdbe->pExplain)!=0 ){
201 va_list ap;
202 if( p->nIndent && endsWithNL(p) ){
203 int n = p->nIndent;
204 if( n>ArraySize(p->aIndent) ) n = ArraySize(p->aIndent);
205 sqlite3AppendSpace(&p->str, p->aIndent[n-1]);
207 va_start(ap, zFormat);
208 sqlite3VXPrintf(&p->str, 1, zFormat, ap);
209 va_end(ap);
214 ** Append a '\n' if there is not already one.
216 void sqlite3ExplainNL(Vdbe *pVdbe){
217 Explain *p;
218 if( pVdbe && (p = pVdbe->pExplain)!=0 && !endsWithNL(p) ){
219 sqlite3StrAccumAppend(&p->str, "\n", 1);
224 ** Push a new indentation level. Subsequent lines will be indented
225 ** so that they begin at the current cursor position.
227 void sqlite3ExplainPush(Vdbe *pVdbe){
228 Explain *p;
229 if( pVdbe && (p = pVdbe->pExplain)!=0 ){
230 if( p->str.zText && p->nIndent<ArraySize(p->aIndent) ){
231 const char *z = p->str.zText;
232 int i = p->str.nChar-1;
233 int x;
234 while( i>=0 && z[i]!='\n' ){ i--; }
235 x = (p->str.nChar - 1) - i;
236 if( p->nIndent && x<p->aIndent[p->nIndent-1] ){
237 x = p->aIndent[p->nIndent-1];
239 p->aIndent[p->nIndent] = x;
241 p->nIndent++;
246 ** Pop the indentation stack by one level.
248 void sqlite3ExplainPop(Vdbe *p){
249 if( p && p->pExplain ) p->pExplain->nIndent--;
253 ** Free the indentation structure
255 void sqlite3ExplainFinish(Vdbe *pVdbe){
256 if( pVdbe && pVdbe->pExplain ){
257 sqlite3_free(pVdbe->zExplain);
258 sqlite3ExplainNL(pVdbe);
259 pVdbe->zExplain = sqlite3StrAccumFinish(&pVdbe->pExplain->str);
260 sqlite3_free(pVdbe->pExplain);
261 pVdbe->pExplain = 0;
262 sqlite3EndBenignMalloc();
267 ** Return the explanation of a virtual machine.
269 const char *sqlite3VdbeExplanation(Vdbe *pVdbe){
270 return (pVdbe && pVdbe->zExplain) ? pVdbe->zExplain : 0;
272 #endif /* defined(SQLITE_DEBUG) */