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