15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2009 November 25
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The author disclaims copyright to this source code.  In place of
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a legal notice, here is a blessing:
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you do good and not evil.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you find forgiveness for yourself and forgive others.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you share freely, never taking more than you give.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*************************************************************************
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This file contains code used to insert the values of host parameters
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** (aka "wildcards") into the SQL text output by sqlite3_trace().
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sqliteInt.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "vdbeInt.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_OMIT_TRACE
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** zSql is a zero-terminated string of UTF-8 SQL text.  Return the number of
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** bytes in this text up to but excluding the first character in
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a host parameter.  If the text contains no host parameters, return
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the total number of bytes in the text.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int findNextHostParameter(const char *zSql, int *pnToken){
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tokenType;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nTotal = 0;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pnToken = 0;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( zSql[0] ){
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n = sqlite3GetToken((u8*)zSql, &tokenType);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( n>0 && tokenType!=TK_ILLEGAL );
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( tokenType==TK_VARIABLE ){
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *pnToken = n;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nTotal += n;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zSql += n;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return nTotal;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This function returns a pointer to a nul-terminated string in memory
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** string contains a copy of zRawSql but with host parameters expanded to
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** then the returned string holds a copy of zRawSql with "-- " prepended
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to each line of text.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The calling function is responsible for making sure the memory returned
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is eventually freed.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** ALGORITHM:  Scan the input string looking for host parameters in any of
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** these forms:  ?, ?N, $A, @A, :A.  Take care to avoid text within
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** string literals, quoted identifier names, and comments.  For text forms,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the host parameter index is found by scanning the perpared
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** statement for the corresponding OP_Variable opcode.  Once the host
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** parameter index is known, locate the value in p->aVar[].  Then render
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the value as a literal in place of the host parameter name.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)char *sqlite3VdbeExpandSql(
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Vdbe *p,                 /* The prepared statement being evaluated */
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zRawSql      /* Raw text of the SQL statement */
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db;             /* The database connection */
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int idx = 0;             /* Index of a host parameter */
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nextIndex = 1;       /* Index of next ? host parameter */
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n;                   /* Length of a token prefix */
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nToken;              /* Length of the parameter token */
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;                   /* Loop counter */
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mem *pVar;               /* Value of a host parameter */
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StrAccum out;            /* Accumulate the output here */
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char zBase[100];         /* Initial working space */
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db = p->db;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3StrAccumInit(&out, zBase, sizeof(zBase),
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      db->aLimit[SQLITE_LIMIT_LENGTH]);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out.db = db;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( db->vdbeExecCnt>1 ){
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( *zRawSql ){
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const char *zStart = zRawSql;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while( *(zRawSql++)!='\n' && *zRawSql );
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3StrAccumAppend(&out, "-- ", 3);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( zRawSql[0] ){
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      n = findNextHostParameter(zRawSql, &nToken);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( n>0 );
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3StrAccumAppend(&out, zRawSql, n);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zRawSql += n;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( zRawSql[0] || nToken==0 );
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( nToken==0 ) break;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( zRawSql[0]=='?' ){
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if( nToken>1 ){
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          assert( sqlite3Isdigit(zRawSql[1]) );
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sqlite3GetInt32(&zRawSql[1], &idx);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }else{
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          idx = nextIndex;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else{
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        testcase( zRawSql[0]==':' );
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        testcase( zRawSql[0]=='$' );
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        testcase( zRawSql[0]=='@' );
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert( idx>0 );
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zRawSql += nToken;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      nextIndex = idx + 1;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( idx>0 && idx<=p->nVar );
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pVar = &p->aVar[idx-1];
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( pVar->flags & MEM_Null ){
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sqlite3StrAccumAppend(&out, "NULL", 4);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else if( pVar->flags & MEM_Int ){
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sqlite3XPrintf(&out, "%lld", pVar->u.i);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else if( pVar->flags & MEM_Real ){
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sqlite3XPrintf(&out, "%!.15g", pVar->r);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else if( pVar->flags & MEM_Str ){
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_OMIT_UTF16
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u8 enc = ENC(db);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if( enc!=SQLITE_UTF8 ){
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Mem utf8;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          memset(&utf8, 0, sizeof(utf8));
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          utf8.db = db;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sqlite3VdbeMemRelease(&utf8);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }else
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else if( pVar->flags & MEM_Zero ){
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else{
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert( pVar->flags & MEM_Blob );
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sqlite3StrAccumAppend(&out, "x'", 2);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for(i=0; i<pVar->n; i++){
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sqlite3StrAccumAppend(&out, "'", 1);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sqlite3StrAccumFinish(&out);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* #ifndef SQLITE_OMIT_TRACE */
155