Improve generate_series so that it handles constraints that compare

the "value" output against a string or blob.
[bugs:/info/2026-10-26T12:55:22Z|Bug 2026-10-26T12:55:22Z]

FossilOrigin-Name: 6b66b52ab29511e0e9d775892bad4eb0b29a5d25289feeaed2eafe004e1e920a
This commit is contained in:
drh committed 2026-10-27 18:46:26 +00:00
1 parent 7721051f69
commit e5796f671a
4 files changed
+77 -11

No files matched your search

+23 -3
View File
@@ -411,6 +411,13 @@ static sqlite3_int64 seriesRealToI64(double r){
return (sqlite3_int64)r;
}
/* Return true if the type of the value is TEXT or BLOB.
*/
static int seriesIsTextOrBlob(sqlite3_value *pVal){
int eType = sqlite3_value_type(pVal);
return eType==SQLITE_TEXT || eType==SQLITE_BLOB;
}
/*
** This method is called to "rewind" the series_cursor object back
** to the first row of output. This method is always called at least
@@ -525,10 +532,19 @@ static int seriesFilter(
/* Narrow the range of iMin and iMax (the minimum and maximum outputs)
** based on equality and inequality constraints on the "value" column.
**
** The "value" column has no affinity, so a TEXT or BLOB operand X is
** not converted into a number. Every INTEGER is less than any TEXT
** or BLOB, so "value=X", "value>X" and "value>=X" are never true and
** "value<X" and "value<=X" are always true. The type must be checked
** before sqlite3_value_numeric_type(), which would convert a TEXT
** value such as '3' into a number.
*/
if( idxNum & 0x3380 ){
if( idxNum & 0x0080 ){ /* value=X */
if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
if( seriesIsTextOrBlob(argv[iArg]) ){
goto series_no_rows;
}else if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[iArg++]);
if( r==seriesCeil(r)
&& r>=(double)SMALLEST_INT64
@@ -543,7 +559,9 @@ static int seriesFilter(
}
}else{
if( idxNum & 0x0300 ){ /* value>X (0x200) or value>=X (0x100) */
if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
if( seriesIsTextOrBlob(argv[iArg]) ){
goto series_no_rows;
}else if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[iArg++]);
if( r<=(double)SMALLEST_INT64 ){
iMin = SMALLEST_INT64;
@@ -568,7 +586,9 @@ static int seriesFilter(
}
}
if( idxNum & 0x3000 ){ /* value<X (0x2000) or value<=X (0x1000) */
if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
if( seriesIsTextOrBlob(argv[iArg]) ){
iArg++; /* No upper bound */
}else if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[iArg++]);
if( r>=(double)LARGEST_INT64 ){
iMax = LARGEST_INT64;
+7 -7
View File
@@ -1,5 +1,5 @@
C Fix\sa\sproblem\sintroduced\sby\s[08e979525ff1eef8]\sand\sreported\sby\n[bugs:/forumpost/70e3174f54|a\sfollow-up\scomment]\sto\sthe\soriginal\sbug\sreport.
D 2026-10-27T18:26:34.914
C Improve\sgenerate_series\sso\sthat\sit\shandles\sconstraints\sthat\scompare\nthe\s"value"\soutput\sagainst\sa\sstring\sor\sblob.\n[bugs:/info/2026-10-26T12:55:22Z|Bug\s2026-10-26T12:55:22Z]
D 2026-10-27T18:46:26.698
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -399,7 +399,7 @@ F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e
F ext/misc/regexp.c 8be28c2515c69e5d4e4cba7fa6f1d3b315b822534e4587477a91ab3fbdd4d568
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/series.c 3296d04bc84a64848c3abea7b9a152cb8dd198f23f71b6ee28c3fa22ca5f8746
F ext/misc/series.c c60c298e0f0387c46dbe32bf6917f99c5040b4e8d580ccda90ff4468b1b9fa1e
F ext/misc/sha1.c c279eaae2d203be3443f9e3052401d15dc98bd43aa389d4e234ab0e295b4a04b
F ext/misc/shathree.c e40d4239d522946f6c9821a2244907ae8288ae45a8c8ed979b62e83979666a6d
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
@@ -1801,7 +1801,7 @@ F test/sync.test a619e407ede58a7b6e3e44375328628559fc9695a9c24c47cb5690a866b0031
F test/sync2.test 06152269ed73128782c450c355988fe8dd794d305833af75e1a5e79edd4dae47
F test/syscall.test a067468b43b8cb2305e9f9fe414e5f40c875bb5d2cba5f00b8154396e95fcf37
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
F test/tabfunc01.test 9840707afb06ee6ab0fdcf45909cd1b5070e55354cd9b97e847068a46565fd91
F test/tabfunc01.test a7cf99dfcf8faa89e149802e034453b2fb9f6c087b46571d442c616035b8e657
F test/table.test e87294bf1c80bfd7792142b84ab32ea5beb4f3f71e535d7fb263a6b2068377bf
F test/tableapi.test e37c33e6be2276e3a96bb54b00eea7f321277115d10e5b30fdb52a112b432750
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
@@ -2303,8 +2303,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
P c5f98a311e26856611f841a7938f92a327c21cc9d89661c6e894d6e77fe98629
R 6e404586829ec2e4939045d3d7d36228
P 6be81afa66f131d7efe59a24a693e738b0d48f82831ce2e0003dc4e4186fa980
R 46e5b8a20bc0e4ec42ae9fe822aeed79
U drh
Z 494d7750e0fd7ed7a5d2150383d04b42
Z 7540b6214bf2a68e19f45dac789e7e10
# Remove this line to create a well-formed Fossil manifest.
+1 -1
View File
@@ -1 +1 @@
6be81afa66f131d7efe59a24a693e738b0d48f82831ce2e0003dc4e4186fa980
6b66b52ab29511e0e9d775892bad4eb0b29a5d25289feeaed2eafe004e1e920a
+46
View File
@@ -806,6 +806,52 @@ do_execsql_test 1530 {
SELECT value FROM generate_series(1,10) ORDER BY value DESC LIMIT 3;
} {10 9 8}
# Bug 2026-10-26T12:55:22Z
#
# The "value" column has no affinity, so a TEXT or BLOB operand in a
# constraint on "value" must not be converted into a number. Every
# INTEGER is less than every TEXT or BLOB.
#
do_execsql_test 1540 {
SELECT value FROM generate_series(1,10) WHERE value='3';
} {}
do_execsql_test 1541 {
SELECT value FROM generate_series(1,10) WHERE value>='3';
} {}
do_execsql_test 1542 {
SELECT value FROM generate_series(1,10) WHERE value>'3.5';
} {}
do_execsql_test 1543 {
SELECT value FROM generate_series(1,10) WHERE value<'5';
} {1 2 3 4 5 6 7 8 9 10}
do_execsql_test 1544 {
SELECT value FROM generate_series(1,10) WHERE value<='a';
} {1 2 3 4 5 6 7 8 9 10}
do_execsql_test 1545 {
SELECT value FROM generate_series(1,10) WHERE value>x'00';
} {}
do_execsql_test 1546 {
SELECT value FROM generate_series(1,10) WHERE value=x'33';
} {}
do_execsql_test 1547 {
SELECT value FROM generate_series(1,10) WHERE value>3 AND value<'5';
} {4 5 6 7 8 9 10}
do_execsql_test 1548 {
SELECT value FROM generate_series(10,1,-1) WHERE value<'5' AND value>=7;
} {10 9 8 7}
do_execsql_test 1549 {
SELECT value FROM generate_series(1,10) WHERE value IN ('3',4,'5');
} {4}
do_execsql_test 1550 {
CREATE TABLE t1550(x);
INSERT INTO t1550 VALUES('3'),(3),(x'33'),(3.0);
SELECT quote(x), value FROM t1550 CROSS JOIN generate_series(1,10)
WHERE value=t1550.x;
} {3 3 3.0 3}
do_execsql_test 1551 {
SELECT value, value='3' FROM generate_series(3,3);
} {3 0}
#------------------------------------------------------------------------
#
ifcapable json1 {