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>