1
0
mirror of https://github.com/sqlite/sqlite.git synced 2026-10-23 21:49:02 +03:00
Files
sqlite/test/reprepare.test
dan e037ddd700 Avoid ever repreparing a statement if a call to sqlite3_bind_int64() does not actually change the bound value.
FossilOrigin-Name: 4708cfe5f7fe1874870564956f0f81ba79226657c6d07ea1edffba7d5a6e4e3b
2026-10-12 14:05:08 +00:00

158 lines
4.3 KiB
Plaintext

# 2026 October 12
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# Specifically, it tests that statements that should only be reprepared
# when a bound variable is changed to or from a small integer value
# (0 or 1), really is only reprepared in those cases.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix reprepare
do_execsql_test 1.0 {
CREATE TABLE t1(id INTEGER PRIMARY KEY, nm TEXT);
INSERT INTO t1 VALUES(4294967296,'a'), (4294967297,'b');
}
proc do_reprepare_count_test {tn sql lInt nReprepare} {
set stmt [sqlite3_prepare_v2 db $sql -1 dummy]
foreach ii $lInt {
set ii [expr $ii]
sqlite3_bind_int64 $stmt 1 $ii
sqlite3_step $stmt
sqlite3_reset $stmt
}
do_test $tn [list \
sqlite3_stmt_status $stmt SQLITE_STMTSTATUS_REPREPARE 0
] [list $nReprepare]
sqlite3_finalize $stmt
}
do_reprepare_count_test 1.1 {
SELECT * FROM t1 WHERE +t1.id=?1
} {4294967296 4294967297 4294967296 4294967297} 0
do_reprepare_count_test 1.2 {
SELECT a.nm, b.nm FROM t1 a, t1 b WHERE a.id=?1 AND b.id=a.id
} {4294967296 4294967297 4294967296 4294967297} 0
proc do_reprepare_test {tn sql lTest} {
set stmt [sqlite3_prepare_v2 db $sql -1 dummy]
set cnt 0
foreach {t res} $lTest {
incr cnt
eval $t
sqlite3_step $stmt
sqlite3_reset $stmt
do_test $tn.$cnt [list \
sqlite3_stmt_status $stmt SQLITE_STMTSTATUS_REPREPARE 1
] [list $res]
}
sqlite3_finalize $stmt
}
do_reprepare_test 1.3 {
SELECT a.nm, b.nm FROM t1 a, t1 b WHERE a.id=?1 AND b.id=a.id
} {
{ sqlite3_bind_int64 $stmt 1 45 } 0
{ sqlite3_bind_int64 $stmt 1 0 } 1
{ sqlite3_bind_int64 $stmt 1 1 } 0
{ sqlite3_bind_int64 $stmt 1 101 } 1
{ sqlite3_bind_null $stmt 1 } 0
{ sqlite3_bind_text $stmt 1 hello -1 } 0
{ sqlite3_bind_int64 $stmt 1 1 } 1
{ sqlite3_bind_text $stmt 1 world -1 } 1
{ sqlite3_bind_int64 $stmt 1 450 } 0
{ sqlite3_bind_int64 $stmt 1 0 } 1
{ sqlite3_bind_null $stmt 1 } 1
{ sqlite3_bind_int64 $stmt 1 0 } 1
{ sqlite3_bind_int64 $stmt 1 1 } 0
{ sqlite3_bind_int64 $stmt 1 2 } 1
}
do_reprepare_test 1.4 {
SELECT * FROM t1 LIMIT ?1
} {
{ sqlite3_bind_int64 $stmt 1 12 } 1
{ sqlite3_bind_int64 $stmt 1 12 } 0
{ sqlite3_bind_int64 $stmt 1 13 } 1
{ sqlite3_bind_int64 $stmt 1 13 } 0
{ sqlite3_bind_int64 $stmt 1 14 } 1
}
#-------------------------------------------------------------------------
# Test that if a variable is used both in a context where only a change
# to or from a small integer requires a reprepare (an equality comparison)
# and in a context where any change requires a reprepare (a LIMIT clause),
# the statement is reprepared every time a new value is bound.
#
do_execsql_test 2.0 {
CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
WITH s(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<10)
INSERT INTO t2 SELECT i, i FROM s;
}
proc do_limit_test {tn sql lTest} {
set stmt [sqlite3_prepare_v2 db $sql -1 dummy]
set cnt 0
foreach {val res} $lTest {
incr cnt
sqlite3_bind_int64 $stmt 1 $val
set nRow 0
while {[sqlite3_step $stmt]=="SQLITE_ROW"} { incr nRow }
sqlite3_reset $stmt
do_test $tn.$cnt [list set {} $nRow] [list $res]
}
sqlite3_finalize $stmt
}
do_limit_test 2.1 {
SELECT b.x FROM t2 a, t2 b WHERE a.x=?1 AND b.x>=a.x LIMIT ?1
} {
2 2 3 3 0 0 4 4 6 5 1 1 5 5 7 4 4 4
}
#-------------------------------------------------------------------------
# Test case from https://sqlite.org/bugs/info/2026-10-11T16:09:34Z
#
reset_db
do_execsql_test 3.0 {
CREATE TABLE t(k INT, v INT);
WITH RECURSIVE c(x) AS (SELECT 0 UNION ALL SELECT x+1 FROM c WHERE x<399)
INSERT INTO t SELECT x%10, x FROM c;
}
set V [list 1 5 7 9]
for {set ii 0} {$ii < 4} {incr ii} {
set val [expr [lindex $V $ii]]
do_test 3.1.$ii {
set cnt 0
db eval {
SELECT x.v FROM t x, t y WHERE x.k=$val AND y.v=x.v LIMIT $val
} {
incr cnt
}
set cnt
} $val
}
finish_test