Annotation of embedaddon/sqlite3/src/vdbetrace.c, revision 1.1
1.1 ! misho 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>