/ Check-in [cb4b9286]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Simplifications to the sqlite3_trace() bound parameter substitution logic.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: cb4b928648504ce29d751834e9ee3b5278dfca65
User & Date: drh 2009-11-26 14:01:53
Context
2009-11-27
12:12
Move [7d30880114] to the trunk. Add optimizations to reduce the number of opcodes used for BEFORE UPDATE triggers. check-in: 1b7c5250 user: dan tags: trunk
2009-11-26
14:01
Simplifications to the sqlite3_trace() bound parameter substitution logic. check-in: cb4b9286 user: drh tags: trunk
2009-11-25
22:42
Make sure the new fts3Int.h header file is added to the amalgamation. check-in: f25558f3 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/sqliteInt.h.

2957
2958
2959
2960
2961
2962
2963

2964
2965
2966
2967
2968
2969
2970
void sqlite3VtabArgExtend(Parse*, Token*);
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, VTable *);
FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);

int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
int sqlite3Reprepare(Vdbe*);
void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
int sqlite3TempInMemory(const sqlite3*);
VTable *sqlite3GetVTable(sqlite3*, Table*);








>







2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
void sqlite3VtabArgExtend(Parse*, Token*);
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
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*);
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
int sqlite3TempInMemory(const sqlite3*);
VTable *sqlite3GetVTable(sqlite3*, Table*);

Changes to src/vdbeapi.c.

1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139



1140
1141
1142
1143
1144
1145
1146
}

/*
** Given a wildcard parameter name, return the index of the variable
** 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 i;
  if( p==0 ){
    return 0;
  }
  createVarMap(p); 
  if( zName ){
    for(i=0; i<p->nVar; i++){
      const char *z = p->azVar[i];
      if( z && strcmp(z,zName)==0 ){
        return i+1;
      }
    }
  }
  return 0;
}




/*
** Transfer all bindings from the first statement over to the second.
*/
int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
  Vdbe *pFrom = (Vdbe*)pFromStmt;
  Vdbe *pTo = (Vdbe*)pToStmt;







|
<








|






>
>
>







1116
1117
1118
1119
1120
1121
1122
1123

1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
}

