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.
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().
15: **
16: ** The Vdbe parse-tree explainer is also found here.
17: */
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: */
29: static int findNextHostParameter(const char *zSql, int *pnToken){
30: int tokenType;
31: int nTotal = 0;
32: int n;
33:
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;
41: }
42: nTotal += n;
43: zSql += n;
44: }
45: return nTotal;
46: }
47:
48: /*
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.
55: **
56: ** The calling function is responsible for making sure the memory returned
57: ** is eventually freed.
58: **
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.
66: */
67: char *sqlite3VdbeExpandSql(
68: Vdbe *p, /* The prepared statement being evaluated */
69: const char *zRawSql /* Raw text of the SQL statement */
70: ){
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 */
80:
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));
91: }
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;
106: }
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 );
114: }
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
138: {
139: sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
140: }
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);
148: }
149: sqlite3StrAccumAppend(&out, "'", 1);
150: }
151: }
152: }
153: return sqlite3StrAccumFinish(&out);
154: }
155:
156: #endif /* #ifndef SQLITE_OMIT_TRACE */
157:
158: /*****************************************************************************
159: ** The following code implements the data-structure explaining logic
160: ** for the Vdbe.
161: */
162:
163: #if defined(SQLITE_ENABLE_TREE_EXPLAIN)
164:
165: /*
166: ** Allocate a new Explain object
167: */
168: void sqlite3ExplainBegin(Vdbe *pVdbe){
169: if( pVdbe ){
170: sqlite3BeginBenignMalloc();
171: Explain *p = sqlite3_malloc( sizeof(Explain) );
172: if( p ){
173: memset(p, 0, sizeof(*p));
174: p->pVdbe = pVdbe;
175: sqlite3_free(pVdbe->pExplain);
176: pVdbe->pExplain = p;
177: sqlite3StrAccumInit(&p->str, p->zBase, sizeof(p->zBase),
178: SQLITE_MAX_LENGTH);
179: p->str.useMalloc = 2;
180: }else{
181: sqlite3EndBenignMalloc();
182: }
183: }
184: }
185:
186: /*
187: ** Return true if the Explain ends with a new-line.
188: */
189: static int endsWithNL(Explain *p){
190: return p && p->str.zText && p->str.nChar
191: && p->str.zText[p->str.nChar-1]=='\n';
192: }
193:
194: /*
195: ** Append text to the indentation
196: */
197: void sqlite3ExplainPrintf(Vdbe *pVdbe, const char *zFormat, ...){
198: Explain *p;
199: if( pVdbe && (p = pVdbe->pExplain)!=0 ){
200: va_list ap;
201: if( p->nIndent && endsWithNL(p) ){
202: int n = p->nIndent;
203: if( n>ArraySize(p->aIndent) ) n = ArraySize(p->aIndent);
204: sqlite3AppendSpace(&p->str, p->aIndent[n-1]);
205: }
206: va_start(ap, zFormat);
207: sqlite3VXPrintf(&p->str, 1, zFormat, ap);
208: va_end(ap);
209: }
210: }
211:
212: /*
213: ** Append a '\n' if there is not already one.
214: */
215: void sqlite3ExplainNL(Vdbe *pVdbe){
216: Explain *p;
217: if( pVdbe && (p = pVdbe->pExplain)!=0 && !endsWithNL(p) ){
218: sqlite3StrAccumAppend(&p->str, "\n", 1);
219: }
220: }
221:
222: /*
223: ** Push a new indentation level. Subsequent lines will be indented
224: ** so that they begin at the current cursor position.
225: */
226: void sqlite3ExplainPush(Vdbe *pVdbe){
227: Explain *p;
228: if( pVdbe && (p = pVdbe->pExplain)!=0 ){
229: if( p->str.zText && p->nIndent<ArraySize(p->aIndent) ){
230: const char *z = p->str.zText;
231: int i = p->str.nChar-1;
232: int x;
233: while( i>=0 && z[i]!='\n' ){ i--; }
234: x = (p->str.nChar - 1) - i;
235: if( p->nIndent && x<p->aIndent[p->nIndent-1] ){
236: x = p->aIndent[p->nIndent-1];
237: }
238: p->aIndent[p->nIndent] = x;
239: }
240: p->nIndent++;
241: }
242: }
243:
244: /*
245: ** Pop the indentation stack by one level.
246: */
247: void sqlite3ExplainPop(Vdbe *p){
248: if( p && p->pExplain ) p->pExplain->nIndent--;
249: }
250:
251: /*
252: ** Free the indentation structure
253: */
254: void sqlite3ExplainFinish(Vdbe *pVdbe){
255: if( pVdbe && pVdbe->pExplain ){
256: sqlite3_free(pVdbe->zExplain);
257: sqlite3ExplainNL(pVdbe);
258: pVdbe->zExplain = sqlite3StrAccumFinish(&pVdbe->pExplain->str);
259: sqlite3_free(pVdbe->pExplain);
260: pVdbe->pExplain = 0;
261: sqlite3EndBenignMalloc();
262: }
263: }
264:
265: /*
266: ** Return the explanation of a virtual machine.
267: */
268: const char *sqlite3VdbeExplanation(Vdbe *pVdbe){
269: return (pVdbe && pVdbe->zExplain) ? pVdbe->zExplain : 0;
270: }
271: #endif /* defined(SQLITE_DEBUG) */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>