Simplifications to the sqlite3_trace() bound parameter substitution logic.

FossilOrigin-Name: cb4b928648504ce29d751834e9ee3b5278dfca65
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 3adba1c..334a39a 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -2961,6 +2961,7 @@
 int sqlite3VtabBegin(sqlite3 *, VTable *);
 FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
 void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
+int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
 int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
 int sqlite3Reprepare(Vdbe*);
 void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 8bf3024..a866708 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -1120,8 +1120,7 @@
 ** with that name.  If there is no variable with the given name,
 ** return 0.
 */
-int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
-  Vdbe *p = (Vdbe*)pStmt;
+int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){
   int i;
   if( p==0 ){
     return 0;
@@ -1130,13 +1129,16 @@
   if( zName ){
     for(i=0; i<p->nVar; i++){
       const char *z = p->azVar[i];
-      if( z && strcmp(z,zName)==0 ){
+      if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){
         return i+1;
       }
     }
   }
   return 0;
 }
+int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
+  return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName));
+}
 
 /*
 ** Transfer all bindings from the first statement over to the second.
diff --git a/src/vdbetrace.c b/src/vdbetrace.c
index e788a33..4da8816 100644
--- a/src/vdbetrace.c
+++ b/src/vdbetrace.c
@@ -24,15 +24,19 @@
 ** a host parameter.  If the text contains no host parameters, return
 ** the total number of bytes in the text.
 */
-static int findNextHostParameter(const char *zSql){
+static int findNextHostParameter(const char *zSql, int *pnToken){
   int tokenType;
   int nTotal = 0;
   int n;
 
+  *pnToken = 0;
   while( zSql[0] ){
     n = sqlite3GetToken((u8*)zSql, &tokenType);
     assert( n>0 && tokenType!=TK_ILLEGAL );
-    if( tokenType==TK_VARIABLE ) break;
+    if( tokenType==TK_VARIABLE ){
+      *pnToken = n;
+      break;
+    }
     nTotal += n;
     zSql += n;
   }
@@ -40,9 +44,9 @@
 }
 
 /*
-** Return a pointer to a string in memory obtained form sqlite3Malloc() which
+** Return a pointer to a string in memory obtained form sqlite3DbMalloc() which
 ** holds a copy of zRawSql but with host parameters expanded to their
-** current values.
+** current bindings.
 **
 ** The calling function is responsible for making sure the memory returned
 ** is eventually freed.
@@ -63,10 +67,9 @@
   int idx;                 /* Index of a host parameter */
   int nextIndex = 1;       /* Index of next ? host parameter */
   int n;                   /* Length of a token prefix */
+  int nToken;              /* Length of the parameter token */
   int i;                   /* Loop counter */
-  int dummy;               /* For holding a unused return value */
   Mem *pVar;               /* Value of a host parameter */
-  VdbeOp *pOp;             /* For looping over opcodes */
   StrAccum out;            /* Accumulate the output here */
   char zBase[100];         /* Initial working space */
 
@@ -75,19 +78,16 @@
                       db->aLimit[SQLITE_LIMIT_LENGTH]);
   out.db = db;
   while( zRawSql[0] ){
-    n = findNextHostParameter(zRawSql);
+    n = findNextHostParameter(zRawSql, &nToken);
     assert( n>0 );
     sqlite3StrAccumAppend(&out, zRawSql, n);
     zRawSql += n;
-    if( zRawSql[0]==0 ) break;
+    assert( zRawSql[0] || nToken==0 );
+    if( nToken==0 ) break;
     if( zRawSql[0]=='?' ){
-      zRawSql++;
-      if( sqlite3Isdigit(zRawSql[0]) ){
-        idx = 0;
-        while( sqlite3Isdigit(zRawSql[0]) ){
-          idx = idx*10 + zRawSql[0] - '0';
-          zRawSql++;
-        }
+      if( nToken>1 ){
+        assert( sqlite3Isdigit(zRawSql[1]) );
+        sqlite3GetInt32(&zRawSql[1], &idx);
       }else{
         idx = nextIndex;
       }
@@ -96,20 +96,10 @@
       testcase( zRawSql[0]==':' );
       testcase( zRawSql[0]=='$' );
       testcase( zRawSql[0]=='@' );
-      n = sqlite3GetToken((u8*)zRawSql, &dummy);
-      idx = 0;
-      for(i=0, pOp=p->aOp; ALWAYS(i<p->nOp); i++, pOp++){
-        if( pOp->opcode!=OP_Variable ) continue;
-        if( pOp->p3>1 ) continue;
-        if( pOp->p4.z==0 ) continue;
-        if( memcmp(pOp->p4.z, zRawSql, n)==0 && pOp->p4.z[n]==0 ){
-          idx = pOp->p1;
-          break;
-        }
-      }
+      idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
       assert( idx>0 );
-      zRawSql += n;
     }
+    zRawSql += nToken;
     nextIndex = idx + 1;
     assert( idx>0 && idx<=p->nVar );
     pVar = &p->aVar[idx-1];
@@ -121,11 +111,12 @@
       sqlite3XPrintf(&out, "%!.15g", pVar->r);
     }else if( pVar->flags & MEM_Str ){
 #ifndef SQLITE_OMIT_UTF16
-      if( ENC(db)!=SQLITE_UTF8 ){
+      u8 enc = ENC(db);
+      if( enc!=SQLITE_UTF8 ){
         Mem utf8;
         memset(&utf8, 0, sizeof(utf8));
         utf8.db = db;
-        sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, ENC(db), SQLITE_STATIC);
+        sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
         sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
         sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
         sqlite3VdbeMemRelease(&utf8);