/*
** Given a wildcard parameter name, return the index of the variable
** with that name.  If there is no variable with the given name,
** return 0.
*/
int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){

  int i;
  if( p==0 ){
    return 0;
  }
  createVarMap(p); 
  if( zName ){
    for(i=0; i<p->nVar; i++){
      const char *z = p->azVar[i];
      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.
*/
int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
  Vdbe *pFrom = (Vdbe*)pFromStmt;
  Vdbe *pTo = (Vdbe*)pToStmt;

Changes to src/vdbetrace.c.

20
21
22
23
24
25
26
27
28
29
30
31

32
33
34
35



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
..
59
60
61
62
63
64
65

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

82
83
84

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

124
125
126
127
128
129
130
131
132
133
134
135

/*
** zSql is a zero-terminated string of UTF-8 SQL text.  Return the number of
** bytes in this text up to but excluding the first character in
** 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){
  int tokenType;
  int nTotal = 0;
  int n;


  while( zSql[0] ){
    n = sqlite3GetToken((u8*)zSql, &tokenType);
    assert( n>0 && tokenType!=TK_ILLEGAL );
    if( tokenType==TK_VARIABLE ) break;



    nTotal += n;
    zSql += n;
  }
  return nTotal;
}

/*
** Return a pointer to a string in memory obtained form sqlite3Malloc() which
** holds a copy of zRawSql but with host parameters expanded to their
** current values.
**
** The calling function is responsible for making sure the memory returned
** is eventually freed.
**
** ALGORITHM:  Scan the input string looking for host parameters in any of
** these forms:  ?, ?N, $A, @A, :A.  Take care to avoid text within
** string literals, quoted identifier names, and comments.  For text forms,
................................................................................
  Vdbe *p,                 /* The prepared statement being evaluated */
  const char *zRawSql      /* Raw text of the SQL statement */
){
  sqlite3 *db;             /* The database connection */
  int idx;                 /* Index of a host parameter */
  int nextIndex = 1;       /* Index of next ? host parameter */
  int n;                   /* Length of a token prefix */

  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 */

  db = p->db;
  sqlite3StrAccumInit(&out, zBase, sizeof(zBase), 
                      db->aLimit[SQLITE_LIMIT_LENGTH]);
  out.db = db;
  while( zRawSql[0] ){
    n = findNextHostParameter(zRawSql);
    assert( n>0 );
    sqlite3StrAccumAppend(&out, zRawSql, n);
    zRawSql += n;

    if( zRawSql[0]==0 ) break;
    if( zRawSql[0]=='?' ){
      zRawSql++;

      if( sqlite3Isdigit(zRawSql[0]) ){
        idx = 0;
        while( sqlite3Isdigit(zRawSql[0]) ){
          idx = idx*10 + zRawSql[0] - '0';
          zRawSql++;
        }
      }else{
        idx = nextIndex;
      }
    }else{
      assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
      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;
        }
      }
      assert( idx>0 );
      zRawSql += n;
    }
    nextIndex = idx + 1;
    assert( idx>0 && idx<=p->nVar );
    pVar = &p->aVar[idx-1];
    if( pVar->flags & MEM_Null ){
      sqlite3StrAccumAppend(&out, "NULL", 4);
    }else if( pVar->flags & MEM_Int ){
      sqlite3XPrintf(&out, "%lld", pVar->u.i);
    }else if( pVar->flags & MEM_Real ){
      sqlite3XPrintf(&out, "%!.15g", pVar->r);
    }else if( pVar->flags & MEM_Str ){
#ifndef SQLITE_OMIT_UTF16

      if( ENC(db)!=SQLITE_UTF8 ){
        Mem utf8;
        memset(&utf8, 0, sizeof(utf8));
        utf8.db = db;
        sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, ENC(db), SQLITE_STATIC);
        sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
        sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
        sqlite3VdbeMemRelease(&utf8);
      }else
#endif
      {
        sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);







|




>



|
>
>
>







|

|







 







>

<

<








|



>
|

<
>
|
<
|
<
<
<








|
|
<
<
<
<
<
<
<
|
<
<
|
<











>
|



|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
..
63
64
65
66
67
68
69
70
71

72

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

88
89

90



91
92
93
94
95
96
97
98
99
100







101


102

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

/*
** zSql is a zero-terminated string of UTF-8 SQL text.  Return the number of
** bytes in this text up to but excluding the first character in
** 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, 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 ){
      *pnToken = n;
      break;
    }
    nTotal += n;
    zSql += n;
  }
  return nTotal;
}

/*
** 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 bindings.
**
** The calling function is responsible for making sure the memory returned
** is eventually freed.
**
** ALGORITHM:  Scan the input string looking for host parameters in any of
** these forms:  ?, ?N, $A, @A, :A.  Take care to avoid text within
** string literals, quoted identifier names, and comments.  For text forms,
................................................................................
  Vdbe *p,                 /* The prepared statement being evaluated */
  const char *zRawSql      /* Raw text of the SQL statement */
){
  sqlite3 *db;             /* The database connection */
  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 */

  Mem *pVar;               /* Value of a host parameter */

  StrAccum out;            /* Accumulate the output here */
  char zBase[100];         /* Initial working space */

  db = p->db;
  sqlite3StrAccumInit(&out, zBase, sizeof(zBase), 
                      db->aLimit[SQLITE_LIMIT_LENGTH]);
  out.db = db;
  while( zRawSql[0] ){
    n = findNextHostParameter(zRawSql, &nToken);
    assert( n>0 );
    sqlite3StrAccumAppend(&out, zRawSql, n);
    zRawSql += n;
    assert( zRawSql[0] || nToken==0 );
    if( nToken==0 ) break;
    if( zRawSql[0]=='?' ){

      if( nToken>1 ){
        assert( sqlite3Isdigit(zRawSql[1]) );

        sqlite3GetInt32(&zRawSql[1], &idx);



      }else{
        idx = nextIndex;
      }
    }else{
      assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
      testcase( zRawSql[0]==':' );
      testcase( zRawSql[0]=='$' );
      testcase( zRawSql[0]=='@' );
      idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
      assert( idx>0 );







    }


    zRawSql += nToken;

    nextIndex = idx + 1;
    assert( idx>0 && idx<=p->nVar );
    pVar = &p->aVar[idx-1];
    if( pVar->flags & MEM_Null ){
      sqlite3StrAccumAppend(&out, "NULL", 4);
    }else if( pVar->flags & MEM_Int ){
      sqlite3XPrintf(&out, "%lld", pVar->u.i);
    }else if( pVar->flags & MEM_Real ){
      sqlite3XPrintf(&out, "%!.15g", pVar->r);
    }else if( pVar->flags & MEM_Str ){
#ifndef SQLITE_OMIT_UTF16
      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, SQLITE_STATIC);
        sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
        sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
        sqlite3VdbeMemRelease(&utf8);
      }else
#endif
      {
        sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);