OLD | NEW |
(Empty) | |
| 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 #include "sqliteInt.h" |
| 17 #include "vdbeInt.h" |
| 18 |
| 19 #ifndef SQLITE_OMIT_TRACE |
| 20 |
| 21 /* |
| 22 ** zSql is a zero-terminated string of UTF-8 SQL text. Return the number of |
| 23 ** bytes in this text up to but excluding the first character in |
| 24 ** a host parameter. If the text contains no host parameters, return |
| 25 ** the total number of bytes in the text. |
| 26 */ |
| 27 static int findNextHostParameter(const char *zSql, int *pnToken){ |
| 28 int tokenType; |
| 29 int nTotal = 0; |
| 30 int n; |
| 31 |
| 32 *pnToken = 0; |
| 33 while( zSql[0] ){ |
| 34 n = sqlite3GetToken((u8*)zSql, &tokenType); |
| 35 assert( n>0 && tokenType!=TK_ILLEGAL ); |
| 36 if( tokenType==TK_VARIABLE ){ |
| 37 *pnToken = n; |
| 38 break; |
| 39 } |
| 40 nTotal += n; |
| 41 zSql += n; |
| 42 } |
| 43 return nTotal; |
| 44 } |
| 45 |
| 46 /* |
| 47 ** Return a pointer to a string in memory obtained form sqlite3DbMalloc() which |
| 48 ** holds a copy of zRawSql but with host parameters expanded to their |
| 49 ** current bindings. |
| 50 ** |
| 51 ** The calling function is responsible for making sure the memory returned |
| 52 ** is eventually freed. |
| 53 ** |
| 54 ** ALGORITHM: Scan the input string looking for host parameters in any of |
| 55 ** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within |
| 56 ** string literals, quoted identifier names, and comments. For text forms, |
| 57 ** the host parameter index is found by scanning the perpared |
| 58 ** statement for the corresponding OP_Variable opcode. Once the host |
| 59 ** parameter index is known, locate the value in p->aVar[]. Then render |
| 60 ** the value as a literal in place of the host parameter name. |
| 61 */ |
| 62 char *sqlite3VdbeExpandSql( |
| 63 Vdbe *p, /* The prepared statement being evaluated */ |
| 64 const char *zRawSql /* Raw text of the SQL statement */ |
| 65 ){ |
| 66 sqlite3 *db; /* The database connection */ |
| 67 int idx = 0; /* Index of a host parameter */ |
| 68 int nextIndex = 1; /* Index of next ? host parameter */ |
| 69 int n; /* Length of a token prefix */ |
| 70 int nToken; /* Length of the parameter token */ |
| 71 int i; /* Loop counter */ |
| 72 Mem *pVar; /* Value of a host parameter */ |
| 73 StrAccum out; /* Accumulate the output here */ |
| 74 char zBase[100]; /* Initial working space */ |
| 75 |
| 76 db = p->db; |
| 77 sqlite3StrAccumInit(&out, zBase, sizeof(zBase), |
| 78 db->aLimit[SQLITE_LIMIT_LENGTH]); |
| 79 out.db = db; |
| 80 while( zRawSql[0] ){ |
| 81 n = findNextHostParameter(zRawSql, &nToken); |
| 82 assert( n>0 ); |
| 83 sqlite3StrAccumAppend(&out, zRawSql, n); |
| 84 zRawSql += n; |
| 85 assert( zRawSql[0] || nToken==0 ); |
| 86 if( nToken==0 ) break; |
| 87 if( zRawSql[0]=='?' ){ |
| 88 if( nToken>1 ){ |
| 89 assert( sqlite3Isdigit(zRawSql[1]) ); |
| 90 sqlite3GetInt32(&zRawSql[1], &idx); |
| 91 }else{ |
| 92 idx = nextIndex; |
| 93 } |
| 94 }else{ |
| 95 assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' ); |
| 96 testcase( zRawSql[0]==':' ); |
| 97 testcase( zRawSql[0]=='$' ); |
| 98 testcase( zRawSql[0]=='@' ); |
| 99 idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken); |
| 100 assert( idx>0 ); |
| 101 } |
| 102 zRawSql += nToken; |
| 103 nextIndex = idx + 1; |
| 104 assert( idx>0 && idx<=p->nVar ); |
| 105 pVar = &p->aVar[idx-1]; |
| 106 if( pVar->flags & MEM_Null ){ |
| 107 sqlite3StrAccumAppend(&out, "NULL", 4); |
| 108 }else if( pVar->flags & MEM_Int ){ |
| 109 sqlite3XPrintf(&out, "%lld", pVar->u.i); |
| 110 }else if( pVar->flags & MEM_Real ){ |
| 111 sqlite3XPrintf(&out, "%!.15g", pVar->r); |
| 112 }else if( pVar->flags & MEM_Str ){ |
| 113 #ifndef SQLITE_OMIT_UTF16 |
| 114 u8 enc = ENC(db); |
| 115 if( enc!=SQLITE_UTF8 ){ |
| 116 Mem utf8; |
| 117 memset(&utf8, 0, sizeof(utf8)); |
| 118 utf8.db = db; |
| 119 sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC); |
| 120 sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8); |
| 121 sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z); |
| 122 sqlite3VdbeMemRelease(&utf8); |
| 123 }else |
| 124 #endif |
| 125 { |
| 126 sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z); |
| 127 } |
| 128 }else if( pVar->flags & MEM_Zero ){ |
| 129 sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero); |
| 130 }else{ |
| 131 assert( pVar->flags & MEM_Blob ); |
| 132 sqlite3StrAccumAppend(&out, "x'", 2); |
| 133 for(i=0; i<pVar->n; i++){ |
| 134 sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff); |
| 135 } |
| 136 sqlite3StrAccumAppend(&out, "'", 1); |
| 137 } |
| 138 } |
| 139 return sqlite3StrAccumFinish(&out); |
| 140 } |
| 141 |
| 142 #endif /* #ifndef SQLITE_OMIT_TRACE */ |
OLD | NEW |