SQLite

Check-in [e6808c988c]
Login

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

Overview
Comment:Fix cases where modifying bound variables using the clear_bindings() or transfer_bindings() APIs can invalidate a query plan.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e6808c988c9cd7b2db23f18b5fe2177151b6f586
User & Date: dan 2009-10-20 07:01:24.000
Context
2009-10-20
14:08
Update documentation on the sqlite3_prepare_v2() interface. No changes to code. (check-in: 3b00e769cd user: drh tags: trunk)
07:01
Fix cases where modifying bound variables using the clear_bindings() or transfer_bindings() APIs can invalidate a query plan. (check-in: e6808c988c user: dan tags: trunk)
2009-10-19
22:41
Remove an unreachable condition in the WHERE clause processing of bound parameters and replace it with an assert(), for test coverage. (check-in: 3bcd78a1d7 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/vdbeapi.c.
94
95
96
97
98
99
100



101
102
103
104
105
106
107
#if SQLITE_THREADSAFE
  sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex;
#endif
  sqlite3_mutex_enter(mutex);
  for(i=0; i<p->nVar; i++){
    sqlite3VdbeMemRelease(&p->aVar[i]);
    p->aVar[i].flags = MEM_Null;



  }
  sqlite3_mutex_leave(mutex);
  return rc;
}


/**************************** sqlite3_value_  *******************************







>
>
>







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#if SQLITE_THREADSAFE
  sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex;
#endif
  sqlite3_mutex_enter(mutex);
  for(i=0; i<p->nVar; i++){
    sqlite3VdbeMemRelease(&p->aVar[i]);
    p->aVar[i].flags = MEM_Null;
  }
  if( p->isPrepareV2 && p->expmask ){
    p->expired = 1;
  }
  sqlite3_mutex_leave(mutex);
  return rc;
}


/**************************** sqlite3_value_  *******************************
1168
1169
1170
1171
1172
1173
1174






1175
1176
1177
1178
1179
1180
1181
** SQLITE_OK is returned.
*/
int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
  Vdbe *pFrom = (Vdbe*)pFromStmt;
  Vdbe *pTo = (Vdbe*)pToStmt;
  if( pFrom->nVar!=pTo->nVar ){
    return SQLITE_ERROR;






  }
  return sqlite3TransferBindings(pFromStmt, pToStmt);
}
#endif

/*
** Return the sqlite3* database handle to which the prepared statement given







>
>
>
>
>
>







1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
** SQLITE_OK is returned.
*/
int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
  Vdbe *pFrom = (Vdbe*)pFromStmt;
  Vdbe *pTo = (Vdbe*)pToStmt;
  if( pFrom->nVar!=pTo->nVar ){
    return SQLITE_ERROR;
  }
  if( pTo->isPrepareV2 && pTo->expmask ){
    pTo->expired = 1;
  }
  if( pFrom->isPrepareV2 && pFrom->expmask ){
    pFrom->expired = 1;
  }
  return sqlite3TransferBindings(pFromStmt, pToStmt);
}
#endif

/*
** Return the sqlite3* database handle to which the prepared statement given
Changes to test/analyze3.test.
36
37
38
39
40
41
42




43
44
45
46
47
48
49
# analyze3-3.*: Test that binding to a variable does not invalidate the 
#               query plan when there is no way in which replanning the
#               query may produce a superior outcome.
#
# analyze3-4.*: Test that SQL or authorization callback errors occuring
#               within sqlite3Reprepare() are handled correctly.
#





proc getvar {varname} { uplevel #0 set $varname }
db function var getvar

proc eqp {sql {db db}} {
  uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db
}







>
>
>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# analyze3-3.*: Test that binding to a variable does not invalidate the 
#               query plan when there is no way in which replanning the
#               query may produce a superior outcome.
#
# analyze3-4.*: Test that SQL or authorization callback errors occuring
#               within sqlite3Reprepare() are handled correctly.
#
# analyze3-5.*: Check that the query plans of applicable statements are
#               invalidated if the values of SQL parameter are modified
#               using the clear_bindings() or transfer_bindings() APIs.
#

proc getvar {varname} { uplevel #0 set $varname }
db function var getvar

proc eqp {sql {db db}} {
  uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db
}
522
523
524
525
526
527
528

529

































































530

  execsql { CREATE TABLE t2(d, e, f) }
  db auth auth
  sqlite3_step $S
} {SQLITE_SCHEMA}
do_test analyze3-4.3.2 {
  sqlite3_finalize $S
} {SQLITE_SCHEMA}



































































finish_test








>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  execsql { CREATE TABLE t2(d, e, f) }
  db auth auth
  sqlite3_step $S
} {SQLITE_SCHEMA}
do_test analyze3-4.3.2 {
  sqlite3_finalize $S
} {SQLITE_SCHEMA}
db auth {}

#-------------------------------------------------------------------------
# Test that modifying bound variables using the clear_bindings() or
# transfer_bindings() APIs works.
#
#   analyze3-5.1.*: sqlite3_clear_bindings()
#   analyze3-5.2.*: sqlite3_transfer_bindings()
#
do_test analyze3-5.1.1 {
  drop_all_tables
  execsql {
    CREATE TABLE t1(x TEXT COLLATE NOCASE);
    CREATE INDEX i1 ON t1(x);
    INSERT INTO t1 VALUES('aaa');
    INSERT INTO t1 VALUES('abb');
    INSERT INTO t1 VALUES('acc');
    INSERT INTO t1 VALUES('baa');
    INSERT INTO t1 VALUES('bbb');
    INSERT INTO t1 VALUES('bcc');
  }

  set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE x LIKE ?" -1 dummy]
  sqlite3_bind_text $S 1 "a%" 2
  set R [list]
  while { "SQLITE_ROW" == [sqlite3_step $S] } {
    lappend R [sqlite3_column_text $S 0]
  }
  concat [sqlite3_reset $S] $R
} {SQLITE_OK aaa abb acc}
do_test analyze3-5.1.2 {
  sqlite3_clear_bindings $S
  set R [list]
  while { "SQLITE_ROW" == [sqlite3_step $S] } {
    lappend R [sqlite3_column_text $S 0]
  }
  concat [sqlite3_reset $S] $R
} {SQLITE_OK}
do_test analyze3-5.1.3 {
  sqlite3_finalize $S
} {SQLITE_OK}

do_test analyze3-5.1.1 {
  set S1 [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE x LIKE ?" -1 dummy]
  sqlite3_bind_text $S1 1 "b%" 2
  set R [list]
  while { "SQLITE_ROW" == [sqlite3_step $S1] } {
    lappend R [sqlite3_column_text $S1 0]
  }
  concat [sqlite3_reset $S1] $R
} {SQLITE_OK baa bbb bcc}

do_test analyze3-5.1.2 {
  set S2 [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE x = ?" -1 dummy]
  sqlite3_bind_text $S2 1 "a%" 2
  sqlite3_transfer_bindings $S2 $S1
  set R [list]
  while { "SQLITE_ROW" == [sqlite3_step $S1] } {
    lappend R [sqlite3_column_text $S1 0]
  }
  concat [sqlite3_reset $S1] $R
} {SQLITE_OK aaa abb acc}
do_test analyze3-5.1.3 {
  sqlite3_finalize $S2
  sqlite3_finalize $S1
} {SQLITE_OK}

finish_test