Compare commits
238 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f61e13f72 | |||
| 5c8b293c75 | |||
| df5e9e977b | |||
| 04de790b09 | |||
| 83dca19e9f | |||
| df24cf81a6 | |||
| 5a7dbc70ea | |||
| dfea45330e | |||
| 449cb9a5af | |||
| 0d3a4085e5 | |||
| d94d4ee7bd | |||
| f7f425d600 | |||
| e18e90ebaf | |||
| 0d51def29e | |||
| 2fc7bc08bd | |||
| 7bd3c89114 | |||
| a09c8855b7 | |||
| e500747cfe | |||
| 84de690b4f | |||
| 2ae56f50ce | |||
| 79211e194d | |||
| a7bf23c6b5 | |||
| c7f6c148d9 | |||
| 012e133772 | |||
| 7a0fd192cc | |||
| fb0d6e56d6 | |||
| e724d3d26a | |||
| 3852413246 | |||
| c5f246eb37 | |||
| e03d76254c | |||
| 5da73e1a09 | |||
| 4243e27f22 | |||
| 8164722c58 | |||
| 75525cbe24 | |||
| 4a6b8a05cd | |||
| 253666e520 | |||
| 224155dd1c | |||
| 264d2b97a9 | |||
| e4618fb30d | |||
| 09e1df6c00 | |||
| 67a03cfd6e | |||
| 7de2a1faf6 | |||
| 42685f211e | |||
| 65e6b0dd12 | |||
| 6b6828625b | |||
| 9881d60d17 | |||
| b51926e67c | |||
| e3bfbb7284 | |||
| 440e6ff3b0 | |||
| 2dd3cdcfab | |||
| 1f8bb4b0a8 | |||
| 453e0261df | |||
| 9940e2aa45 | |||
| 8ad1d8ba38 | |||
| b79c718f1a | |||
| cfc9df76e1 | |||
| 9dfaf621d1 | |||
| a01c7c70fd | |||
| aa9933c115 | |||
| f690c14280 | |||
| 0ff435a782 | |||
| 3de4df27dd | |||
| 9e0ed8d4ec | |||
| f0582f43dd | |||
| 374cd78c1d | |||
| b355c2cc12 | |||
| 46a06bbe47 | |||
| 958d261bb8 | |||
| e9af1894e3 | |||
| 71794dbaeb | |||
| 2cf4acbd9f | |||
| a9f43d735b | |||
| 31a0bfde9b | |||
| db30fc4ff2 | |||
| 7f0a24b7bf | |||
| 22ace89179 | |||
| 1a088a8ef5 | |||
| 65b9ac5224 | |||
| 9c1586ec7c | |||
| f77ceba594 | |||
| 92a20dde1f | |||
| be3018c18f | |||
| d249090450 | |||
| 87744513e7 | |||
| 82a8a9f120 | |||
| 4be4c406fa | |||
| d83cad235a | |||
| d30ab3d9dd | |||
| bf20a35d5f | |||
| f7da5555da | |||
| 48e080b26c | |||
| 85462ed939 | |||
| 853546d047 | |||
| 1fb6a11072 | |||
| 8daefc2af0 | |||
| 6b5d4759ce | |||
| 1aca5caa88 | |||
| c438df1be0 | |||
| 8930c2ab0c | |||
| 831116d164 | |||
| 6e4cc55e1f | |||
| a634fb1577 | |||
| 54d0d2dd9a | |||
| ac4f0039c0 | |||
| dd95d30f82 | |||
| 8d8f56296b | |||
| fad9f9a8a6 | |||
| 578e1ca8d7 | |||
| 38fdead890 | |||
| a38c9516e8 | |||
| 4c417181c2 | |||
| e4529c5724 | |||
| d3c156638a | |||
| b3f56fdb69 | |||
| 3fb183d2f7 | |||
| 53cd10afcd | |||
| b663587890 | |||
| 7a4b1642a7 | |||
| 853c4a7621 | |||
| e7c84cc7e3 | |||
| ff9fce4d60 | |||
| 73e7d8b2bb | |||
| 2f17001521 | |||
| 7c8e9c78c8 | |||
| 70c93204ea | |||
| 36ed03428d | |||
| a1f7c0a21c | |||
| 6971952c65 | |||
| 27de5c5cb6 | |||
| face087212 | |||
| 382bdeabef | |||
| bfa463696b | |||
| 664eb14d8e | |||
| 68916c9fd3 | |||
| d9c131c366 | |||
| 182ea4e324 | |||
| e2ac506704 | |||
| 5e8980ddb1 | |||
| e6c7b09df6 | |||
| c872966ef4 | |||
| ab1dcc1a4b | |||
| 78d5843245 | |||
| 0c60c1fe66 | |||
| 3c863634ef | |||
| 5c2b314222 | |||
| 86dd3716b9 | |||
| dd23c6bfb4 | |||
| fd0a2f9756 | |||
| b22f38a779 | |||
| 3d1d90a13d | |||
| 4979088506 | |||
| 3f802ebce2 | |||
| 83553eefaf | |||
| 70f624c3a9 | |||
| d345a66428 | |||
| f45f2326a2 | |||
| 323913c880 | |||
| dbfca2b7f8 | |||
| c83a6bed04 | |||
| 59b8f2e108 | |||
| 9a4444778f | |||
| 8e1ee88c88 | |||
| 9afccba269 | |||
| cc08fa48b8 | |||
| a22a75e5ca | |||
| e99b9cdc70 | |||
| f9f1bdb0c8 | |||
| 5b1420e046 | |||
| 9bc21b535e | |||
| 8ad0de3f72 | |||
| fbb24d1092 | |||
| 4ef7efad5e | |||
| 0a8d14261c | |||
| 2b59b3a4c8 | |||
| 0c8a934cb4 | |||
| bc76063cd2 | |||
| 781e34cde3 | |||
| db1cc09c72 | |||
| 6284db908a | |||
| 344510e62b | |||
| 65ea12cb4a | |||
| 26d7e7c6b7 | |||
| ba194369ad | |||
| ea6c36e204 | |||
| 079a307259 | |||
| ddba0c227e | |||
| d2de861cbe | |||
| 0401acec91 | |||
| f87684189d | |||
| 0e682099a1 | |||
| a70a073b3f | |||
| 18c7e40ca3 | |||
| c625ba7f4f | |||
| d88e521f59 | |||
| 82d25da5b0 | |||
| 87af14a639 | |||
| 926345e027 | |||
| 036dbec01c | |||
| 5a500afd57 | |||
| 468108628c | |||
| 8073c70b33 | |||
| 3afca7d18c | |||
| 89212fb9f9 | |||
| b06a4ec1f0 | |||
| 55aeee4b48 | |||
| b72cad14d0 | |||
| f3ccc38a69 | |||
| eb443925ef | |||
| 8879481868 | |||
| f0ec2a5ea7 | |||
| fe70510aa7 | |||
| 0df163a9f0 | |||
| 378d01aa94 | |||
| b6e8fd105c | |||
| 62117159d0 | |||
| 0d71d121ae | |||
| dc90d3d8af | |||
| a6eaa635cc | |||
| fc5717cc99 | |||
| 03af2168db | |||
| 13ef14afc1 | |||
| 6d1626eb7c | |||
| 1496566560 | |||
| 817492630a | |||
| b1a1c29a07 | |||
| ef4668bc05 | |||
| d520041bc0 | |||
| edb4ece65e | |||
| 5b4627e957 | |||
| 65acf373c9 | |||
| a7b3b63524 | |||
| 6ddecb753a | |||
| daa3ce4b08 | |||
| e22724ee54 | |||
| a806475f86 | |||
| 572df3b1e4 | |||
| da0e47109e | |||
| f51446a38c |
+5
-1
@@ -177,7 +177,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
|
||||
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
|
||||
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
|
||||
random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \
|
||||
table.lo tokenize.lo trigger.lo \
|
||||
table.lo threads.lo tokenize.lo trigger.lo \
|
||||
update.lo util.lo vacuum.lo \
|
||||
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
|
||||
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
|
||||
@@ -261,6 +261,7 @@ SRC = \
|
||||
$(TOP)/src/sqliteInt.h \
|
||||
$(TOP)/src/sqliteLimit.h \
|
||||
$(TOP)/src/table.c \
|
||||
$(TOP)/src/threads.c \
|
||||
$(TOP)/src/tclsqlite.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/trigger.c \
|
||||
@@ -732,6 +733,9 @@ status.lo: $(TOP)/src/status.c $(HDR)
|
||||
table.lo: $(TOP)/src/table.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/table.c
|
||||
|
||||
threads.lo: $(TOP)/src/threads.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/threads.c
|
||||
|
||||
tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/tokenize.c
|
||||
|
||||
|
||||
+5
-1
@@ -564,7 +564,7 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
|
||||
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
|
||||
pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
|
||||
random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \
|
||||
table.lo tokenize.lo trigger.lo \
|
||||
table.lo threads.lo tokenize.lo trigger.lo \
|
||||
update.lo util.lo vacuum.lo \
|
||||
vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
|
||||
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
|
||||
@@ -659,6 +659,7 @@ SRC = \
|
||||
$(TOP)\src\sqliteInt.h \
|
||||
$(TOP)\src\sqliteLimit.h \
|
||||
$(TOP)\src\table.c \
|
||||
$(TOP)\src\threads.c \
|
||||
$(TOP)\src\tclsqlite.c \
|
||||
$(TOP)\src\tokenize.c \
|
||||
$(TOP)\src\trigger.c \
|
||||
@@ -1139,6 +1140,9 @@ status.lo: $(TOP)\src\status.c $(HDR)
|
||||
table.lo: $(TOP)\src\table.c $(HDR)
|
||||
$(LTCOMPILE) -c $(TOP)\src\table.c
|
||||
|
||||
threads.lo: $(TOP)\src\threads.c $(HDR)
|
||||
$(LTCOMPILE) -c $(TOP)\src\threads.c
|
||||
|
||||
tokenize.lo: $(TOP)\src\tokenize.c keywordhash.h $(HDR)
|
||||
$(LTCOMPILE) -c $(TOP)\src\tokenize.c
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.8.4.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.8.5.
|
||||
#
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.8.4'
|
||||
PACKAGE_STRING='sqlite 3.8.4'
|
||||
PACKAGE_VERSION='3.8.5'
|
||||
PACKAGE_STRING='sqlite 3.8.5'
|
||||
PACKAGE_BUGREPORT=''
|
||||
|
||||
# Factoring default headers for most tests.
|
||||
@@ -1483,7 +1483,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.8.4 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.8.5 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1548,7 +1548,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.8.4:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.8.5:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1664,7 +1664,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.8.4
|
||||
sqlite configure 3.8.5
|
||||
generated by GNU Autoconf 2.62
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1678,7 +1678,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.8.4, which was
|
||||
It was created by sqlite $as_me 3.8.5, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -14021,7 +14021,7 @@ exec 6>&1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.8.4, which was
|
||||
This file was extended by sqlite $as_me 3.8.5, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -14074,7 +14074,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.8.4
|
||||
sqlite config.status 3.8.5
|
||||
configured by $0, generated by GNU Autoconf 2.62,
|
||||
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
+37
-7
@@ -1410,10 +1410,7 @@ static int fts3InitVtab(
|
||||
** addition of a %_stat table so that it can use incremental merge.
|
||||
*/
|
||||
if( !isFts4 && !isCreate ){
|
||||
int rc2 = SQLITE_OK;
|
||||
fts3DbExec(&rc2, db, "SELECT 1 FROM %Q.'%q_stat' WHERE id=2",
|
||||
p->zDb, p->zName);
|
||||
if( rc2==SQLITE_OK ) p->bHasStat = 1;
|
||||
p->bHasStat = 2;
|
||||
}
|
||||
|
||||
/* Figure out the page-size for the database. This is required in order to
|
||||
@@ -3320,7 +3317,34 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of xBegin() method. This is a no-op.
|
||||
** If it is currently unknown whether or not the FTS table has an %_stat
|
||||
** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat
|
||||
** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code
|
||||
** if an error occurs.
|
||||
*/
|
||||
static int fts3SetHasStat(Fts3Table *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->bHasStat==2 ){
|
||||
const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'";
|
||||
char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName);
|
||||
if( zSql ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc==SQLITE_OK ) p->bHasStat = bHasStat;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of xBegin() method.
|
||||
*/
|
||||
static int fts3BeginMethod(sqlite3_vtab *pVtab){
|
||||
Fts3Table *p = (Fts3Table*)pVtab;
|
||||
@@ -3331,7 +3355,7 @@ static int fts3BeginMethod(sqlite3_vtab *pVtab){
|
||||
TESTONLY( p->inTransaction = 1 );
|
||||
TESTONLY( p->mxSavepoint = -1; );
|
||||
p->nLeafAdd = 0;
|
||||
return SQLITE_OK;
|
||||
return fts3SetHasStat(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3580,6 +3604,10 @@ static int fts3RenameMethod(
|
||||
sqlite3 *db = p->db; /* Database connection */
|
||||
int rc; /* Return Code */
|
||||
|
||||
/* At this point it must be known if the %_stat table exists or not.
|
||||
** So bHasStat may not be 2. */
|
||||
rc = fts3SetHasStat(p);
|
||||
|
||||
/* As it happens, the pending terms table is always empty here. This is
|
||||
** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
|
||||
** always opens a savepoint transaction. And the xSavepoint() method
|
||||
@@ -3587,7 +3615,9 @@ static int fts3RenameMethod(
|
||||
** PendingTermsFlush() in in case that changes.
|
||||
*/
|
||||
assert( p->nPendingData==0 );
|
||||
rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts3PendingTermsFlush(p);
|
||||
}
|
||||
|
||||
if( p->zContentTbl==0 ){
|
||||
fts3DbExec(&rc, db,
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ struct Fts3Table {
|
||||
|
||||
int nNodeSize; /* Soft limit for node size */
|
||||
u8 bFts4; /* True for FTS4, false for FTS3 */
|
||||
u8 bHasStat; /* True if %_stat table exists */
|
||||
u8 bHasStat; /* True if %_stat table exists (2==unknown) */
|
||||
u8 bHasDocsize; /* True if %_docsize table exists */
|
||||
u8 bDescIdx; /* True if doclists are in reverse order */
|
||||
u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */
|
||||
|
||||
@@ -5271,6 +5271,10 @@ int sqlite3Fts3UpdateMethod(
|
||||
int nChng = 0; /* Net change in number of documents */
|
||||
int bInsertDone = 0;
|
||||
|
||||
/* At this point it must be known if the %_stat table exists or not.
|
||||
** So bHasStat may not be 2. */
|
||||
assert( p->bHasStat==0 || p->bHasStat==1 );
|
||||
|
||||
assert( p->pSegments==0 );
|
||||
assert(
|
||||
nArg==1 /* DELETE operations */
|
||||
|
||||
+1
-1
@@ -26,8 +26,8 @@ SQLITE_EXTENSION_INIT1
|
||||
# define NEVER(X) 0
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
|
||||
+785
-749
File diff suppressed because it is too large
Load Diff
+11
-8
@@ -120,12 +120,13 @@ proc execsql_intout {sql} {
|
||||
# Test that it is possible to open an existing database that contains
|
||||
# r-tree tables.
|
||||
#
|
||||
do_test rtree-1.4.1 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2);
|
||||
INSERT INTO t1 VALUES(1, 5.0, 10.0);
|
||||
INSERT INTO t1 VALUES(2, 15.0, 20.0);
|
||||
}
|
||||
do_execsql_test rtree-1.4.1a {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2);
|
||||
INSERT INTO t1 VALUES(1, 5.0, 10.0);
|
||||
SELECT substr(hex(data),1,40) FROM t1_node;
|
||||
} {00000001000000000000000140A0000041200000}
|
||||
do_execsql_test rtree-1.4.1b {
|
||||
INSERT INTO t1 VALUES(2, 15.0, 20.0);
|
||||
} {}
|
||||
do_test rtree-1.4.2 {
|
||||
db close
|
||||
@@ -435,16 +436,18 @@ do_test rtree-11.2 {
|
||||
# Test on-conflict clause handling.
|
||||
#
|
||||
db_delete_and_reopen
|
||||
do_execsql_test 12.0 {
|
||||
do_execsql_test 12.0.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree_i32(idx, x1, x2, y1, y2);
|
||||
INSERT INTO t1 VALUES(1, 1, 2, 3, 4);
|
||||
SELECT substr(hex(data),1,56) FROM t1_node;
|
||||
} {00000001000000000000000100000001000000020000000300000004}
|
||||
do_execsql_test 12.0.2 {
|
||||
INSERT INTO t1 VALUES(2, 2, 3, 4, 5);
|
||||
INSERT INTO t1 VALUES(3, 3, 4, 5, 6);
|
||||
|
||||
CREATE TABLE source(idx, x1, x2, y1, y2);
|
||||
INSERT INTO source VALUES(5, 8, 8, 8, 8);
|
||||
INSERT INTO source VALUES(2, 7, 7, 7, 7);
|
||||
|
||||
}
|
||||
db_save_and_close
|
||||
foreach {tn sql_template testdata} {
|
||||
|
||||
@@ -57,31 +57,31 @@ do_test rtree6-1.1 {
|
||||
|
||||
do_test rtree6-1.2 {
|
||||
rtree_strategy {SELECT * FROM t1 WHERE x1>10}
|
||||
} {Ea}
|
||||
} {E0}
|
||||
|
||||
do_test rtree6-1.3 {
|
||||
rtree_strategy {SELECT * FROM t1 WHERE x1<10}
|
||||
} {Ca}
|
||||
} {C0}
|
||||
|
||||
do_test rtree6-1.4 {
|
||||
rtree_strategy {SELECT * FROM t1,t2 WHERE k=ii AND x1<10}
|
||||
} {Ca}
|
||||
} {C0}
|
||||
|
||||
do_test rtree6-1.5 {
|
||||
rtree_strategy {SELECT * FROM t1,t2 WHERE k=+ii AND x1<10}
|
||||
} {Ca}
|
||||
} {C0}
|
||||
|
||||
do_eqp_test rtree6.2.1 {
|
||||
SELECT * FROM t1,t2 WHERE k=+ii AND x1<10
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca}
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0}
|
||||
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
do_eqp_test rtree6.2.2 {
|
||||
SELECT * FROM t1,t2 WHERE k=ii AND x1<10
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca}
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0}
|
||||
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ do_eqp_test rtree6.2.3 {
|
||||
do_eqp_test rtree6.2.4 {
|
||||
SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:CaEb}
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1}
|
||||
0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ do_test rtree6.3.2 {
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5
|
||||
}
|
||||
} {EaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEa}
|
||||
} {E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0}
|
||||
do_test rtree6.3.3 {
|
||||
rtree_strategy {
|
||||
SELECT * FROM t3 WHERE
|
||||
@@ -137,7 +137,7 @@ do_test rtree6.3.3 {
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5
|
||||
}
|
||||
} {EaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEa}
|
||||
} {E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0}
|
||||
|
||||
do_execsql_test rtree6-3.4 {
|
||||
SELECT * FROM t3 WHERE x1>0.5 AND x1>0.8 AND x1>1.1
|
||||
|
||||
@@ -41,7 +41,7 @@ ifcapable rtree_int_only {
|
||||
INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400);
|
||||
SELECT rtreenode(2, data) FROM t1_node;
|
||||
}
|
||||
} {{{1073741824 0.000000 0.000000 100.000000 100.000000} {2147483646 0.000000 0.000000 200.000000 200.000000} {4294967296 0.000000 0.000000 300.000000 300.000000} {8589934592 20.000000 20.000000 150.000000 150.000000} {9223372036854775807 150.000000 150.000000 400.000000 400.000000}}}
|
||||
} {{{1073741824 0 0 100 100} {2147483646 0 0 200 200} {4294967296 0 0 300 300} {8589934592 20 20 150 150} {9223372036854775807 150 150 400 400}}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+118
-7
@@ -29,7 +29,7 @@ do_eqp_test 1.1 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 1 {SCAN TABLE t}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 1.2 {
|
||||
@@ -37,7 +37,7 @@ do_eqp_test 1.2 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 1.3 {
|
||||
@@ -45,7 +45,7 @@ do_eqp_test 1.3 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 1.5 {
|
||||
@@ -82,7 +82,7 @@ do_eqp_test 2.1 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 1 {SCAN TABLE t}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 2.2 {
|
||||
@@ -90,7 +90,7 @@ do_eqp_test 2.2 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 2.3 {
|
||||
@@ -98,7 +98,7 @@ do_eqp_test 2.3 {
|
||||
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
|
||||
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
|
||||
}
|
||||
|
||||
do_eqp_test 2.5 {
|
||||
@@ -158,5 +158,116 @@ do_execsql_test 4.3 {
|
||||
SELECT b, a FROM t2 LEFT JOIN t1 ON (+a = +b);
|
||||
} {1 1 3 {}}
|
||||
|
||||
finish_test
|
||||
#--------------------------------------------------------------------
|
||||
# Test that the sqlite_stat1 data is used correctly.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.1 {
|
||||
CREATE TABLE t1(x PRIMARY KEY, y);
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
|
||||
|
||||
INSERT INTO t1(x) VALUES(1);
|
||||
INSERT INTO t1(x) SELECT x+1 FROM t1; -- 2
|
||||
INSERT INTO t1(x) SELECT x+2 FROM t1; -- 4
|
||||
INSERT INTO t1(x) SELECT x+4 FROM t1; -- 8
|
||||
INSERT INTO t1(x) SELECT x+8 FROM t1; -- 16
|
||||
INSERT INTO t1(x) SELECT x+16 FROM t1; -- 32
|
||||
INSERT INTO t1(x) SELECT x+32 FROM t1; -- 64
|
||||
INSERT INTO t1(x) SELECT x+64 FROM t1; -- 128
|
||||
INSERT INTO t1(x) SELECT x+128 FROM t1; -- 256
|
||||
INSERT INTO t1(x) SELECT x+256 FROM t1; -- 512
|
||||
INSERT INTO t1(x) SELECT x+512 FROM t1; --1024
|
||||
|
||||
INSERT INTO rt SELECT x, x, x+1 FROM t1 WHERE x<=5;
|
||||
}
|
||||
|
||||
# First test a query with no ANALYZE data at all. The outer loop is
|
||||
# real table "t1".
|
||||
#
|
||||
do_eqp_test 5.2 {
|
||||
SELECT * FROM t1, rt WHERE x==id;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
|
||||
}
|
||||
|
||||
# Now create enough ANALYZE data to tell SQLite that virtual table "rt"
|
||||
# contains very few rows. This causes it to move "rt" to the outer loop.
|
||||
#
|
||||
do_execsql_test 5.3 {
|
||||
ANALYZE;
|
||||
DELETE FROM sqlite_stat1 WHERE tbl='t1';
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_eqp_test 5.4 {
|
||||
SELECT * FROM t1, rt WHERE x==id;
|
||||
} {
|
||||
0 0 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:}
|
||||
0 1 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (x=?)}
|
||||
}
|
||||
|
||||
# Delete the ANALYZE data. "t1" should be the outer loop again.
|
||||
#
|
||||
do_execsql_test 5.5 { DROP TABLE sqlite_stat1; }
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_eqp_test 5.6 {
|
||||
SELECT * FROM t1, rt WHERE x==id;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
|
||||
}
|
||||
|
||||
# This time create and attach a database that contains ANALYZE data for
|
||||
# tables of the same names as those used internally by virtual table
|
||||
# "rt". Check that the rtree module is not fooled into using this data.
|
||||
# Table "t1" should remain the outer loop.
|
||||
#
|
||||
do_test 5.7 {
|
||||
db backup test.db2
|
||||
sqlite3 db2 test.db2
|
||||
db2 eval {
|
||||
ANALYZE;
|
||||
DELETE FROM sqlite_stat1 WHERE tbl='t1';
|
||||
}
|
||||
db2 close
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { ATTACH 'test.db2' AS aux; }
|
||||
} {}
|
||||
do_eqp_test 5.8 {
|
||||
SELECT * FROM t1, rt WHERE x==id;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Test that having a second connection drop the sqlite_stat1 table
|
||||
# before it is required by rtreeConnect() does not cause problems.
|
||||
#
|
||||
ifcapable rtree {
|
||||
reset_db
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE t1(x);
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO rt VALUES(1,2,3);
|
||||
ANALYZE;
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 6.2 { SELECT * FROM t1 } {1}
|
||||
|
||||
do_test 6.3 {
|
||||
sqlite3 db2 test.db
|
||||
db2 eval { DROP TABLE sqlite_stat1 }
|
||||
db2 close
|
||||
execsql { SELECT * FROM rt }
|
||||
} {1 2.0 3.0}
|
||||
db close
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# 2014 March 11
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Miscellaneous tests for errors in the rtree constructor.
|
||||
#
|
||||
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source [file join [file dirname [info script]] rtree_util.tcl]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
ifcapable !rtree {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
set testprefix rtreeD
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that if an SQLITE_BUSY is encountered within the vtable
|
||||
# constructor, a relevant error message is returned.
|
||||
#
|
||||
do_multiclient_test tn {
|
||||
do_test 1.$tn.1 {
|
||||
sql1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, minx, maxx, miny, maxy);
|
||||
INSERT INTO rt VALUES(1,2,3,4,5);
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test 1.$tn.2 {
|
||||
sql2 { SELECT * FROM t1; }
|
||||
} {1 2}
|
||||
|
||||
do_test 1.$tn.3 {
|
||||
sql1 { BEGIN EXCLUSIVE; INSERT INTO t1 VALUES(3, 4); }
|
||||
} {}
|
||||
|
||||
do_test 1.$tn.4 {
|
||||
list [catch { sql2 { SELECT * FROM rt } } msg] $msg
|
||||
} {1 {database is locked}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
# 2010 August 28
|
||||
#
|
||||
# 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 contains tests for the r-tree module. Specifically, it tests
|
||||
# that new-style custom r-tree queries (geometry callbacks) work.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !rtree { finish_test ; return }
|
||||
ifcapable rtree_int_only { finish_test; return }
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the example 2d "circle" geometry callback.
|
||||
#
|
||||
register_circle_geom db
|
||||
|
||||
do_execsql_test rtreeE-1.1 {
|
||||
PRAGMA page_size=512;
|
||||
CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1);
|
||||
|
||||
/* A tight pattern of small boxes near 0,0 */
|
||||
WITH RECURSIVE
|
||||
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
|
||||
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
|
||||
INSERT INTO rt1 SELECT x+5*y, x, x+2, y, y+2 FROM x, y;
|
||||
|
||||
/* A looser pattern of small boxes near 100, 0 */
|
||||
WITH RECURSIVE
|
||||
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
|
||||
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
|
||||
INSERT INTO rt1 SELECT 100+x+5*y, x*3+100, x*3+102, y*3, y*3+2 FROM x, y;
|
||||
|
||||
/* A looser pattern of larger boxes near 0, 200 */
|
||||
WITH RECURSIVE
|
||||
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
|
||||
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
|
||||
INSERT INTO rt1 SELECT 200+x+5*y, x*7, x*7+15, y*7+200, y*7+215 FROM x, y;
|
||||
} {}
|
||||
|
||||
# Queries against each of the three clusters */
|
||||
do_execsql_test rtreeE-1.1 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0.0, 0.0, 50.0, 3) ORDER BY id;
|
||||
} {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24}
|
||||
do_execsql_test rtreeE-1.2 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(100.0, 0.0, 50.0, 3) ORDER BY id;
|
||||
} {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}
|
||||
do_execsql_test rtreeE-1.3 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0.0, 200.0, 50.0, 3) ORDER BY id;
|
||||
} {200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224}
|
||||
|
||||
# The Qcircle geometry function gives a lower score to larger leaf-nodes.
|
||||
# This causes the 200s to sort before the 100s and the 0s to sort before
|
||||
# last.
|
||||
#
|
||||
do_execsql_test rtreeE-1.4 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,3) AND id%100==0
|
||||
} {200 100 0}
|
||||
|
||||
# Exclude odd rowids on a depth-first search
|
||||
do_execsql_test rtreeE-1.5 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,4) ORDER BY +id
|
||||
} {0 2 4 6 8 10 12 14 16 18 20 22 24 100 102 104 106 108 110 112 114 116 118 120 122 124 200 202 204 206 208 210 212 214 216 218 220 222 224}
|
||||
|
||||
# Exclude odd rowids on a breadth-first search.
|
||||
do_execsql_test rtreeE-1.6 {
|
||||
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,5) ORDER BY +id
|
||||
} {0 2 4 6 8 10 12 14 16 18 20 22 24 100 102 104 106 108 110 112 114 116 118 120 122 124 200 202 204 206 208 210 212 214 216 218 220 222 224}
|
||||
|
||||
# Construct a large 2-D RTree with thousands of random entries.
|
||||
#
|
||||
do_test rtreeE-2.1 {
|
||||
db eval {
|
||||
CREATE TABLE t2(id,x0,x1,y0,y1);
|
||||
CREATE VIRTUAL TABLE rt2 USING rtree(id,x0,x1,y0,y1);
|
||||
BEGIN;
|
||||
}
|
||||
expr srand(0)
|
||||
for {set i 1} {$i<=10000} {incr i} {
|
||||
set dx [expr {int(rand()*40)+1}]
|
||||
set dy [expr {int(rand()*40)+1}]
|
||||
set x0 [expr {int(rand()*(10000 - $dx))}]
|
||||
set x1 [expr {$x0+$dx}]
|
||||
set y0 [expr {int(rand()*(10000 - $dy))}]
|
||||
set y1 [expr {$y0+$dy}]
|
||||
set id [expr {$i+10000}]
|
||||
db eval {INSERT INTO t2 VALUES($id,$x0,$x1,$y0,$y1)}
|
||||
}
|
||||
db eval {
|
||||
INSERT INTO rt2 SELECT * FROM t2;
|
||||
COMMIT;
|
||||
}
|
||||
} {}
|
||||
|
||||
for {set i 1} {$i<=200} {incr i} {
|
||||
set dx [expr {int(rand()*100)}]
|
||||
set dy [expr {int(rand()*100)}]
|
||||
set x0 [expr {int(rand()*(10000 - $dx))}]
|
||||
set x1 [expr {$x0+$dx}]
|
||||
set y0 [expr {int(rand()*(10000 - $dy))}]
|
||||
set y1 [expr {$y0+$dy}]
|
||||
set ans [db eval {SELECT id FROM t2 WHERE x1>=$x0 AND x0<=$x1 AND y1>=$y0 AND y0<=$y1 ORDER BY id}]
|
||||
do_execsql_test rtreeE-2.2.$i {
|
||||
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch($x0,$x1,$y0,$y1) ORDER BY id
|
||||
} $ans
|
||||
}
|
||||
|
||||
# Run query that have very deep priority queues
|
||||
#
|
||||
set ans [db eval {SELECT id FROM t2 WHERE x1>=0 AND x0<=5000 AND y1>=0 AND y0<=5000 ORDER BY id}]
|
||||
do_execsql_test rtreeE-2.3 {
|
||||
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch(0,5000,0,5000) ORDER BY id
|
||||
} $ans
|
||||
set ans [db eval {SELECT id FROM t2 WHERE x1>=0 AND x0<=10000 AND y1>=0 AND y0<=10000 ORDER BY id}]
|
||||
do_execsql_test rtreeE-2.4 {
|
||||
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch(0,10000,0,10000) ORDER BY id
|
||||
} $ans
|
||||
|
||||
finish_test
|
||||
@@ -21,6 +21,16 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
|
||||
typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
|
||||
|
||||
/* The double-precision datatype used by RTree depends on the
|
||||
** SQLITE_RTREE_INT_ONLY compile-time option.
|
||||
*/
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
typedef sqlite3_int64 sqlite3_rtree_dbl;
|
||||
#else
|
||||
typedef double sqlite3_rtree_dbl;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Register a geometry callback named zGeom that can be used as part of an
|
||||
@@ -31,11 +41,7 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
|
||||
int sqlite3_rtree_geometry_callback(
|
||||
sqlite3 *db,
|
||||
const char *zGeom,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes),
|
||||
#else
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes),
|
||||
#endif
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
|
||||
void *pContext
|
||||
);
|
||||
|
||||
@@ -47,11 +53,60 @@ int sqlite3_rtree_geometry_callback(
|
||||
struct sqlite3_rtree_geometry {
|
||||
void *pContext; /* Copy of pContext passed to s_r_g_c() */
|
||||
int nParam; /* Size of array aParam[] */
|
||||
double *aParam; /* Parameters passed to SQL geom function */
|
||||
sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */
|
||||
void *pUser; /* Callback implementation user data */
|
||||
void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */
|
||||
};
|
||||
|
||||
/*
|
||||
** Register a 2nd-generation geometry callback named zScore that can be
|
||||
** used as part of an R-Tree geometry query as follows:
|
||||
**
|
||||
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
|
||||
*/
|
||||
int sqlite3_rtree_query_callback(
|
||||
sqlite3 *db,
|
||||
const char *zQueryFunc,
|
||||
int (*xQueryFunc)(sqlite3_rtree_query_info*),
|
||||
void *pContext,
|
||||
void (*xDestructor)(void*)
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
** A pointer to a structure of the following type is passed as the
|
||||
** argument to scored geometry callback registered using
|
||||
** sqlite3_rtree_query_callback().
|
||||
**
|
||||
** Note that the first 5 fields of this structure are identical to
|
||||
** sqlite3_rtree_geometry. This structure is a subclass of
|
||||
** sqlite3_rtree_geometry.
|
||||
*/
|
||||
struct sqlite3_rtree_query_info {
|
||||
void *pContext; /* pContext from when function registered */
|
||||
int nParam; /* Number of function parameters */
|
||||
sqlite3_rtree_dbl *aParam; /* value of function parameters */
|
||||
void *pUser; /* callback can use this, if desired */
|
||||
void (*xDelUser)(void*); /* function to free pUser */
|
||||
sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */
|
||||
unsigned int *anQueue; /* Number of pending entries in the queue */
|
||||
int nCoord; /* Number of coordinates */
|
||||
int iLevel; /* Level of current node or entry */
|
||||
int mxLevel; /* The largest iLevel value in the tree */
|
||||
sqlite3_int64 iRowid; /* Rowid for current entry */
|
||||
sqlite3_rtree_dbl rParentScore; /* Score of parent node */
|
||||
int eParentWithin; /* Visibility of parent node */
|
||||
int eWithin; /* OUT: Visiblity */
|
||||
sqlite3_rtree_dbl rScore; /* OUT: Write the score here */
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin.
|
||||
*/
|
||||
#define NOT_WITHIN 0 /* Object completely outside of query region */
|
||||
#define PARTLY_WITHIN 1 /* Object partially overlaps query region */
|
||||
#define FULLY_WITHIN 2 /* Object fully contained within query region */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
|
||||
@@ -66,7 +66,7 @@ LIBOBJ+= vdbe.o parse.o \
|
||||
notify.o opcodes.o os.o os_unix.o os_win.o \
|
||||
pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \
|
||||
random.o resolve.o rowset.o rtree.o select.o status.o \
|
||||
table.o tokenize.o trigger.o \
|
||||
table.o threads.o tokenize.o trigger.o \
|
||||
update.o util.o vacuum.o \
|
||||
vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
|
||||
vdbetrace.o wal.o walker.o where.o utf.o vtab.o
|
||||
@@ -144,6 +144,7 @@ SRC = \
|
||||
$(TOP)/src/sqliteLimit.h \
|
||||
$(TOP)/src/table.c \
|
||||
$(TOP)/src/tclsqlite.c \
|
||||
$(TOP)/src/threads.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/trigger.c \
|
||||
$(TOP)/src/utf.c \
|
||||
@@ -311,6 +312,7 @@ TESTSRC2 = \
|
||||
$(TOP)/src/pcache.c \
|
||||
$(TOP)/src/pcache1.c \
|
||||
$(TOP)/src/select.c \
|
||||
$(TOP)/src/threads.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/utf.c \
|
||||
$(TOP)/src/util.c \
|
||||
@@ -476,7 +478,7 @@ parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk
|
||||
mv parse.h parse.h.temp
|
||||
$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
|
||||
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h
|
||||
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
|
||||
|
||||
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Experimental\ssimplification\sof\smemory\sflags/type\shandling.
|
||||
D 2014-03-05T01:29:18.160
|
||||
C Fix\sseveral\sharmless\scompiler\swarnings.
|
||||
D 2014-05-09T00:36:06.204
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
||||
F Makefile.in ad0921c4b2780d01868cf69b419a4f102308d125
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc fdacba6fb574868c71fde6db6b77789a383a4c19
|
||||
F Makefile.msc 7d6981e8e14d8189a2a2f9b4a485f40b2032cb2e
|
||||
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
|
||||
F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8
|
||||
F VERSION 0dc30ad5cf90736d5fd9e540c9f05c542658abe7
|
||||
F VERSION 9f823c026c6a32fc5f84d212a8aae0a221dba45c
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -38,7 +38,7 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure e12e1a4f031354f9af735bcb377941a72dc2cca5 x
|
||||
F configure 5de98fac90452f876511fee8a35565a55dfb191f x
|
||||
F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
|
||||
@@ -78,9 +78,9 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 3fe91e36a0304ad4b35020f0e22ff37e95873166
|
||||
F ext/fts3/fts3.c 41b1920b9a8657963f09cb93b208c2671c5568db
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h eb5f8029589f3d8f1dc7fd50c773326a640388b1
|
||||
F ext/fts3/fts3Int.h bdeb9015405e8facffb8fc7e09174521a2a780f4
|
||||
F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365
|
||||
F ext/fts3/fts3_expr.c 5165c365cb5a035f5be8bb296f7aa3211d43e4ac
|
||||
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
|
||||
@@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
|
||||
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
|
||||
F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9
|
||||
F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d
|
||||
F ext/fts3/fts3_write.c cdebe72171a217b1465032dec103f8d17f7dad4d
|
||||
F ext/fts3/fts3_write.c 74c00329006c3ed6325ba4e5ab7c9b5fc99c8934
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197
|
||||
@@ -114,35 +114,37 @@ F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
|
||||
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/spellfix.c 3548c433f473c2054e080b6382771636fcaa2c4c
|
||||
F ext/misc/spellfix.c 93f3961074cebe63c31fcefe62ca2a032ee8dfed
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c a4e18b2c150adad20aecbeb3408cd235a0a57441
|
||||
F ext/rtree/rtree.c 6f70db93e0e42c369325c5cddcf2024c5a87ca43
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test cf679265ecafff494a768ac9c2f43a70915a6290
|
||||
F ext/rtree/rtree1.test e2da4aaa426918d27122d1a1066c6ecf8409a514
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
|
||||
F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
|
||||
F ext/rtree/rtree5.test 6a510494f12454bf57ef28f45bc7764ea279431e
|
||||
F ext/rtree/rtree6.test fe0bd377a21c68ce2826129d14354c884cb1f354
|
||||
F ext/rtree/rtree6.test 756585abc51727fec97c77852476445c10c0ee95
|
||||
F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
|
||||
F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a
|
||||
F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34
|
||||
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
|
||||
F ext/rtree/rtreeB.test 983e567b49b5dca165940f66b87e161aa30e82b2
|
||||
F ext/rtree/rtreeC.test 03975565f40a0bee165f613143e4dec716dd5a59
|
||||
F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e
|
||||
F ext/rtree/rtreeC.test df158dcc81f1a43ce7eef361af03c48ec91f1e06
|
||||
F ext/rtree/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca
|
||||
F ext/rtree/rtreeE.test 388c1c8602c3ce55c15f03b509e9cf545fb7c41f
|
||||
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/sqlite3rtree.h c34c1e41d1ab80bb8ad09aae402c9c956871a765
|
||||
F ext/rtree/sqlite3rtree.h 83349d519fe5f518b3ea025d18dd1fe51b1684bd
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt f439556c5ce01ced70987e5ee86549a45165d9ff
|
||||
F main.mk 3ae543fa446525c1dec55f58de67f41b78651812
|
||||
F main.mk f51f401a87fd07be255bcecae8b03105ca2024e8
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
@@ -156,77 +158,77 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 5d99edbac5bc416032772b723ee30182ee6e5de0
|
||||
F src/analyze.c 69761e1677142d180a9f55250dee2952f45e4793
|
||||
F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1
|
||||
F src/analyze.c 3596f863bb80126fe56ba217df5932749271efc8
|
||||
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c ad795be588e394a0921796f87cc27717359738cc
|
||||
F src/btree.h 9e0f97c01b972f779eb7655cfb4f8727fd6dc26f
|
||||
F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4
|
||||
F src/build.c 00ce613bc2256e525c9195cb10d0df7bcc48d1f0
|
||||
F src/btree.c e14daeed62b5b1499835a6523f9a47d660c297c8
|
||||
F src/btree.h d79306df4ed9181b48916737fe8871a4392c4594
|
||||
F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3
|
||||
F src/build.c 9c522b6e5af1485c38b12a55f9d946e66fca61b6
|
||||
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
|
||||
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c cdd57149543bb28304d8f717c243f2a86b1fc280
|
||||
F src/expr.c 014b8087a15c4c314bdd798cb1cb0b32693f8b40
|
||||
F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf
|
||||
F src/expr.c 4f9e497c66e2f25a4d139357a778c84d5713207c
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf
|
||||
F src/func.c f4499b39d66b71825514334ce67b32ff14bd19f5
|
||||
F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
|
||||
F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811
|
||||
F src/global.c b7943ff485c31660ec0b17c68467034804df01b1
|
||||
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c d3d1164299faa53b5347f8ff676d3787537fa9e5
|
||||
F src/insert.c ab34bea5af4fee9f956a0805a32463fb7f674d00
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
|
||||
F src/main.c e054917b1beb3081b0f23e8bdd3d6c0e12933dd3
|
||||
F src/main.c 2ba4f6eeb84cf8efd8bb632c1abe203dc86adcac
|
||||
F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
|
||||
F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
|
||||
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
|
||||
F src/mem5.c aeb019f271ea53de83d651ec526877e6ba863450
|
||||
F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529
|
||||
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
|
||||
F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
|
||||
F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c
|
||||
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
|
||||
F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553
|
||||
F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc
|
||||
F src/mutex_w32.c 6108c88e1cb38d8fbb3534b170793815cbedbf97
|
||||
F src/mutex_noop.c 4222773e5f61e506f232aedc9ad9e16ca00c1399
|
||||
F src/mutex_unix.c 56e22c1bc6aabfa2f9736317a8f56acd5d0c5f7c
|
||||
F src/mutex_w32.c c4726d3bfe80996665a39d27598ebd056e2d6b89
|
||||
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
|
||||
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_unix.c 18f7f95dc6bcb9cf4d4a238d8e2de96611bc2ae5
|
||||
F src/os_win.c c47f107fc5c9d3466c06ea4aa35822f3568e81ee
|
||||
F src/pager.c 0ffa313a30ed6d061d9c6601b7b175cc50a1cab7
|
||||
F src/os_unix.c ae4b5240af4619d711301d7992396e182585269f
|
||||
F src/os_win.c 5024065c68c50739aeef6d490db88e5b682fcc30
|
||||
F src/pager.c ab62a24218d87dda1be641f6c5ad291bff78fd94
|
||||
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
|
||||
F src/parse.y 2613ca5d609c2f3d71dd297351f010bcec16e1e0
|
||||
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
|
||||
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
|
||||
F src/pragma.c a46ee83671f5c95f53d2ceeb5e1a818d7b1df99a
|
||||
F src/pragma.c 810ef31ccfaa233201dcf100637a9777cc24e897
|
||||
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
|
||||
F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
|
||||
F src/printf.c e5a0005f8b3de21f85da6a709d2fbee76775bf4b
|
||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 0adf172d33cc610ff5ffe26edfd2ba67c3551655
|
||||
F src/shell.c 7bf07bcacb181ecc3fc3ccacfdfeb4084aee67ed
|
||||
F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80
|
||||
F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be
|
||||
F src/select.c a5ed3fdc82ebab5b9b095ea1971515a7f8a303d2
|
||||
F src/shell.c 6946aea9f21af551fa84bc6b2a8de55d93bf0004
|
||||
F src/sqlite.h.in ed6d0cc90da850340c3863c84351e6e164c0ef00
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h bf529055591dd81ec92a84d35dba0854642f6cc2
|
||||
F src/sqliteInt.h 851003126071d4a3bac86a0db75c48197fbd0ff0
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c e87c99e28a145943666b51b212dacae35fcea0bd
|
||||
F src/test1.c 2401eee14a4309a7cfe2aeb2f30ad517a1d9c299
|
||||
F src/test1.c a0e59104fec5626bb1d1bd746157f43e85245e4b
|
||||
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
@@ -238,8 +240,8 @@ F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
|
||||
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
|
||||
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
|
||||
F src/test_config.c 0336e0bdbe541b4af89d7e3dd0656e8e6b51e585
|
||||
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
|
||||
F src/test_config.c bf2e0bf49ebd8fe3dccabb4542157f9571fe48fa
|
||||
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
|
||||
@@ -250,7 +252,7 @@ F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61
|
||||
F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d
|
||||
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
|
||||
F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4
|
||||
F src/test_malloc.c 1ff5b1243d96124c9a180f3b89424820a1f337f3
|
||||
F src/test_malloc.c 27047a841f5bff1cb638123806a2c30714771307
|
||||
F src/test_multiplex.c 9f304bf04170c91c0318238d512df2da039eb1c8
|
||||
F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1
|
||||
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
|
||||
@@ -259,58 +261,59 @@ F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba
|
||||
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
|
||||
F src/test_quota.c 30c64f0ef84734f2231a686df41ed882b0c59bc0
|
||||
F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb
|
||||
F src/test_rtree.c f3d1d12538dccb75fd916e3fa58f250edbdd3b47
|
||||
F src/test_rtree.c fdd8d29ca5165c7857987a2ba263fac5c69e231f
|
||||
F src/test_schema.c cd12a2223c3a394f4d07bb93bdf6d344c5c121b6
|
||||
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
|
||||
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
|
||||
F src/test_stat.c 9898687a6c2beca733b0dd6fe19163d987826d31
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_syscall.c 16dbe79fb320fadb5acd7a0a59f49e52ab2d2091
|
||||
F src/test_syscall.c 2e21ca7f7dc54a028f1967b63f1e76155c356f9b
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb
|
||||
F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
|
||||
F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
|
||||
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c b9daffcb6ae3a9c080da37b905e790d45a8f99db
|
||||
F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
|
||||
F src/trigger.c a80036fcbd992729adc7cd34a875d59a71fa10cc
|
||||
F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb
|
||||
F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115
|
||||
F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c
|
||||
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
|
||||
F src/util.c 2b5fb283a190aacdb286f7835a447c45b345b83c
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c 8c6fc7bb9f2218c0e43f24d847e596effa8671e2
|
||||
F src/vdbe.h d189f92468a17a6f04daeec9df3b767f50557b21
|
||||
F src/vdbeInt.h e54fc4f289fce48e81b3371128446033d097733b
|
||||
F src/vdbeapi.c a5c48f2b015679ddb7c25ae866abf5e2d6e42857
|
||||
F src/vdbeaux.c 43bee29ac866f7ce6af90c4f084bb22c160b8b70
|
||||
F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50
|
||||
F src/vdbe.c 89ab2ded5123e823b47293aedd7931a4742fb6bd
|
||||
F src/vdbe.h 394464909ed682334aa3d5831aae0c2fe2abef94
|
||||
F src/vdbeInt.h c78ace64dc37495806dd50596eded1f6cd2b5a64
|
||||
F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4
|
||||
F src/vdbeaux.c 44d4d1f5711f71eaf0d624de5c3e4976fe4e180b
|
||||
F src/vdbeblob.c 9205ce9d3b064d9600f8418a897fc88b5687d9ac
|
||||
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
|
||||
F src/vdbesort.c 46801acb342e5e4c07ba1777fe58880c143abb59
|
||||
F src/vdbesort.c b36070436d33372237541e9eaa6068e1a61bc402
|
||||
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
|
||||
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
||||
F src/where.c 2269342f82ea97596564bdc981c362a5177b72c5
|
||||
F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138
|
||||
F src/where.c 91dfd382273c3f67fcdc0ac4728f9140f91c6ab3
|
||||
F src/whereInt.h 6804c2e5010378568c2bb1350477537755296a46
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
|
||||
F test/alter.test e88dfa77e020c2b48e52a8020c70171ab828e079
|
||||
F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2
|
||||
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
|
||||
F test/alter4.test d6c011fa0d6227abba762498cafbb607c9609e93
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4
|
||||
F test/analyze3.test 412f690dfe95b337475e3e78a84a85d25f6f125d
|
||||
F test/analyze3.test bf41f0f680dd1e0d44eed5e769531e93a5320275
|
||||
F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213
|
||||
F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
|
||||
F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c
|
||||
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
|
||||
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
|
||||
F test/analyze9.test e072a5172d55afcba98d6ca6a219ce8878c2f5c9
|
||||
F test/analyze9.test 623e02a99a78fa12fe5def2fd559032d5d887e0f
|
||||
F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
|
||||
F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
|
||||
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
|
||||
@@ -328,7 +331,7 @@ F test/auth.test 5bdf154eb28c0e4bbc0473f335858c0d96171768
|
||||
F test/auth2.test c3b415b76c033bedb81292118fb7c01f5f10cbcd
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/autoinc.test c58912526998a39e11f66b533e23cfabea7f25b7
|
||||
F test/autoindex1.test d4dfe14001dfcb74cfbd7107f45a79fc1ab6183e
|
||||
F test/autoindex1.test 762ff3f8e25d852aae55c6462ca166a80c0cde61
|
||||
F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74
|
||||
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
|
||||
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
|
||||
@@ -361,7 +364,7 @@ F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
|
||||
F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738
|
||||
F test/capi3.test 6cdd49656bd62a296924f4d2fcfd05cd2a298369
|
||||
F test/capi3.test 71bcf2fbd36a9732f617766dfd752552c8e491b5
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test a21869e4d50d5dbb7e566e328fc0bc7c2efa6a32
|
||||
F test/capi3d.test 6d0fc0a86d73f42dd19a7d8b7761ab9bc02277d0
|
||||
@@ -402,9 +405,10 @@ F test/corruptC.test 02405cf7ed0c1e989060e1aab6d02ffbc3906fbb
|
||||
F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040
|
||||
F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee
|
||||
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
|
||||
F test/corruptG.test 58ec333a01997fe655e34e5bea52b7a2a6b9704d
|
||||
F test/corruptH.test 9d8186f6f8751efdfd445d8546fd98f073499039
|
||||
F test/corruptI.test d9eca60cb373215d97e0994bf104f9a37e1ac0fc
|
||||
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
|
||||
F test/corruptH.test 88ed71a086e13591c917aac6de32750e7c7281cb
|
||||
F test/corruptI.test b3e4203d420490fc3d3062711597bc1dea06a789
|
||||
F test/cost.test 04842adec34311d70c3f3c5fd698b22be54138fd
|
||||
F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5
|
||||
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
|
||||
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
|
||||
@@ -430,14 +434,14 @@ F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
|
||||
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test c7b194ef95dbddb32d77acbbab2e023c6eed0cb2
|
||||
F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
|
||||
F test/e_createtable.test ed82efcedc4b3656b27a5fcd12335cdb7e20eeee
|
||||
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
||||
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
|
||||
F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306
|
||||
F test/e_expr.test 5c71d183fbf519a4769fd2e2124afdc70b5b1f42
|
||||
F test/e_fkey.test 630597377549af579d34faaf64c6959a5a68ef76
|
||||
F test/e_fkey.test a1783fe1f759e1990e6a11adfcf0702dac4d0707
|
||||
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
|
||||
F test/e_insert.test 1e44f84d2abe44d66e4fbf198be4b20e3cc724a0
|
||||
F test/e_reindex.test 396b7b4f0a66863b4e95116a67d93b227193e589
|
||||
@@ -451,7 +455,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
|
||||
F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40
|
||||
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
|
||||
F test/eqp.test 57c6c604c2807fb5531731c5323133453c24afac
|
||||
F test/eqp.test 90b56d03a93a2e7bb90f88be6083a8ea53f11a0e
|
||||
F test/errmsg.test f31592a594b44ee121371d25ddd5d63497bb3401
|
||||
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
|
||||
F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75
|
||||
@@ -522,7 +526,7 @@ F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d
|
||||
F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f
|
||||
F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
|
||||
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
|
||||
F test/fts3ao.test 71b0675e3df5c512a5a03daaa95ee1916de23dda
|
||||
F test/fts3ao.test 3e4e3d5e75c076520341d0bdf4eb17c00e8cbde2
|
||||
F test/fts3atoken.test fca30fd86db9241d571c637751e9a8a2f50f1451
|
||||
F test/fts3auto.test b981fea19b132b4e6878f50d7c1f369b28f68eb9
|
||||
F test/fts3aux1.test f8f287a4a73f381f8fa15b6a70f36245f903d221
|
||||
@@ -534,7 +538,7 @@ F test/fts3conf.test ee8500c86dd58ec075e8831a1e216a79989436de
|
||||
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
|
||||
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
|
||||
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
|
||||
F test/fts3d.test c8a193513a269ec4c205ca09645e26e0bc71b860
|
||||
F test/fts3d.test 597b0b76e41f0d672e2731c4d7b631d628efd13f
|
||||
F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963
|
||||
F test/fts3defer2.test a3b6cbeabaf28c9398652a4d101ea224d9358479
|
||||
F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd
|
||||
@@ -573,7 +577,7 @@ F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584
|
||||
F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057
|
||||
F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test 00667bbeac044d007f6f021af1b9f6150f0c7ff8
|
||||
F test/func.test c2cbfc23d554c5bf8678d0fb271aa4f8ef94839c
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test dbccee9133cfef1473c59ec07b5f0262b9d72f9a
|
||||
F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f
|
||||
@@ -592,7 +596,7 @@ F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
|
||||
F test/in4.test 41c1c031aa46b1eb4411df2687ed2ed498da23b5
|
||||
F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3
|
||||
F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328
|
||||
F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600
|
||||
@@ -609,7 +613,7 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test 55a90cff99834305e8141df7afaef39674b57062
|
||||
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
|
||||
F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
|
||||
F test/index6.test 936979c3a1e87b81feaed2d00505665bf142d764
|
||||
F test/index6.test fb370966ac3cd0989053dd5385757b5c3e24ab6a
|
||||
F test/index7.test a3baf9a625bda7fd49471e99aeae04095fbfeecf
|
||||
F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
@@ -630,7 +634,7 @@ F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
|
||||
F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
|
||||
F test/join.test 8d63cc4d230a7affafa4b6ab0b97c49b8ccb365c
|
||||
F test/join.test 559b81eb56ae350246f9c25986aa52c81c725c7e
|
||||
F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
@@ -647,7 +651,7 @@ F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
F test/like.test e191e536d0fcd722a6b965e7cd1ee0bfd12a5991
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
F test/limit.test cc0ab63385239b63c72452b0e93700bf5e8f0b99
|
||||
F test/limit.test 3d7df19c35ac672a11f7de406cd3205d592babbb
|
||||
F test/loadext.test 648cb95f324d1775c54a55c12271b2d1156b633b
|
||||
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
|
||||
F test/lock.test 87af515b0c4cf928576d0f89946d67d7c265dfb4
|
||||
@@ -661,7 +665,7 @@ F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95
|
||||
F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2
|
||||
F test/main.test 39c4bb8a157f57298ed1659d6df89d9f35aaf2c8
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test fd368e31fe98d4779ed80442f311ed9f03bcd1f7
|
||||
F test/malloc.test ada8ae15193ffc6415bf431a6db31d4ec507dbfe
|
||||
F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a
|
||||
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
|
||||
F test/malloc5.test fafce0aa9157060445cd1a56ad50fc79d82f28c3
|
||||
@@ -669,7 +673,7 @@ F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151
|
||||
F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a
|
||||
F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d
|
||||
F test/malloc9.test 2307c6ee3703b0a21391f3ea92388b4b73f9105e
|
||||
F test/mallocA.test 1ba0367fb5434e7bc2fa4afcb30b14174d91b160
|
||||
F test/mallocA.test c049224adeb0244b8f6eb770c1fa6ac40f9b3518
|
||||
F test/mallocAll.test 98f1be74bc9f49a858bc4f361fc58e26486798be
|
||||
F test/mallocB.test bc475ab850cda896142ab935bbfbc74c24e51ed6
|
||||
F test/mallocC.test 3dffe16532f109293ce1ccecd0c31dca55ef08c4
|
||||
@@ -721,7 +725,9 @@ F test/orderby1.test 9b524aff9147288da43a6d7ddfdcff47fa2303c6
|
||||
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
|
||||
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
|
||||
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
|
||||
F test/orderby5.test 0eb82d5890c3f3d0563966560cfdc984ea69e30c
|
||||
F test/orderby5.test 8f08a54836d21fb7c70245360751aedd1c2286fb
|
||||
F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859
|
||||
F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da
|
||||
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
|
||||
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
|
||||
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
|
||||
@@ -735,7 +741,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
|
||||
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
|
||||
F test/permutations.test 40add071ba71aefe1c04f5845308cf46f7de8d04
|
||||
F test/permutations.test 33e7e239ba494fdb30e2f4ffc64c508b145ff42f
|
||||
F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0
|
||||
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
@@ -784,7 +790,7 @@ F test/select6.test e76bd10a56988f15726c097a5d5a7966fe82d3b2
|
||||
F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
|
||||
F test/selectA.test 77adaffe9704cb80e301ebaeff4b107b58d435c5
|
||||
F test/selectA.test 64b88a80271c1710966e50e633380696b60a12a4
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
|
||||
F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394
|
||||
@@ -808,13 +814,18 @@ F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
|
||||
F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9
|
||||
F test/shell5.test bb755ea9144b8078a752fc56223582627070b5f1
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/skipscan1.test 8c777ffd9dad6ee6d2568160cb2158f0b5cd9dd2
|
||||
F test/skipscan2.test 5a4db0799c338ddbacb154aaa5589c0254b36a8d
|
||||
F test/skipscan1.test bed8cbe9d554c8c27afb6c88500f704c86a9196f
|
||||
F test/skipscan2.test d77f79cdbba25f0f6f35298136cff21a7d7a553a
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
|
||||
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
|
||||
F test/sort.test 688468cef8c9a66fcc1d54235de8e4deac745690
|
||||
F test/sort2.test c5e25eb674689e291d06b5209fe8d337ae0ec010
|
||||
F test/sort3.test 6178ade30810ac9166fcdf14b7065e49c0f534e2
|
||||
F test/sort4.test 971452fd4e2928e6fc05c3868396ad7d5f9ce2ad
|
||||
F test/sortfault.test 1a12b6e27d475f50658a8164aaa34f0080a86b36
|
||||
F test/speed1.test f2974a91d79f58507ada01864c0e323093065452
|
||||
F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb
|
||||
F test/speed1p.test b180e98609c7677382cf618c0ec9b69f789033a8
|
||||
@@ -823,7 +834,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c 1603da7b4897716f9df15bd71b0310f56ec3181e
|
||||
F test/speedtest1.c f452891e50571627f7060c0e1262359127055717
|
||||
F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
|
||||
@@ -834,7 +845,7 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
|
||||
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
|
||||
F test/syscall.test a653783d985108c4912cc64d341ffbbb55ad2806
|
||||
F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
|
||||
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
|
||||
F test/table.test 580d23530187026d4502fae74a490f0408cf2cc7
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
@@ -843,7 +854,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
|
||||
F test/tester.tcl f31bea1483ea1d39620f982130026e76f872d744
|
||||
F test/tester.tcl bc0889a2f86d9c17307992ca1e70391794780265
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -890,9 +901,11 @@ F test/tkt-94c04eaadb.test f738c57c7f68ab8be1c054415af7774617cb6223
|
||||
F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
|
||||
F test/tkt-9f2eb3abac.test 85bc63e749f050e6a61c8f9207f1eee65c9d3395
|
||||
F test/tkt-a7b7803e.test 159ef554234fa1f9fb318c751b284bd1cf858da4
|
||||
F test/tkt-a8a0d2996a.test eb597379dbcefa24765763d7f682c00cb5924fa9
|
||||
F test/tkt-b1d3a2e531.test 8f7576e41ca179289ee1a8fee28386fd8e4b0550
|
||||
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
|
||||
F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3
|
||||
F test/tkt-b75a9ca6b0.test 97cc2d5eeaf82799eb42138c0a1ff64370238ce4
|
||||
F test/tkt-bd484a090c.test 60460bf946f79a79712b71f202eda501ca99b898
|
||||
F test/tkt-bdc6bbbb38.test fc38bb09bdd440e3513a1f5f98fc60a075182d7d
|
||||
F test/tkt-c48d99d690.test ba61977d62ab612fc515b3c488a6fbd6464a2447
|
||||
@@ -901,6 +914,7 @@ F test/tkt-d11f09d36e.test d999b548fef885d1d1afa49a0e8544ecf436869d
|
||||
F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09
|
||||
F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30
|
||||
F test/tkt-f3e5abed55.test d5a0126118142d13e27f6ce9f4c47096e9321c00
|
||||
F test/tkt-f67b41381a.test a23bc124c981662db712167bacd0ed8ad11abac9
|
||||
F test/tkt-f777251dc7a.test af6531446c64bfd268416f07b4df7be7f9c749d2
|
||||
F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7
|
||||
F test/tkt-f973c7ac31.test 28ef85c7f015477916795246d8286aeda39d4ead
|
||||
@@ -1018,9 +1032,9 @@ F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
|
||||
F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825
|
||||
F test/unordered.test ef85ac8f2f3c93ed2b9e811b684de73175fc464c
|
||||
F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
|
||||
F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb
|
||||
F test/uri.test 63e03df051620a18f794b4f4adcdefb3c23b6751
|
||||
F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
|
||||
F test/vacuum2.test af432e6e3bfc0ea20a80cb86a03c7d9876d38324
|
||||
@@ -1046,13 +1060,14 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
|
||||
F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e
|
||||
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 6acafaae7126c9f49be72c2f57eb8bef3024f1cb
|
||||
F test/wal.test 40073e54359d43354925b2b700b7eebd5e207285
|
||||
F test/wal2.test a8e3963abf6b232cf0b852b09b53665ef34007af
|
||||
F test/vtab_shared.test ea8778d5b0df200adef2ca7c00c3c37d4375f772
|
||||
F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc
|
||||
F test/wal2.test 1f841d2048080d32f552942e333fd99ce541dada
|
||||
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b
|
||||
F test/wal6.test 527581f5527bf9c24394991e2be83000aace5f9e
|
||||
F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8
|
||||
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
|
||||
F test/wal8.test 75c42e1bc4545c277fed212f8fc9b7723cd02216
|
||||
F test/wal9.test 378e76a9ad09cd9bee06c172ad3547b0129a6750
|
||||
@@ -1074,7 +1089,7 @@ F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
|
||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||
F test/where.test 28b64e93428961b07b0d486778d63fd672948f6b
|
||||
F test/where2.test 455a2eb2666e66c1e84e2cb5815173a85e6237db
|
||||
F test/where3.test d28c51f257e60be30f74308fa385ceeddfb54a6e
|
||||
F test/where3.test 1ad55ba900bd7747f98b6082e65bd3e442c5004e
|
||||
F test/where4.test d8420ceeb8323a41ceff1f1841fc528e824e1ecf
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
@@ -1085,17 +1100,18 @@ F test/where9.test 4f3eab951353a3ae164befc521c777dfa903e46c
|
||||
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
|
||||
F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62
|
||||
F test/whereD.test fd9120e262f9da3c45940f52aefeef4d15b904e5
|
||||
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
|
||||
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||
F test/whereG.test 2a3d5181decc801b36600fa1c40b0dad2ccc267f
|
||||
F test/whereG.test 0ac23e5e8311b69d87245f4a85112de321031658
|
||||
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/with1.test 268081a6b14817a262ced4d0ee34d4d2a1dd2068
|
||||
F test/with2.test 2fe78fcd8deef2a0f9cfc49bfc755911d0b3fd64
|
||||
F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775
|
||||
F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991
|
||||
F test/without_rowid1.test e00a0a9dc9f0be651f011d61e8a32b7add5afb30
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
@@ -1117,14 +1133,14 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/lemon.c 07aba6270d5a5016ba8107b09e431eea4ecdc123
|
||||
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
|
||||
F tool/logest.c 7ad625cac3d54012b27d468b7af6612f78b9ba75
|
||||
F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
|
||||
F tool/mkautoconfamal.sh f8d8dbf7d62f409ebed5134998bf5b51d7266383
|
||||
F tool/mkkeywordhash.c c9e05e4a7bcab8fab9f583d5b321fb72f565ad97
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl 78a77b2c554d534c6f2dc903130186ed15715460
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl 8bce31074e4cbe631bb7676526a048335f4c9f02
|
||||
F tool/mksqlite3c.tcl ed5b4e9ca8bf209ff401059a16362f37710fd8b8
|
||||
F tool/mksqlite3c-noext.tcl 752f1a9d3287f6c0ef5738b1c4add0b96fbe0854
|
||||
F tool/mksqlite3c.tcl 8da823522f27608494997e1dba19cd426572ba80
|
||||
F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12
|
||||
F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795
|
||||
F tool/mkvsix.tcl 6477fb9dab838b7eea1eed50658ff1cda04850b5
|
||||
@@ -1155,10 +1171,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P 554501f158534f9c27fd51900589c2ab7cf300d8
|
||||
R f9e55f86cd630e3c544c56ddb75f2871
|
||||
T *branch * noMemType
|
||||
T *sym-noMemType *
|
||||
T -sym-trunk *
|
||||
P dc7f84dfcc8415fad4af041fd30c20b3fd91be45
|
||||
R dab57784c4183d6467c4fe813ebf5ee5
|
||||
U mistachkin
|
||||
Z 24e103c83e028827d3da7d1aab872449
|
||||
Z bd4d9a5acb160a48faa7ad2a8521ce0e
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
bac2820e13a79d91d0f8938c643134a9d6900327
|
||||
360c0fd1cf9db5f1e4f670a4b95971daaeaa5879
|
||||
@@ -116,6 +116,7 @@ static void renameParentFunc(
|
||||
int token; /* Type of token */
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
if( zInput==0 || zOld==0 ) return;
|
||||
for(z=zInput; *z; z=z+n){
|
||||
n = sqlite3GetToken(z, &token);
|
||||
if( token==TK_REFERENCES ){
|
||||
|
||||
+23
-9
@@ -1178,7 +1178,10 @@ static void analyzeOneTable(
|
||||
callStatGet(v, regStat4, STAT_GET_NLT, regLt);
|
||||
callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
|
||||
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
|
||||
VdbeCoverage(v);
|
||||
/* We know that the regSampleRowid row exists because it was read by
|
||||
** the previous loop. Thus the not-found jump of seekOp will never
|
||||
** be taken */
|
||||
VdbeCoverageNeverTaken(v);
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
|
||||
pIdx->aiColumn[0], regSample);
|
||||
@@ -1192,7 +1195,7 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regTemp, regNewRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */
|
||||
sqlite3VdbeJumpHere(v, addrIsNull);
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
@@ -1368,6 +1371,7 @@ static void decodeIntArray(
|
||||
char *zIntArray, /* String containing int array to decode */
|
||||
int nOut, /* Number of slots in aOut[] */
|
||||
tRowcnt *aOut, /* Store integers here */
|
||||
LogEst *aLog, /* Or, if aOut==0, here */
|
||||
Index *pIndex /* Handle extra flags for this index, if not NULL */
|
||||
){
|
||||
char *z = zIntArray;
|
||||
@@ -1386,7 +1390,17 @@ static void decodeIntArray(
|
||||
v = v*10 + c - '0';
|
||||
z++;
|
||||
}
|
||||
aOut[i] = v;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( aOut ){
|
||||
aOut[i] = v;
|
||||
}else
|
||||
#else
|
||||
assert( aOut==0 );
|
||||
UNUSED_PARAMETER(aOut);
|
||||
#endif
|
||||
{
|
||||
aLog[i] = sqlite3LogEst(v);
|
||||
}
|
||||
if( *z==' ' ) z++;
|
||||
}
|
||||
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
@@ -1442,12 +1456,12 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
z = argv[2];
|
||||
|
||||
if( pIndex ){
|
||||
decodeIntArray((char*)z, pIndex->nKeyCol+1, pIndex->aiRowEst, pIndex);
|
||||
if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0];
|
||||
decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex);
|
||||
if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
|
||||
}else{
|
||||
Index fakeIdx;
|
||||
fakeIdx.szIdxRow = pTable->szTabRow;
|
||||
decodeIntArray((char*)z, 1, &pTable->nRowEst, &fakeIdx);
|
||||
decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
|
||||
pTable->szTabRow = fakeIdx.szIdxRow;
|
||||
}
|
||||
|
||||
@@ -1639,9 +1653,9 @@ static int loadStatTbl(
|
||||
pPrevIdx = pIdx;
|
||||
}
|
||||
pSample = &pIdx->aSample[pIdx->nSample];
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,1), nCol, pSample->anEq, 0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,2), nCol, pSample->anLt, 0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,3), nCol, pSample->anDLt,0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,1),nCol,pSample->anEq,0,0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0);
|
||||
|
||||
/* Take a copy of the sample. Add two 0x00 bytes the end of the buffer.
|
||||
** This is in case the sample record is corrupted. In that case, the
|
||||
|
||||
+139
-95
@@ -446,16 +446,11 @@ static int cursorHoldsMutex(BtCursor *p){
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/*
|
||||
** Invalidate the overflow page-list cache for cursor pCur, if any.
|
||||
** Invalidate the overflow cache of the cursor passed as the first argument.
|
||||
** on the shared btree structure pBt.
|
||||
*/
|
||||
static void invalidateOverflowCache(BtCursor *pCur){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
sqlite3_free(pCur->aOverflow);
|
||||
pCur->aOverflow = 0;
|
||||
}
|
||||
#define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl)
|
||||
|
||||
/*
|
||||
** Invalidate the overflow page-list cache for all cursors opened
|
||||
@@ -469,6 +464,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/*
|
||||
** This function is called before modifying the contents of a table
|
||||
** to invalidate any incrblob cursors that are open on the
|
||||
@@ -491,16 +487,14 @@ static void invalidateIncrblobCursors(
|
||||
BtShared *pBt = pBtree->pBt;
|
||||
assert( sqlite3BtreeHoldsMutex(pBtree) );
|
||||
for(p=pBt->pCursor; p; p=p->pNext){
|
||||
if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){
|
||||
if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){
|
||||
p->eState = CURSOR_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub functions when INCRBLOB is omitted */
|
||||
#define invalidateOverflowCache(x)
|
||||
#define invalidateAllOverflowCache(x)
|
||||
/* Stub function when INCRBLOB is omitted */
|
||||
#define invalidateIncrblobCursors(x,y,z)
|
||||
#endif /* SQLITE_OMIT_INCRBLOB */
|
||||
|
||||
@@ -746,20 +740,32 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){
|
||||
** at is deleted out from under them.
|
||||
**
|
||||
** This routine returns an error code if something goes wrong. The
|
||||
** integer *pHasMoved is set to one if the cursor has moved and 0 if not.
|
||||
** integer *pHasMoved is set as follows:
|
||||
**
|
||||
** 0: The cursor is unchanged
|
||||
** 1: The cursor is still pointing at the same row, but the pointers
|
||||
** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch()
|
||||
** might now be invalid because of a balance() or other change to the
|
||||
** b-tree.
|
||||
** 2: The cursor is no longer pointing to the row. The row might have
|
||||
** been deleted out from under the cursor.
|
||||
*/
|
||||
int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
|
||||
int rc;
|
||||
|
||||
if( pCur->eState==CURSOR_VALID ){
|
||||
*pHasMoved = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc ){
|
||||
*pHasMoved = 1;
|
||||
*pHasMoved = 2;
|
||||
return rc;
|
||||
}
|
||||
if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
|
||||
*pHasMoved = 1;
|
||||
*pHasMoved = 2;
|
||||
}else{
|
||||
*pHasMoved = 0;
|
||||
*pHasMoved = 1;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -2161,6 +2167,7 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
/*
|
||||
** Change the limit on the amount of the database file that may be
|
||||
** memory mapped.
|
||||
@@ -2173,6 +2180,7 @@ int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
|
||||
sqlite3BtreeLeave(p);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
|
||||
|
||||
/*
|
||||
** Change the way data is synced to disk in order to increase or decrease
|
||||
@@ -2549,7 +2557,8 @@ static int countValidCursors(BtShared *pBt, int wrOnly){
|
||||
BtCursor *pCur;
|
||||
int r = 0;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++;
|
||||
if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0)
|
||||
&& pCur->eState!=CURSOR_FAULT ) r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -3624,7 +3633,8 @@ static int btreeCursor(
|
||||
pCur->pKeyInfo = pKeyInfo;
|
||||
pCur->pBtree = p;
|
||||
pCur->pBt = pBt;
|
||||
pCur->wrFlag = (u8)wrFlag;
|
||||
assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
|
||||
pCur->curFlags = wrFlag;
|
||||
pCur->pNext = pBt->pCursor;
|
||||
if( pCur->pNext ){
|
||||
pCur->pNext->pPrev = pCur;
|
||||
@@ -3694,7 +3704,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
releasePage(pCur->apPage[i]);
|
||||
}
|
||||
unlockBtreeIfUnused(pBt);
|
||||
invalidateOverflowCache(pCur);
|
||||
sqlite3DbFree(pBtree->db, pCur->aOverflow);
|
||||
/* sqlite3_free(pCur); */
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
}
|
||||
@@ -3733,7 +3743,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
if( pCur->info.nSize==0 ){
|
||||
int iPage = pCur->iPage;
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
|
||||
pCur->validNKey = 1;
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
}else{
|
||||
assertCellInfo(pCur);
|
||||
}
|
||||
@@ -3743,8 +3753,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
#define getCellInfo(pCur) \
|
||||
if( pCur->info.nSize==0 ){ \
|
||||
int iPage = pCur->iPage; \
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
|
||||
pCur->validNKey = 1; \
|
||||
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
|
||||
pCur->curFlags |= BTCF_ValidNKey; \
|
||||
}else{ \
|
||||
assertCellInfo(pCur); \
|
||||
}
|
||||
@@ -3915,10 +3925,12 @@ static int copyPayload(
|
||||
|
||||
/*
|
||||
** This function is used to read or overwrite payload information
|
||||
** for the entry that the pCur cursor is pointing to. If the eOp
|
||||
** parameter is 0, this is a read operation (data copied into
|
||||
** buffer pBuf). If it is non-zero, a write (data copied from
|
||||
** buffer pBuf).
|
||||
** for the entry that the pCur cursor is pointing to. The eOp
|
||||
** argument is interpreted as follows:
|
||||
**
|
||||
** 0: The operation is a read. Populate the overflow cache.
|
||||
** 1: The operation is a write. Populate the overflow cache.
|
||||
** 2: The operation is a read. Do not populate the overflow cache.
|
||||
**
|
||||
** A total of "amt" bytes are read or written beginning at "offset".
|
||||
** Data is read to or from the buffer pBuf.
|
||||
@@ -3926,11 +3938,11 @@ static int copyPayload(
|
||||
** The content being read or written might appear on the main page
|
||||
** or be scattered out on multiple overflow pages.
|
||||
**
|
||||
** If the BtCursor.isIncrblobHandle flag is set, and the current
|
||||
** cursor entry uses one or more overflow pages, this function
|
||||
** allocates space for and lazily popluates the overflow page-list
|
||||
** cache array (BtCursor.aOverflow). Subsequent calls use this
|
||||
** cache to make seeking to the supplied offset more efficient.
|
||||
** If the current cursor entry uses one or more overflow pages and the
|
||||
** eOp argument is not 2, this function may allocate space for and lazily
|
||||
** popluates the overflow page-list cache array (BtCursor.aOverflow).
|
||||
** Subsequent calls use this cache to make seeking to the supplied offset
|
||||
** more efficient.
|
||||
**
|
||||
** Once an overflow page-list cache has been allocated, it may be
|
||||
** invalidated if some other cursor writes to the same table, or if
|
||||
@@ -3954,15 +3966,22 @@ static int accessPayload(
|
||||
int iIdx = 0;
|
||||
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
|
||||
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
|
||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||
int bEnd; /* True if reading to end of data */
|
||||
#endif
|
||||
|
||||
assert( pPage );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
|
||||
|
||||
getCellInfo(pCur);
|
||||
aPayload = pCur->info.pCell + pCur->info.nHeader;
|
||||
nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
|
||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||
bEnd = (offset+amt==nKey+pCur->info.nData);
|
||||
#endif
|
||||
|
||||
if( NEVER(offset+amt > nKey+pCur->info.nData)
|
||||
|| &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
|
||||
@@ -3977,7 +3996,7 @@ static int accessPayload(
|
||||
if( a+offset>pCur->info.nLocal ){
|
||||
a = pCur->info.nLocal - offset;
|
||||
}
|
||||
rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
|
||||
rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
|
||||
offset = 0;
|
||||
pBuf += a;
|
||||
amt -= a;
|
||||
@@ -3991,21 +4010,30 @@ static int accessPayload(
|
||||
|
||||
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[]
|
||||
** has not been allocated, allocate it now. The array is sized at
|
||||
** one entry for each overflow page in the overflow chain. The
|
||||
** page number of the first overflow page is stored in aOverflow[0],
|
||||
** etc. A value of 0 in the aOverflow[] array means "not yet known"
|
||||
** (the cache is lazily populated).
|
||||
/* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
|
||||
** Except, do not allocate aOverflow[] for eOp==2.
|
||||
**
|
||||
** The aOverflow[] array is sized at one entry for each overflow page
|
||||
** in the overflow chain. The page number of the first overflow page is
|
||||
** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array
|
||||
** means "not yet known" (the cache is lazily populated).
|
||||
*/
|
||||
if( pCur->isIncrblobHandle && !pCur->aOverflow ){
|
||||
if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
|
||||
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
|
||||
pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl);
|
||||
/* nOvfl is always positive. If it were zero, fetchPayload would have
|
||||
** been used instead of this routine. */
|
||||
if( ALWAYS(nOvfl) && !pCur->aOverflow ){
|
||||
rc = SQLITE_NOMEM;
|
||||
if( nOvfl>pCur->nOvflAlloc ){
|
||||
Pgno *aNew = (Pgno*)sqlite3DbRealloc(
|
||||
pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
|
||||
);
|
||||
if( aNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
pCur->nOvflAlloc = nOvfl*2;
|
||||
pCur->aOverflow = aNew;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
|
||||
pCur->curFlags |= BTCF_ValidOvfl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4013,22 +4041,19 @@ static int accessPayload(
|
||||
** entry for the first required overflow page is valid, skip
|
||||
** directly to it.
|
||||
*/
|
||||
if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
|
||||
if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){
|
||||
iIdx = (offset/ovflSize);
|
||||
nextPage = pCur->aOverflow[iIdx];
|
||||
offset = (offset%ovflSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/* If required, populate the overflow page-list cache. */
|
||||
if( pCur->aOverflow ){
|
||||
if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
|
||||
assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
|
||||
pCur->aOverflow[iIdx] = nextPage;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( offset>=ovflSize ){
|
||||
/* The only reason to read this page is to obtain the page
|
||||
@@ -4036,13 +4061,17 @@ static int accessPayload(
|
||||
** data is not required. So first try to lookup the overflow
|
||||
** page-list cache, if any, then fall back to the getOverflowPage()
|
||||
** function.
|
||||
**
|
||||
** Note that the aOverflow[] array must be allocated because eOp!=2
|
||||
** here. If eOp==2, then offset==0 and this branch is never taken.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){
|
||||
assert( eOp!=2 );
|
||||
assert( pCur->curFlags & BTCF_ValidOvfl );
|
||||
if( pCur->aOverflow[iIdx+1] ){
|
||||
nextPage = pCur->aOverflow[iIdx+1];
|
||||
} else
|
||||
#endif
|
||||
}else{
|
||||
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
|
||||
}
|
||||
offset -= ovflSize;
|
||||
}else{
|
||||
/* Need to read this page properly. It contains some of the
|
||||
@@ -4064,13 +4093,15 @@ static int accessPayload(
|
||||
** 3) the database is file-backed, and
|
||||
** 4) there is no open write-transaction, and
|
||||
** 5) the database is not a WAL database,
|
||||
** 6) all data from the page is being read.
|
||||
**
|
||||
** then data can be read directly from the database file into the
|
||||
** output buffer, bypassing the page-cache altogether. This speeds
|
||||
** up loading large records that span many overflow pages.
|
||||
*/
|
||||
if( eOp==0 /* (1) */
|
||||
if( (eOp&0x01)==0 /* (1) */
|
||||
&& offset==0 /* (2) */
|
||||
&& (bEnd || a==ovflSize) /* (6) */
|
||||
&& pBt->inTransaction==TRANS_READ /* (4) */
|
||||
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
|
||||
&& pBt->pPage1->aData[19]==0x01 /* (5) */
|
||||
@@ -4087,12 +4118,12 @@ static int accessPayload(
|
||||
{
|
||||
DbPage *pDbPage;
|
||||
rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
|
||||
(eOp==0 ? PAGER_GET_READONLY : 0)
|
||||
((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
aPayload = sqlite3PagerGetData(pDbPage);
|
||||
nextPage = get4byte(aPayload);
|
||||
rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
|
||||
rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
|
||||
sqlite3PagerUnref(pDbPage);
|
||||
offset = 0;
|
||||
}
|
||||
@@ -4186,10 +4217,13 @@ static const void *fetchPayload(
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
assert( pCur->info.nSize>0 );
|
||||
#if 0
|
||||
if( pCur->info.nSize==0 ){
|
||||
btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
|
||||
&pCur->info);
|
||||
}
|
||||
#endif
|
||||
*pAmt = pCur->info.nLocal;
|
||||
return (void*)(pCur->info.pCell + pCur->info.nHeader);
|
||||
}
|
||||
@@ -4240,14 +4274,14 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
rc = getAndInitPage(pBt, newPgno, &pNewPage,
|
||||
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
|
||||
(pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
|
||||
if( rc ) return rc;
|
||||
pCur->apPage[i+1] = pNewPage;
|
||||
pCur->aiIdx[i+1] = 0;
|
||||
pCur->iPage++;
|
||||
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
@@ -4305,7 +4339,7 @@ static void moveToParent(BtCursor *pCur){
|
||||
releasePage(pCur->apPage[pCur->iPage]);
|
||||
pCur->iPage--;
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4352,7 +4386,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
|
||||
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
|
||||
(pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
return rc;
|
||||
@@ -4379,8 +4413,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
|
||||
pCur->aiIdx[0] = 0;
|
||||
pCur->info.nSize = 0;
|
||||
pCur->atLast = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
|
||||
if( pRoot->nCell>0 ){
|
||||
pCur->eState = CURSOR_VALID;
|
||||
@@ -4443,7 +4476,7 @@ static int moveToRightmost(BtCursor *pCur){
|
||||
if( rc==SQLITE_OK ){
|
||||
pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~BTCF_ValidNKey;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -4482,7 +4515,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
|
||||
/* If the cursor already points to the last entry, this is a no-op. */
|
||||
if( CURSOR_VALID==pCur->eState && pCur->atLast ){
|
||||
if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* This block serves to assert() that the cursor really does point
|
||||
** to the last entry in the b-tree. */
|
||||
@@ -4505,7 +4538,12 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
*pRes = 0;
|
||||
rc = moveToRightmost(pCur);
|
||||
pCur->atLast = rc==SQLITE_OK ?1:0;
|
||||
if( rc==SQLITE_OK ){
|
||||
pCur->curFlags |= BTCF_AtLast;
|
||||
}else{
|
||||
pCur->curFlags &= ~BTCF_AtLast;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -4556,14 +4594,14 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
|
||||
/* If the cursor is already positioned at the point we are trying
|
||||
** to move to, then just return without doing any work */
|
||||
if( pCur->eState==CURSOR_VALID && pCur->validNKey
|
||||
if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
|
||||
&& pCur->apPage[0]->intKey
|
||||
){
|
||||
if( pCur->info.nKey==intKey ){
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pCur->atLast && pCur->info.nKey<intKey ){
|
||||
if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
|
||||
*pRes = -1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -4571,12 +4609,13 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
|
||||
if( pIdxKey ){
|
||||
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
|
||||
pIdxKey->errCode = 0;
|
||||
assert( pIdxKey->default_rc==1
|
||||
|| pIdxKey->default_rc==0
|
||||
|| pIdxKey->default_rc==-1
|
||||
);
|
||||
}else{
|
||||
xRecordCompare = 0; /* Not actually used. Avoids a compiler warning. */
|
||||
xRecordCompare = 0; /* All keys are integers */
|
||||
}
|
||||
|
||||
rc = moveToRoot(pCur);
|
||||
@@ -4629,7 +4668,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
if( lwr>upr ){ c = +1; break; }
|
||||
}else{
|
||||
assert( nCellKey==intKey );
|
||||
pCur->validNKey = 1;
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
pCur->info.nKey = nCellKey;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
if( !pPage->leaf ){
|
||||
@@ -4686,7 +4725,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
|
||||
if( rc ){
|
||||
sqlite3_free(pCellKey);
|
||||
goto moveto_finish;
|
||||
@@ -4694,6 +4733,10 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
|
||||
sqlite3_free(pCellKey);
|
||||
}
|
||||
assert(
|
||||
(pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
|
||||
&& (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed)
|
||||
);
|
||||
if( c<0 ){
|
||||
lwr = idx+1;
|
||||
}else if( c>0 ){
|
||||
@@ -4703,6 +4746,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
*pRes = 0;
|
||||
rc = SQLITE_OK;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
if( lwr>upr ) break;
|
||||
@@ -4731,7 +4775,7 @@ moveto_next_layer:
|
||||
}
|
||||
moveto_finish:
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -4776,6 +4820,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
invalidateOverflowCache(pCur);
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc!=SQLITE_OK ){
|
||||
*pRes = 0;
|
||||
@@ -4809,7 +4854,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
testcase( idx>pPage->nCell );
|
||||
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
if( idx>=pPage->nCell ){
|
||||
if( !pPage->leaf ){
|
||||
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
|
||||
@@ -4870,7 +4915,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
assert( pRes!=0 );
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
pCur->atLast = 0;
|
||||
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl);
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
|
||||
rc = btreeRestoreCursorPosition(pCur);
|
||||
@@ -4915,7 +4960,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
moveToParent(pCur);
|
||||
}
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
|
||||
pCur->aiIdx[pCur->iPage]--;
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
@@ -6940,7 +6985,7 @@ int sqlite3BtreeInsert(
|
||||
}
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE
|
||||
assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE
|
||||
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
|
||||
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
||||
|
||||
@@ -6973,7 +7018,7 @@ int sqlite3BtreeInsert(
|
||||
/* If the cursor is currently on the last row and we are appending a
|
||||
** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
|
||||
** call */
|
||||
if( pCur->validNKey && nKey>0 && pCur->info.nKey==nKey-1 ){
|
||||
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){
|
||||
loc = -1;
|
||||
}
|
||||
}
|
||||
@@ -7026,7 +7071,7 @@ int sqlite3BtreeInsert(
|
||||
|
||||
/* If no error has occurred and pPage has an overflow cell, call balance()
|
||||
** to redistribute the cells within the tree. Since balance() may move
|
||||
** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey
|
||||
** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
|
||||
** variables.
|
||||
**
|
||||
** Previous versions of SQLite called moveToRoot() to move the cursor
|
||||
@@ -7046,7 +7091,7 @@ int sqlite3BtreeInsert(
|
||||
*/
|
||||
pCur->info.nSize = 0;
|
||||
if( rc==SQLITE_OK && pPage->nOverflow ){
|
||||
pCur->validNKey = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey);
|
||||
rc = balance(pCur);
|
||||
|
||||
/* Must make sure nOverflow is reset to zero even if the balance()
|
||||
@@ -7078,7 +7123,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pBt->inTransaction==TRANS_WRITE );
|
||||
assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
|
||||
assert( pCur->wrFlag );
|
||||
assert( pCur->curFlags & BTCF_WriteFlag );
|
||||
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
||||
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
|
||||
|
||||
@@ -7423,6 +7468,15 @@ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete all information from the single table that pCur is open on.
|
||||
**
|
||||
** This routine only work for pCur on an ephemeral table.
|
||||
*/
|
||||
int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){
|
||||
return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Erase all information in a table and add the root of the table to
|
||||
** the freelist. Except, the root of the principle table (the one on
|
||||
@@ -8382,7 +8436,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
|
||||
int rc;
|
||||
assert( cursorHoldsMutex(pCsr) );
|
||||
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
|
||||
assert( pCsr->isIncrblobHandle );
|
||||
assert( pCsr->curFlags & BTCF_Incrblob );
|
||||
|
||||
rc = restoreCursorPosition(pCsr);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -8411,7 +8465,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
|
||||
** (d) there are no conflicting read-locks, and
|
||||
** (e) the cursor points at a valid row of an intKey table.
|
||||
*/
|
||||
if( !pCsr->wrFlag ){
|
||||
if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
|
||||
@@ -8424,20 +8478,10 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
|
||||
}
|
||||
|
||||
/*
|
||||
** Set a flag on this cursor to cache the locations of pages from the
|
||||
** overflow list for the current row. This is used by cursors opened
|
||||
** for incremental blob IO only.
|
||||
**
|
||||
** This function sets a flag only. The actual page location cache
|
||||
** (stored in BtCursor.aOverflow[]) is allocated and used by function
|
||||
** accessPayload() (the worker function for sqlite3BtreeData() and
|
||||
** sqlite3BtreePutData()).
|
||||
** Mark this cursor as an incremental blob cursor.
|
||||
*/
|
||||
void sqlite3BtreeCacheOverflow(BtCursor *pCur){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
invalidateOverflowCache(pCur);
|
||||
pCur->isIncrblobHandle = 1;
|
||||
void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
|
||||
pCur->curFlags |= BTCF_Incrblob;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+5
-2
@@ -63,7 +63,9 @@ int sqlite3BtreeOpen(
|
||||
|
||||
int sqlite3BtreeClose(Btree*);
|
||||
int sqlite3BtreeSetCacheSize(Btree*,int);
|
||||
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
|
||||
#endif
|
||||
int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
|
||||
int sqlite3BtreeSyncDisabled(Btree*);
|
||||
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
|
||||
@@ -113,6 +115,7 @@ int sqlite3BtreeIncrVacuum(Btree *);
|
||||
|
||||
int sqlite3BtreeDropTable(Btree*, int, int*);
|
||||
int sqlite3BtreeClearTable(Btree*, int, int*);
|
||||
int sqlite3BtreeClearTableOfCursor(BtCursor*);
|
||||
void sqlite3BtreeTripAllCursors(Btree*, int);
|
||||
|
||||
void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
|
||||
@@ -187,7 +190,7 @@ char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
|
||||
struct Pager *sqlite3BtreePager(Btree*);
|
||||
|
||||
int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
void sqlite3BtreeCacheOverflow(BtCursor *);
|
||||
void sqlite3BtreeIncrblobCursor(BtCursor *);
|
||||
void sqlite3BtreeClearCursor(BtCursor *);
|
||||
int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
|
||||
void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
|
||||
|
||||
+14
-11
@@ -496,27 +496,30 @@ struct BtCursor {
|
||||
BtShared *pBt; /* The BtShared this cursor points to */
|
||||
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
|
||||
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
Pgno *aOverflow; /* Cache of overflow page locations */
|
||||
#endif
|
||||
Pgno pgnoRoot; /* The root page of this tree */
|
||||
CellInfo info; /* A parse of the cell we are pointing at */
|
||||
i64 nKey; /* Size of pKey, or last integer key */
|
||||
void *pKey; /* Saved key that was cursor's last known position */
|
||||
i64 nKey; /* Size of pKey, or last integer key */
|
||||
void *pKey; /* Saved key that was cursor last known position */
|
||||
Pgno pgnoRoot; /* The root page of this tree */
|
||||
int nOvflAlloc; /* Allocated size of aOverflow[] array */
|
||||
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
|
||||
u8 wrFlag; /* True if writable */
|
||||
u8 atLast; /* Cursor pointing to the last entry */
|
||||
u8 validNKey; /* True if info.nKey is valid */
|
||||
u8 curFlags; /* zero or more BTCF_* flags defined below */
|
||||
u8 eState; /* One of the CURSOR_XXX constants (see below) */
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
|
||||
#endif
|
||||
u8 hints; /* As configured by CursorSetHints() */
|
||||
i16 iPage; /* Index of current page in apPage */
|
||||
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
|
||||
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
|
||||
};
|
||||
|
||||
/*
|
||||
** Legal values for BtCursor.curFlags
|
||||
*/
|
||||
#define BTCF_WriteFlag 0x01 /* True if a write cursor */
|
||||
#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
|
||||
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
|
||||
#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
|
||||
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
|
||||
|
||||
/*
|
||||
** Potential values for BtCursor.eState.
|
||||
**
|
||||
|
||||
+32
-25
@@ -905,7 +905,7 @@ void sqlite3StartTable(
|
||||
pTable->iPKey = -1;
|
||||
pTable->pSchema = db->aDb[iDb].pSchema;
|
||||
pTable->nRef = 1;
|
||||
pTable->nRowEst = 1048576;
|
||||
pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
assert( pParse->pNewTable==0 );
|
||||
pParse->pNewTable = pTable;
|
||||
|
||||
@@ -2669,7 +2669,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
|
||||
/* Open the sorter cursor if we are to use one. */
|
||||
iSorter = pParse->nTab++;
|
||||
sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*)
|
||||
sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*)
|
||||
sqlite3KeyInfoRef(pKey), P4_KEYINFO);
|
||||
|
||||
/* Open the table. Loop through all rows of the table, inserting index
|
||||
@@ -2680,7 +2680,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
|
||||
sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
|
||||
sqlite3VdbeResolveLabel(v, iPartIdxLabel);
|
||||
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
|
||||
@@ -2730,15 +2730,15 @@ Index *sqlite3AllocateIndexObject(
|
||||
|
||||
nByte = ROUND8(sizeof(Index)) + /* Index structure */
|
||||
ROUND8(sizeof(char*)*nCol) + /* Index.azColl */
|
||||
ROUND8(sizeof(tRowcnt)*(nCol+1) + /* Index.aiRowEst */
|
||||
ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */
|
||||
sizeof(i16)*nCol + /* Index.aiColumn */
|
||||
sizeof(u8)*nCol); /* Index.aSortOrder */
|
||||
p = sqlite3DbMallocZero(db, nByte + nExtra);
|
||||
if( p ){
|
||||
char *pExtra = ((char*)p)+ROUND8(sizeof(Index));
|
||||
p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
|
||||
p->aiRowEst = (tRowcnt*)pExtra; pExtra += sizeof(tRowcnt)*(nCol+1);
|
||||
p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
|
||||
p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
|
||||
p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1);
|
||||
p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
|
||||
p->aSortOrder = (u8*)pExtra;
|
||||
p->nColumn = nCol;
|
||||
p->nKeyCol = nCol - 1;
|
||||
@@ -2968,7 +2968,7 @@ Index *sqlite3CreateIndex(
|
||||
if( db->mallocFailed ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowEst) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) );
|
||||
pIndex->zName = zExtra;
|
||||
zExtra += nName + 1;
|
||||
@@ -3018,7 +3018,7 @@ Index *sqlite3CreateIndex(
|
||||
pParse->checkSchema = 1;
|
||||
goto exit_create_index;
|
||||
}
|
||||
assert( pTab->nCol<=0x7fff && j<=0x7fff );
|
||||
assert( j<=0x7fff );
|
||||
pIndex->aiColumn[i] = (i16)j;
|
||||
if( pListItem->pExpr ){
|
||||
int nColl;
|
||||
@@ -3249,7 +3249,7 @@ exit_create_index:
|
||||
** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the
|
||||
** number of rows in the table that match any particular value of the
|
||||
** first column of the index. aiRowEst[2] is an estimate of the number
|
||||
** of rows that match any particular combiniation of the first 2 columns
|
||||
** of rows that match any particular combination of the first 2 columns
|
||||
** of the index. And so forth. It must always be the case that
|
||||
*
|
||||
** aiRowEst[N]<=aiRowEst[N-1]
|
||||
@@ -3260,20 +3260,27 @@ exit_create_index:
|
||||
** are based on typical values found in actual indices.
|
||||
*/
|
||||
void sqlite3DefaultRowEst(Index *pIdx){
|
||||
tRowcnt *a = pIdx->aiRowEst;
|
||||
/* 10, 9, 8, 7, 6 */
|
||||
LogEst aVal[] = { 33, 32, 30, 28, 26 };
|
||||
LogEst *a = pIdx->aiRowLogEst;
|
||||
int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
|
||||
int i;
|
||||
tRowcnt n;
|
||||
assert( a!=0 );
|
||||
a[0] = pIdx->pTable->nRowEst;
|
||||
if( a[0]<10 ) a[0] = 10;
|
||||
n = 10;
|
||||
for(i=1; i<=pIdx->nKeyCol; i++){
|
||||
a[i] = n;
|
||||
if( n>5 ) n--;
|
||||
}
|
||||
if( pIdx->onError!=OE_None ){
|
||||
a[pIdx->nKeyCol] = 1;
|
||||
|
||||
/* Set the first entry (number of rows in the index) to the estimated
|
||||
** number of rows in the table. Or 10, if the estimated number of rows
|
||||
** in the table is less than that. */
|
||||
a[0] = pIdx->pTable->nRowLogEst;
|
||||
if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
|
||||
|
||||
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
|
||||
** 6 and each subsequent value (if any) is 5. */
|
||||
memcpy(&a[1], aVal, nCopy*sizeof(LogEst));
|
||||
for(i=nCopy+1; i<=pIdx->nKeyCol; i++){
|
||||
a[i] = 23; assert( 23==sqlite3LogEst(5) );
|
||||
}
|
||||
|
||||
assert( 0==sqlite3LogEst(1) );
|
||||
if( pIdx->onError!=OE_None ) a[pIdx->nKeyCol] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3473,7 +3480,7 @@ SrcList *sqlite3SrcListEnlarge(
|
||||
assert( iStart<=pSrc->nSrc );
|
||||
|
||||
/* Allocate additional space if needed */
|
||||
if( pSrc->nSrc+nExtra>pSrc->nAlloc ){
|
||||
if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){
|
||||
SrcList *pNew;
|
||||
int nAlloc = pSrc->nSrc+nExtra;
|
||||
int nGot;
|
||||
@@ -3485,7 +3492,7 @@ SrcList *sqlite3SrcListEnlarge(
|
||||
}
|
||||
pSrc = pNew;
|
||||
nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1;
|
||||
pSrc->nAlloc = (u8)nGot;
|
||||
pSrc->nAlloc = nGot;
|
||||
}
|
||||
|
||||
/* Move existing slots that come after the newly inserted slots
|
||||
@@ -3493,7 +3500,7 @@ SrcList *sqlite3SrcListEnlarge(
|
||||
for(i=pSrc->nSrc-1; i>=iStart; i--){
|
||||
pSrc->a[i+nExtra] = pSrc->a[i];
|
||||
}
|
||||
pSrc->nSrc += (i8)nExtra;
|
||||
pSrc->nSrc += nExtra;
|
||||
|
||||
/* Zero the newly allocated slots */
|
||||
memset(&pSrc->a[iStart], 0, sizeof(pSrc->a[0])*nExtra);
|
||||
|
||||
@@ -215,6 +215,9 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
"OMIT_COMPOUND_SELECT",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_CTE
|
||||
"OMIT_CTE",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_DATETIME_FUNCS
|
||||
"OMIT_DATETIME_FUNCS",
|
||||
#endif
|
||||
|
||||
+16
-2
@@ -739,7 +739,7 @@ void sqlite3GenerateRowIndexDelete(
|
||||
&iPartIdxLabel, pPrior, r1);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
|
||||
sqlite3VdbeResolveLabel(v, iPartIdxLabel);
|
||||
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
||||
pPrior = pIdx;
|
||||
}
|
||||
}
|
||||
@@ -758,10 +758,11 @@ void sqlite3GenerateRowIndexDelete(
|
||||
**
|
||||
** If *piPartIdxLabel is not NULL, fill it in with a label and jump
|
||||
** to that label if pIdx is a partial index that should be skipped.
|
||||
** The label should be resolved using sqlite3ResolvePartIdxLabel().
|
||||
** A partial index should be skipped if its WHERE clause evaluates
|
||||
** to false or null. If pIdx is not a partial index, *piPartIdxLabel
|
||||
** will be set to zero which is an empty label that is ignored by
|
||||
** sqlite3VdbeResolveLabel().
|
||||
** sqlite3ResolvePartIdxLabel().
|
||||
**
|
||||
** The pPrior and regPrior parameters are used to implement a cache to
|
||||
** avoid unnecessary register loads. If pPrior is not NULL, then it is
|
||||
@@ -794,6 +795,7 @@ int sqlite3GenerateIndexKey(
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
|
||||
pParse->iPartIdxTab = iDataCur;
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
||||
SQLITE_JUMPIFNULL);
|
||||
}else{
|
||||
@@ -821,3 +823,15 @@ int sqlite3GenerateIndexKey(
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
||||
return regBase;
|
||||
}
|
||||
|
||||
/*
|
||||
** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label
|
||||
** because it was a partial index, then this routine should be called to
|
||||
** resolve that label.
|
||||
*/
|
||||
void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
|
||||
if( iLabel ){
|
||||
sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
}
|
||||
}
|
||||
|
||||
+24
-22
@@ -33,6 +33,7 @@
|
||||
char sqlite3ExprAffinity(Expr *pExpr){
|
||||
int op;
|
||||
pExpr = sqlite3ExprSkipCollate(pExpr);
|
||||
if( pExpr->flags & EP_Generic ) return SQLITE_AFF_NONE;
|
||||
op = pExpr->op;
|
||||
if( op==TK_SELECT ){
|
||||
assert( pExpr->flags&EP_xIsSelect );
|
||||
@@ -65,7 +66,11 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
** If a memory allocation error occurs, that fact is recorded in pParse->db
|
||||
** and the pExpr parameter is returned unchanged.
|
||||
*/
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){
|
||||
Expr *sqlite3ExprAddCollateToken(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pExpr, /* Add the "COLLATE" clause to this expression */
|
||||
const Token *pCollName /* Name of collating sequence */
|
||||
){
|
||||
if( pCollName->n>0 ){
|
||||
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
|
||||
if( pNew ){
|
||||
@@ -118,6 +123,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
Expr *p = pExpr;
|
||||
while( p ){
|
||||
int op = p->op;
|
||||
if( p->flags & EP_Generic ) break;
|
||||
if( op==TK_CAST || op==TK_UPLUS ){
|
||||
p = p->pLeft;
|
||||
continue;
|
||||
@@ -949,7 +955,6 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->iECursor = 0;
|
||||
pNew->nExpr = i = p->nExpr;
|
||||
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
|
||||
pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
|
||||
@@ -1062,7 +1067,6 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->addrOpenEphm[2] = -1;
|
||||
pNew->nSelectRow = p->nSelectRow;
|
||||
pNew->pWith = withDup(db, p->pWith);
|
||||
return pNew;
|
||||
@@ -1630,7 +1634,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
*prNotFound = rMayHaveNull = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
|
||||
}else{
|
||||
testcase( pParse->nQueryLoop>0 );
|
||||
pParse->nQueryLoop = 0;
|
||||
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
|
||||
eType = IN_INDEX_ROWID;
|
||||
@@ -1880,7 +1883,7 @@ int sqlite3CodeSubselect(
|
||||
if( testAddr>=0 ){
|
||||
sqlite3VdbeJumpHere(v, testAddr);
|
||||
}
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
|
||||
return rReg;
|
||||
}
|
||||
@@ -2015,7 +2018,7 @@ static void sqlite3ExprCodeIN(
|
||||
}
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
VdbeComment((v, "end IN expr"));
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
@@ -2198,15 +2201,14 @@ void sqlite3ExprCachePush(Parse *pParse){
|
||||
|
||||
/*
|
||||
** Remove from the column cache any entries that were added since the
|
||||
** the previous N Push operations. In other words, restore the cache
|
||||
** to the state it was in N Pushes ago.
|
||||
** the previous sqlite3ExprCachePush operation. In other words, restore
|
||||
** the cache to the state it was in prior the most recent Push.
|
||||
*/
|
||||
void sqlite3ExprCachePop(Parse *pParse, int N){
|
||||
void sqlite3ExprCachePop(Parse *pParse){
|
||||
int i;
|
||||
struct yColCache *p;
|
||||
assert( N>0 );
|
||||
assert( pParse->iCacheLevel>=N );
|
||||
pParse->iCacheLevel -= N;
|
||||
assert( pParse->iCacheLevel>=1 );
|
||||
pParse->iCacheLevel--;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
|
||||
printf("POP to %d\n", pParse->iCacheLevel);
|
||||
@@ -2335,7 +2337,7 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
|
||||
int i;
|
||||
struct yColCache *p;
|
||||
assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
|
||||
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1);
|
||||
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
|
||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
int x = p->iReg;
|
||||
if( x>=iFrom && x<iFrom+nReg ){
|
||||
@@ -2684,7 +2686,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3ExprCacheRemove(pParse, target, 1);
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, endCoalesce);
|
||||
break;
|
||||
@@ -2736,9 +2738,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
}
|
||||
|
||||
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
|
||||
sqlite3ExprCodeExprList(pParse, pFarg, r1,
|
||||
sqlite3ExprCodeExprList(pParse, pFarg, r1,
|
||||
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
|
||||
sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
|
||||
sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */
|
||||
}else{
|
||||
r1 = 0;
|
||||
}
|
||||
@@ -2958,13 +2960,13 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
|
||||
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
sqlite3VdbeResolveLabel(v, nextCase);
|
||||
}
|
||||
if( (nExpr&1)!=0 ){
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||
}
|
||||
@@ -3543,7 +3545,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
sqlite3VdbeResolveLabel(v, d2);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
break;
|
||||
}
|
||||
case TK_OR: {
|
||||
@@ -3551,7 +3553,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
break;
|
||||
}
|
||||
case TK_NOT: {
|
||||
@@ -3697,7 +3699,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
break;
|
||||
}
|
||||
case TK_OR: {
|
||||
@@ -3707,7 +3709,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
sqlite3ExprCachePush(pParse);
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
sqlite3VdbeResolveLabel(v, d2);
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
break;
|
||||
}
|
||||
case TK_NOT: {
|
||||
|
||||
+1
-1
@@ -1017,7 +1017,7 @@ static void charFunc(
|
||||
){
|
||||
unsigned char *z, *zOut;
|
||||
int i;
|
||||
zOut = z = sqlite3_malloc( argc*4 );
|
||||
zOut = z = sqlite3_malloc( argc*4+1 );
|
||||
if( z==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
|
||||
@@ -167,6 +167,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
0, /* nPage */
|
||||
0, /* mxParserStack */
|
||||
0, /* sharedCacheEnabled */
|
||||
SQLITE_DEFAULT_WORKER_THREADS, /* nWorker */
|
||||
/* All the rest should always be initialized to zero */
|
||||
0, /* isInit */
|
||||
0, /* inProgress */
|
||||
|
||||
+16
-8
@@ -101,13 +101,13 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
** Compute the affinity string for table pTab, if it has not already been
|
||||
** computed. As an optimization, omit trailing SQLITE_AFF_NONE affinities.
|
||||
**
|
||||
** If the affinity exists (if it is no entirely SQLITE_AFF_NONE values and
|
||||
** If the affinity exists (if it is no entirely SQLITE_AFF_NONE values) and
|
||||
** if iReg>0 then code an OP_Affinity opcode that will set the affinities
|
||||
** for register iReg and following. Or if affinities exists and iReg==0,
|
||||
** then just set the P4 operand of the previous opcode (which should be
|
||||
** an OP_MakeRecord) to the affinity string.
|
||||
**
|
||||
** A column affinity string has one character column:
|
||||
** A column affinity string has one character per column:
|
||||
**
|
||||
** Character Column affinity
|
||||
** ------------------------------
|
||||
@@ -148,10 +148,9 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
||||
|
||||
/*
|
||||
** Return non-zero if the table pTab in database iDb or any of its indices
|
||||
** have been opened at any point in the VDBE program beginning at location
|
||||
** iStartAddr throught the end of the program. This is used to see if
|
||||
** have been opened at any point in the VDBE program. This is used to see if
|
||||
** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
|
||||
** run without using temporary table for the results of the SELECT.
|
||||
** run without using a temporary table for the results of the SELECT.
|
||||
*/
|
||||
static int readsTable(Parse *p, int iDb, Table *pTab){
|
||||
Vdbe *v = sqlite3GetVdbe(p);
|
||||
@@ -1866,15 +1865,24 @@ static int xferOptimization(
|
||||
return 0; /* Both tables must have the same INTEGER PRIMARY KEY */
|
||||
}
|
||||
for(i=0; i<pDest->nCol; i++){
|
||||
if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){
|
||||
Column *pDestCol = &pDest->aCol[i];
|
||||
Column *pSrcCol = &pSrc->aCol[i];
|
||||
if( pDestCol->affinity!=pSrcCol->affinity ){
|
||||
return 0; /* Affinity must be the same on all columns */
|
||||
}
|
||||
if( !xferCompatibleCollation(pDest->aCol[i].zColl, pSrc->aCol[i].zColl) ){
|
||||
if( !xferCompatibleCollation(pDestCol->zColl, pSrcCol->zColl) ){
|
||||
return 0; /* Collating sequence must be the same on all columns */
|
||||
}
|
||||
if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){
|
||||
if( pDestCol->notNull && !pSrcCol->notNull ){
|
||||
return 0; /* tab2 must be NOT NULL if tab1 is */
|
||||
}
|
||||
/* Default values for second and subsequent columns need to match. */
|
||||
if( i>0
|
||||
&& ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
|
||||
|| (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
|
||||
){
|
||||
return 0; /* Default values must be the same for all columns */
|
||||
}
|
||||
}
|
||||
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
||||
if( pDestIdx->onError!=OE_None ){
|
||||
|
||||
+32
@@ -515,6 +515,13 @@ int sqlite3_config(int op, ...){
|
||||
}
|
||||
#endif
|
||||
|
||||
case SQLITE_CONFIG_WORKER_THREADS: {
|
||||
int n = va_arg(ap, int);
|
||||
if( n>SQLITE_MAX_WORKER_THREADS ) n = SQLITE_MAX_WORKER_THREADS;
|
||||
if( n>=0 ) sqlite3GlobalConfig.nWorker = n;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
@@ -800,6 +807,7 @@ static void disconnectAllVtab(sqlite3 *db){
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3VtabUnlockList(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
#else
|
||||
UNUSED_PARAMETER(db);
|
||||
@@ -2496,6 +2504,7 @@ static int openDatabase(
|
||||
db->nextAutovac = -1;
|
||||
db->szMmap = sqlite3GlobalConfig.szMmap;
|
||||
db->nextPagesize = 0;
|
||||
db->nMaxSorterMmap = 0x7FFFFFFF;
|
||||
db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill
|
||||
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
|
||||
| SQLITE_AutoIndex
|
||||
@@ -3204,6 +3213,22 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER);
|
||||
**
|
||||
** The integer returned reveals the byte-order of the computer on which
|
||||
** SQLite is running:
|
||||
**
|
||||
** 1 big-endian, determined at run-time
|
||||
** 10 little-endian, determined at run-time
|
||||
** 432101 big-endian, determined at compile-time
|
||||
** 123410 little-endian, determined at compile-time
|
||||
*/
|
||||
case SQLITE_TESTCTRL_BYTEORDER: {
|
||||
rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN;
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
|
||||
**
|
||||
** Set the nReserve size to N for the main database on the database
|
||||
@@ -3322,6 +3347,13 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */
|
||||
case SQLITE_TESTCTRL_SORTER_MMAP: {
|
||||
sqlite3 *db = va_arg(ap, sqlite3*);
|
||||
db->nMaxSorterMmap = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
va_end(ap);
|
||||
#endif /* SQLITE_OMIT_BUILTIN_TEST */
|
||||
|
||||
+1
-1
@@ -248,7 +248,7 @@ static void *memsys5MallocUnsafe(int nByte){
|
||||
** block. If not, then split a block of the next larger power of
|
||||
** two in order to create a new free block of size iLogsize.
|
||||
*/
|
||||
for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
|
||||
for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){}
|
||||
if( iBin>LOGMAX ){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ int sqlite3MutexEnd(void){
|
||||
*/
|
||||
sqlite3_mutex *sqlite3_mutex_alloc(int id){
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
if( sqlite3_initialize() ) return 0;
|
||||
if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
|
||||
#endif
|
||||
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
|
||||
}
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
|
||||
** that means that a mutex could not be allocated.
|
||||
*/
|
||||
static sqlite3_mutex *debugMutexAlloc(int id){
|
||||
static sqlite3_debug_mutex aStatic[6];
|
||||
static sqlite3_debug_mutex aStatic[8];
|
||||
sqlite3_debug_mutex *pNew = 0;
|
||||
switch( id ){
|
||||
case SQLITE_MUTEX_FAST:
|
||||
|
||||
+5
-1
@@ -96,10 +96,12 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_OPEN
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_PMEM
|
||||
** <li> SQLITE_MUTEX_STATIC_APP1
|
||||
** <li> SQLITE_MUTEX_STATIC_APP2
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
@@ -133,6 +135,8 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER
|
||||
};
|
||||
sqlite3_mutex *p;
|
||||
|
||||
+6
-2
@@ -93,7 +93,9 @@ static int winMutexNotheld(sqlite3_mutex *p){
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
*/
|
||||
static sqlite3_mutex winMutex_staticMutexes[6] = {
|
||||
static sqlite3_mutex winMutex_staticMutexes[] = {
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
@@ -159,10 +161,12 @@ static int winMutexEnd(void){
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_OPEN
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_PMEM
|
||||
** <li> SQLITE_MUTEX_STATIC_APP1
|
||||
** <li> SQLITE_MUTEX_STATIC_APP2
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
|
||||
+59
-23
@@ -323,6 +323,7 @@ static int posixFchown(int fd, uid_t uid, gid_t gid){
|
||||
|
||||
/* Forward reference */
|
||||
static int openDirectory(const char*, int*);
|
||||
static int unixGetpagesize(void);
|
||||
|
||||
/*
|
||||
** Many system calls are accessed through pointer-to-functions so that
|
||||
@@ -446,6 +447,9 @@ static struct unix_syscall {
|
||||
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
|
||||
#endif
|
||||
|
||||
{ "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
|
||||
#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
|
||||
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
/*
|
||||
@@ -4105,6 +4109,36 @@ static int unixShmSystemLock(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the system page size.
|
||||
**
|
||||
** This function should not be called directly by other code in this file.
|
||||
** Instead, it should be called via macro osGetpagesize().
|
||||
*/
|
||||
static int unixGetpagesize(void){
|
||||
#if defined(_BSD_SOURCE)
|
||||
return getpagesize();
|
||||
#else
|
||||
return (int)sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the minimum number of 32KB shm regions that should be mapped at
|
||||
** a time, assuming that each mapping must be an integer multiple of the
|
||||
** current system page-size.
|
||||
**
|
||||
** Usually, this is 1. The exception seems to be systems that are configured
|
||||
** to use 64KB pages - in this case each mapping must cover at least two
|
||||
** shm regions.
|
||||
*/
|
||||
static int unixShmRegionPerMap(void){
|
||||
int shmsz = 32*1024; /* SHM region size */
|
||||
int pgsz = osGetpagesize(); /* System page size */
|
||||
assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */
|
||||
if( pgsz<shmsz ) return 1;
|
||||
return pgsz/shmsz;
|
||||
}
|
||||
|
||||
/*
|
||||
** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
|
||||
@@ -4116,10 +4150,11 @@ static void unixShmPurge(unixFile *pFd){
|
||||
unixShmNode *p = pFd->pInode->pShmNode;
|
||||
assert( unixMutexHeld() );
|
||||
if( p && p->nRef==0 ){
|
||||
int nShmPerMap = unixShmRegionPerMap();
|
||||
int i;
|
||||
assert( p->pInode==pFd->pInode );
|
||||
sqlite3_mutex_free(p->mutex);
|
||||
for(i=0; i<p->nRegion; i++){
|
||||
for(i=0; i<p->nRegion; i+=nShmPerMap){
|
||||
if( p->h>=0 ){
|
||||
osMunmap(p->apRegion[i], p->szRegion);
|
||||
}else{
|
||||
@@ -4326,6 +4361,8 @@ static int unixShmMap(
|
||||
unixShm *p;
|
||||
unixShmNode *pShmNode;
|
||||
int rc = SQLITE_OK;
|
||||
int nShmPerMap = unixShmRegionPerMap();
|
||||
int nReqRegion;
|
||||
|
||||
/* If the shared-memory file has not yet been opened, open it now. */
|
||||
if( pDbFd->pShm==0 ){
|
||||
@@ -4341,9 +4378,12 @@ static int unixShmMap(
|
||||
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
|
||||
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
|
||||
|
||||
if( pShmNode->nRegion<=iRegion ){
|
||||
/* Minimum number of regions required to be mapped. */
|
||||
nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
|
||||
|
||||
if( pShmNode->nRegion<nReqRegion ){
|
||||
char **apNew; /* New apRegion[] array */
|
||||
int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
|
||||
int nByte = nReqRegion*szRegion; /* Minimum required file size */
|
||||
struct stat sStat; /* Used by fstat() */
|
||||
|
||||
pShmNode->szRegion = szRegion;
|
||||
@@ -4392,17 +4432,19 @@ static int unixShmMap(
|
||||
|
||||
/* Map the requested memory region into this processes address space. */
|
||||
apNew = (char **)sqlite3_realloc(
|
||||
pShmNode->apRegion, (iRegion+1)*sizeof(char *)
|
||||
pShmNode->apRegion, nReqRegion*sizeof(char *)
|
||||
);
|
||||
if( !apNew ){
|
||||
rc = SQLITE_IOERR_NOMEM;
|
||||
goto shmpage_out;
|
||||
}
|
||||
pShmNode->apRegion = apNew;
|
||||
while(pShmNode->nRegion<=iRegion){
|
||||
while( pShmNode->nRegion<nReqRegion ){
|
||||
int nMap = szRegion*nShmPerMap;
|
||||
int i;
|
||||
void *pMem;
|
||||
if( pShmNode->h>=0 ){
|
||||
pMem = osMmap(0, szRegion,
|
||||
pMem = osMmap(0, nMap,
|
||||
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
|
||||
);
|
||||
@@ -4418,8 +4460,11 @@ static int unixShmMap(
|
||||
}
|
||||
memset(pMem, 0, szRegion);
|
||||
}
|
||||
pShmNode->apRegion[pShmNode->nRegion] = pMem;
|
||||
pShmNode->nRegion++;
|
||||
|
||||
for(i=0; i<nShmPerMap; i++){
|
||||
pShmNode->apRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i];
|
||||
}
|
||||
pShmNode->nRegion += nShmPerMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4633,19 +4678,6 @@ static void unixUnmapfile(unixFile *pFd){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the system page size.
|
||||
*/
|
||||
static int unixGetPagesize(void){
|
||||
#if HAVE_MREMAP
|
||||
return 512;
|
||||
#elif defined(_BSD_SOURCE)
|
||||
return getpagesize();
|
||||
#else
|
||||
return (int)sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to set the size of the memory mapping maintained by file
|
||||
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
|
||||
@@ -4682,8 +4714,12 @@ static void unixRemapfile(
|
||||
if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
|
||||
|
||||
if( pOrig ){
|
||||
const int szSyspage = unixGetPagesize();
|
||||
#if HAVE_MREMAP
|
||||
i64 nReuse = pFd->mmapSize;
|
||||
#else
|
||||
const int szSyspage = osGetpagesize();
|
||||
i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
|
||||
#endif
|
||||
u8 *pReq = &pOrig[nReuse];
|
||||
|
||||
/* Unmap any pages of the existing mapping that cannot be reused. */
|
||||
@@ -7429,7 +7465,7 @@ int sqlite3_os_init(void){
|
||||
|
||||
/* Double-check that the aSyscall[] array has been constructed
|
||||
** correctly. See ticket [bb3a86e890c8e96ab] */
|
||||
assert( ArraySize(aSyscall)==24 );
|
||||
assert( ArraySize(aSyscall)==25 );
|
||||
|
||||
/* Register all VFSes defined in the aVfs[] array */
|
||||
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
|
||||
|
||||
+125
-5
@@ -267,6 +267,7 @@ struct winFile {
|
||||
sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */
|
||||
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
|
||||
#endif
|
||||
SQLiteThread *preCacheThread; /* Thread used to pre-cache file contents */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -948,11 +949,7 @@ static struct win_syscall {
|
||||
#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
|
||||
DWORD))aSyscall[63].pCurrent)
|
||||
|
||||
#if SQLITE_OS_WINRT
|
||||
{ "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
|
||||
#else
|
||||
{ "WaitForSingleObjectEx", (SYSCALL)0, 0 },
|
||||
#endif
|
||||
|
||||
#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
|
||||
BOOL))aSyscall[64].pCurrent)
|
||||
@@ -1048,6 +1045,11 @@ static struct win_syscall {
|
||||
#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
|
||||
LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent)
|
||||
|
||||
{ "DuplicateHandle", (SYSCALL)DuplicateHandle, 0 },
|
||||
|
||||
#define osDuplicateHandle ((BOOL(WINAPI*)(HANDLE, \
|
||||
HANDLE,HANDLE,LPHANDLE,DWORD,BOOL,DWORD))aSyscall[76].pCurrent)
|
||||
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
/*
|
||||
@@ -1279,6 +1281,13 @@ void sqlite3_win32_sleep(DWORD milliseconds){
|
||||
#endif
|
||||
}
|
||||
|
||||
DWORD sqlite3Win32Wait(HANDLE hObject){
|
||||
DWORD rc;
|
||||
while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
|
||||
TRUE))==WAIT_IO_COMPLETION ){}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
|
||||
** or WinCE. Return false (zero) for Win95, Win98, or WinME.
|
||||
@@ -2351,6 +2360,13 @@ static int winClose(sqlite3_file *id){
|
||||
assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
|
||||
OSTRACE(("CLOSE file=%p\n", pFile->h));
|
||||
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
if( pFile->preCacheThread ){
|
||||
void *pOut = 0;
|
||||
sqlite3ThreadJoin(pFile->preCacheThread, &pOut);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
winUnmapfile(pFile);
|
||||
#endif
|
||||
@@ -3195,6 +3211,84 @@ static int winDeviceCharacteristics(sqlite3_file *id){
|
||||
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
|
||||
}
|
||||
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
/*
|
||||
** Thread routine that attempts to read the entire file. This is used to
|
||||
** provide a hint to the operating system that the entire file should be held
|
||||
** in the cache.
|
||||
*/
|
||||
static void *winPreCacheThread(void *pCtx){
|
||||
winFile *pFile = (winFile*)pCtx;
|
||||
void *pBuf = 0;
|
||||
DWORD lastErrno;
|
||||
HANDLE dupHandle = NULL;
|
||||
DWORD dwSize, dwRet;
|
||||
DWORD dwAmt;
|
||||
DWORD nRead;
|
||||
|
||||
if( !osDuplicateHandle(GetCurrentProcess(), pFile->h, GetCurrentProcess(),
|
||||
&dupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) ){
|
||||
pFile->lastErrno = osGetLastError();
|
||||
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR\n", dupHandle));
|
||||
return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR, pFile->lastErrno,
|
||||
"winPreCacheThread1", pFile->zPath));
|
||||
}
|
||||
dwSize = osSetFilePointer(dupHandle, 0, 0, FILE_END);
|
||||
if( (dwSize==INVALID_SET_FILE_POINTER
|
||||
&& ((lastErrno = osGetLastError())!=NO_ERROR)) ){
|
||||
pFile->lastErrno = lastErrno;
|
||||
osCloseHandle(dupHandle);
|
||||
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_SEEK\n", dupHandle));
|
||||
return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
|
||||
"winPreCacheThread2", pFile->zPath));
|
||||
}
|
||||
dwRet = osSetFilePointer(dupHandle, 0, 0, FILE_BEGIN);
|
||||
if( (dwRet==INVALID_SET_FILE_POINTER
|
||||
&& ((lastErrno = osGetLastError())!=NO_ERROR)) ){
|
||||
pFile->lastErrno = lastErrno;
|
||||
osCloseHandle(dupHandle);
|
||||
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_SEEK\n", dupHandle));
|
||||
return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
|
||||
"winPreCacheThread3", pFile->zPath));
|
||||
}
|
||||
dwAmt = 4194304; /* TODO: Tuning. */
|
||||
if( dwSize<dwAmt ){
|
||||
dwAmt = dwSize;
|
||||
}
|
||||
pBuf = sqlite3MallocZero( dwAmt );
|
||||
if( pBuf==0 ){
|
||||
osCloseHandle(dupHandle);
|
||||
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_NOMEM\n", dupHandle));
|
||||
return SQLITE_INT_TO_PTR(SQLITE_IOERR_NOMEM);
|
||||
}
|
||||
while( 1 ){
|
||||
if( !osReadFile(dupHandle, pBuf, dwAmt, &nRead, 0) ){
|
||||
pFile->lastErrno = osGetLastError();
|
||||
sqlite3_free(pBuf);
|
||||
osCloseHandle(dupHandle);
|
||||
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_READ\n", dupHandle));
|
||||
return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
|
||||
"winPreCacheThread4", pFile->zPath));
|
||||
}
|
||||
if( nRead<dwAmt ){
|
||||
sqlite3_free(pBuf);
|
||||
osCloseHandle(dupHandle);
|
||||
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_SHORT_READ\n", dupHandle));
|
||||
return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_SHORT_READ,
|
||||
pFile->lastErrno,
|
||||
"winPreCacheThread5", pFile->zPath));
|
||||
}
|
||||
dwSize -= dwAmt;
|
||||
if( dwSize==0 ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3_free(pBuf);
|
||||
osCloseHandle(dupHandle);
|
||||
return SQLITE_INT_TO_PTR(SQLITE_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Windows will only let you create file view mappings
|
||||
** on allocation size granularity boundaries.
|
||||
@@ -4701,6 +4795,15 @@ static int winOpen(
|
||||
pFile->mmapSizeActual = 0;
|
||||
pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap;
|
||||
#endif
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
sqlite3ThreadCreate(&pFile->preCacheThread, winPreCacheThread, pFile);
|
||||
|
||||
{
|
||||
void *pOut = 0;
|
||||
sqlite3ThreadJoin(pFile->preCacheThread, &pOut);
|
||||
pFile->preCacheThread = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
OpenCounter(+1);
|
||||
return rc;
|
||||
@@ -5137,8 +5240,25 @@ static int winFullPathname(
|
||||
*/
|
||||
static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
|
||||
HANDLE h;
|
||||
#if defined(__CYGWIN__)
|
||||
int nFull = pVfs->mxPathname+1;
|
||||
char *zFull = sqlite3MallocZero( nFull );
|
||||
void *zConverted = 0;
|
||||
if( zFull==0 ){
|
||||
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
|
||||
return 0;
|
||||
}
|
||||
if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){
|
||||
sqlite3_free(zFull);
|
||||
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
|
||||
return 0;
|
||||
}
|
||||
zConverted = winConvertFromUtf8Filename(zFull);
|
||||
sqlite3_free(zFull);
|
||||
#else
|
||||
void *zConverted = winConvertFromUtf8Filename(zFilename);
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
#endif
|
||||
if( zConverted==0 ){
|
||||
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
|
||||
return 0;
|
||||
@@ -5402,7 +5522,7 @@ int sqlite3_os_init(void){
|
||||
|
||||
/* Double-check that the aSyscall[] array has been constructed
|
||||
** correctly. See ticket [bb3a86e890c8e96ab] */
|
||||
assert( ArraySize(aSyscall)==76 );
|
||||
assert( ArraySize(aSyscall)==77 );
|
||||
|
||||
/* get memory map allocation granularity */
|
||||
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
|
||||
|
||||
+10
-9
@@ -1624,12 +1624,11 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
||||
|
||||
if( !zMaster
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|
||||
|| !isOpen(pPager->jfd)
|
||||
){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pPager->setMaster = 1;
|
||||
assert( isOpen(pPager->jfd) );
|
||||
assert( pPager->journalHdr <= pPager->journalOff );
|
||||
|
||||
/* Calculate the length in bytes and the checksum of zMaster */
|
||||
@@ -4889,15 +4888,17 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
||||
if( rc==SQLITE_OK && !locked ){
|
||||
Pgno nPage; /* Number of pages in database file */
|
||||
|
||||
/* Check the size of the database file. If it consists of 0 pages,
|
||||
** then delete the journal file. See the header comment above for
|
||||
** the reasoning here. Delete the obsolete journal file under
|
||||
** a RESERVED lock to avoid race conditions and to avoid violating
|
||||
** [H33020].
|
||||
*/
|
||||
rc = pagerPagecount(pPager, &nPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( nPage==0 ){
|
||||
/* If the database is zero pages in size, that means that either (1) the
|
||||
** journal is a remnant from a prior database with the same name where
|
||||
** the database file but not the journal was deleted, or (2) the initial
|
||||
** transaction that populates a new database is being rolled back.
|
||||
** In either case, the journal file can be deleted. However, take care
|
||||
** not to delete the journal file if it is already open due to
|
||||
** journal_mode=PERSIST.
|
||||
*/
|
||||
if( nPage==0 && !jrnlOpen ){
|
||||
sqlite3BeginBenignMalloc();
|
||||
if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){
|
||||
sqlite3OsDelete(pVfs, pPager->zJournal, 0);
|
||||
|
||||
+27
@@ -1020,6 +1020,33 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
*/
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[N]);
|
||||
sqlite3ExprDelete(pParse->db, X.pExpr);
|
||||
}else if( Y->nExpr==1 ){
|
||||
/* Expressions of the form:
|
||||
**
|
||||
** expr1 IN (?1)
|
||||
** expr1 NOT IN (?2)
|
||||
**
|
||||
** with exactly one value on the RHS can be simplified to something
|
||||
** like this:
|
||||
**
|
||||
** expr1 == ?1
|
||||
** expr1 <> ?2
|
||||
**
|
||||
** But, the RHS of the == or <> is marked with the EP_Generic flag
|
||||
** so that it may not contribute to the computation of comparison
|
||||
** affinity or the collating sequence to use for comparison. Otherwise,
|
||||
** the semantics would be subtly different from IN or NOT IN.
|
||||
*/
|
||||
Expr *pRHS = Y->a[0].pExpr;
|
||||
Y->a[0].pExpr = 0;
|
||||
sqlite3ExprListDelete(pParse->db, Y);
|
||||
/* pRHS cannot be NULL because a malloc error would have been detected
|
||||
** before now and control would have never reached this point */
|
||||
if( ALWAYS(pRHS) ){
|
||||
pRHS->flags &= ~EP_Collate;
|
||||
pRHS->flags |= EP_Generic;
|
||||
}
|
||||
A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, X.pExpr, pRHS, 0);
|
||||
}else{
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
|
||||
if( A.pExpr ){
|
||||
|
||||
+9
-7
@@ -824,7 +824,7 @@ void sqlite3Pragma(
|
||||
** size of historical compatibility.
|
||||
*/
|
||||
case PragTyp_DEFAULT_CACHE_SIZE: {
|
||||
static const int iLn = __LINE__+2;
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList getCacheSize[] = {
|
||||
{ OP_Transaction, 0, 0, 0}, /* 0 */
|
||||
{ OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */
|
||||
@@ -1087,7 +1087,7 @@ void sqlite3Pragma(
|
||||
** file. Before writing to meta[6], check that meta[3] indicates
|
||||
** that this really is an auto-vacuum capable database.
|
||||
*/
|
||||
static const int iLn = __LINE__+2;
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList setMeta6[] = {
|
||||
{ OP_Transaction, 0, 1, 0}, /* 0 */
|
||||
{ OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
|
||||
@@ -1488,13 +1488,15 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 2);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
(int)sqlite3LogEstToInt(pTab->szTabRow), 3);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, (int)pTab->nRowEst, 4);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
(int)sqlite3LogEstToInt(pTab->nRowLogEst), 4);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
(int)sqlite3LogEstToInt(pIdx->szIdxRow), 3);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, (int)pIdx->aiRowEst[0], 4);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
(int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]), 4);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
|
||||
}
|
||||
}
|
||||
@@ -1790,7 +1792,7 @@ void sqlite3Pragma(
|
||||
** messages have been generated, output OK. Otherwise output the
|
||||
** error message
|
||||
*/
|
||||
static const int iLn = __LINE__+2;
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList endCode[] = {
|
||||
{ OP_AddImm, 1, 0, 0}, /* 0 */
|
||||
{ OP_IfNeg, 1, 0, 0}, /* 1 */
|
||||
@@ -1875,7 +1877,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
||||
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
|
||||
P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp2(v, OP_Move, 2, 4);
|
||||
sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
@@ -1928,7 +1930,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
sqlite3VdbeJumpHere(v, jmp4);
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
sqlite3VdbeResolveLabel(v, jmp3);
|
||||
sqlite3ResolvePartIdxLabel(pParse, jmp3);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, loopTop-1);
|
||||
|
||||
+84
-77
@@ -134,20 +134,6 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
|
||||
}
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
|
||||
/*
|
||||
** Append N space characters to the given string buffer.
|
||||
*/
|
||||
void sqlite3AppendSpace(StrAccum *pAccum, int N){
|
||||
static const char zSpaces[] = " ";
|
||||
while( N>=(int)sizeof(zSpaces)-1 ){
|
||||
sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
|
||||
N -= sizeof(zSpaces)-1;
|
||||
}
|
||||
if( N>0 ){
|
||||
sqlite3StrAccumAppend(pAccum, zSpaces, N);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the StrAccum object to an error mode.
|
||||
*/
|
||||
@@ -237,11 +223,9 @@ void sqlite3VXPrintf(
|
||||
}
|
||||
for(; (c=(*fmt))!=0; ++fmt){
|
||||
if( c!='%' ){
|
||||
int amt;
|
||||
bufpt = (char *)fmt;
|
||||
amt = 1;
|
||||
while( (c=(*++fmt))!='%' && c!=0 ) amt++;
|
||||
sqlite3StrAccumAppend(pAccum, bufpt, amt);
|
||||
while( (c=(*++fmt))!='%' && c!=0 ){};
|
||||
sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
|
||||
if( c==0 ) break;
|
||||
}
|
||||
if( (c=(*++fmt))==0 ){
|
||||
@@ -422,10 +406,8 @@ void sqlite3VXPrintf(
|
||||
*(--bufpt) = zOrd[x*2];
|
||||
}
|
||||
{
|
||||
register const char *cset; /* Use registers for speed */
|
||||
register int base;
|
||||
cset = &aDigits[infop->charset];
|
||||
base = infop->base;
|
||||
const char *cset = &aDigits[infop->charset];
|
||||
u8 base = infop->base;
|
||||
do{ /* Convert to ascii */
|
||||
*(--bufpt) = cset[longvalue%base];
|
||||
longvalue = longvalue/base;
|
||||
@@ -729,29 +711,89 @@ void sqlite3VXPrintf(
|
||||
** "length" characters long. The field width is "width". Do
|
||||
** the output.
|
||||
*/
|
||||
if( !flag_leftjustify ){
|
||||
register int nspace;
|
||||
nspace = width-length;
|
||||
if( nspace>0 ){
|
||||
sqlite3AppendSpace(pAccum, nspace);
|
||||
}
|
||||
}
|
||||
if( length>0 ){
|
||||
sqlite3StrAccumAppend(pAccum, bufpt, length);
|
||||
}
|
||||
if( flag_leftjustify ){
|
||||
register int nspace;
|
||||
nspace = width-length;
|
||||
if( nspace>0 ){
|
||||
sqlite3AppendSpace(pAccum, nspace);
|
||||
}
|
||||
}
|
||||
width -= length;
|
||||
if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
|
||||
sqlite3StrAccumAppend(pAccum, bufpt, length);
|
||||
if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
|
||||
|
||||
if( zExtra ) sqlite3_free(zExtra);
|
||||
}/* End for loop over the format string */
|
||||
} /* End of function */
|
||||
|
||||
/*
|
||||
** Append N bytes of text from z to the StrAccum object.
|
||||
** Enlarge the memory allocation on a StrAccum object so that it is
|
||||
** able to accept at least N more bytes of text.
|
||||
**
|
||||
** Return the number of bytes of text that StrAccum is able to accept
|
||||
** after the attempted enlargement. The value returned might be zero.
|
||||
*/
|
||||
static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
|
||||
char *zNew;
|
||||
assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
|
||||
if( p->accError ){
|
||||
testcase(p->accError==STRACCUM_TOOBIG);
|
||||
testcase(p->accError==STRACCUM_NOMEM);
|
||||
return 0;
|
||||
}
|
||||
if( !p->useMalloc ){
|
||||
N = p->nAlloc - p->nChar - 1;
|
||||
setStrAccumError(p, STRACCUM_TOOBIG);
|
||||
return N;
|
||||
}else{
|
||||
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
|
||||
i64 szNew = p->nChar;
|
||||
szNew += N + 1;
|
||||
if( szNew > p->mxAlloc ){
|
||||
sqlite3StrAccumReset(p);
|
||||
setStrAccumError(p, STRACCUM_TOOBIG);
|
||||
return 0;
|
||||
}else{
|
||||
p->nAlloc = (int)szNew;
|
||||
}
|
||||
if( p->useMalloc==1 ){
|
||||
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
|
||||
}else{
|
||||
zNew = sqlite3_realloc(zOld, p->nAlloc);
|
||||
}
|
||||
if( zNew ){
|
||||
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
|
||||
p->zText = zNew;
|
||||
}else{
|
||||
sqlite3StrAccumReset(p);
|
||||
setStrAccumError(p, STRACCUM_NOMEM);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
/*
|
||||
** Append N space characters to the given string buffer.
|
||||
*/
|
||||
void sqlite3AppendSpace(StrAccum *p, int N){
|
||||
if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
|
||||
while( (N--)>0 ) p->zText[p->nChar++] = ' ';
|
||||
}
|
||||
|
||||
/*
|
||||
** The StrAccum "p" is not large enough to accept N new bytes of z[].
|
||||
** So enlarge if first, then do the append.
|
||||
**
|
||||
** This is a helper routine to sqlite3StrAccumAppend() that does special-case
|
||||
** work (enlarging the buffer) using tail recursion, so that the
|
||||
** sqlite3StrAccumAppend() routine can use fast calling semantics.
|
||||
*/
|
||||
static void enlargeAndAppend(StrAccum *p, const char *z, int N){
|
||||
N = sqlite3StrAccumEnlarge(p, N);
|
||||
if( N>0 ){
|
||||
memcpy(&p->zText[p->nChar], z, N);
|
||||
p->nChar += N;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Append N bytes of text from z to the StrAccum object. Increase the
|
||||
** size of the memory allocation for StrAccum if necessary.
|
||||
*/
|
||||
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
assert( z!=0 );
|
||||
@@ -759,43 +801,8 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
assert( N>=0 );
|
||||
assert( p->accError==0 || p->nAlloc==0 );
|
||||
if( p->nChar+N >= p->nAlloc ){
|
||||
char *zNew;
|
||||
if( p->accError ){
|
||||
testcase(p->accError==STRACCUM_TOOBIG);
|
||||
testcase(p->accError==STRACCUM_NOMEM);
|
||||
return;
|
||||
}
|
||||
if( !p->useMalloc ){
|
||||
N = p->nAlloc - p->nChar - 1;
|
||||
setStrAccumError(p, STRACCUM_TOOBIG);
|
||||
if( N<=0 ){
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
|
||||
i64 szNew = p->nChar;
|
||||
szNew += N + 1;
|
||||
if( szNew > p->mxAlloc ){
|
||||
sqlite3StrAccumReset(p);
|
||||
setStrAccumError(p, STRACCUM_TOOBIG);
|
||||
return;
|
||||
}else{
|
||||
p->nAlloc = (int)szNew;
|
||||
}
|
||||
if( p->useMalloc==1 ){
|
||||
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
|
||||
}else{
|
||||
zNew = sqlite3_realloc(zOld, p->nAlloc);
|
||||
}
|
||||
if( zNew ){
|
||||
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
|
||||
p->zText = zNew;
|
||||
}else{
|
||||
sqlite3StrAccumReset(p);
|
||||
setStrAccumError(p, STRACCUM_NOMEM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
enlargeAndAppend(p,z,N);
|
||||
return;
|
||||
}
|
||||
assert( p->zText );
|
||||
memcpy(&p->zText[p->nChar], z, N);
|
||||
|
||||
+3
-3
@@ -112,8 +112,8 @@ struct RowSet {
|
||||
struct RowSetEntry *pFresh; /* Source of new entry objects */
|
||||
struct RowSetEntry *pForest; /* List of binary trees of entries */
|
||||
u16 nFresh; /* Number of objects on pFresh */
|
||||
u8 rsFlags; /* Various flags */
|
||||
u8 iBatch; /* Current insert batch */
|
||||
u16 rsFlags; /* Various flags */
|
||||
int iBatch; /* Current insert batch */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -447,7 +447,7 @@ int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
|
||||
** on pRowSet->pEntry, then sort those entires into the forest at
|
||||
** pRowSet->pForest so that they can be tested.
|
||||
*/
|
||||
int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){
|
||||
int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
|
||||
struct RowSetEntry *p, *pTree;
|
||||
|
||||
/* This routine is never called after sqlite3RowSetNext() */
|
||||
|
||||
+284
-155
@@ -14,6 +14,34 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** An instance of the following object is used to record information about
|
||||
** how to process the DISTINCT keyword, to simplify passing that information
|
||||
** into the selectInnerLoop() routine.
|
||||
*/
|
||||
typedef struct DistinctCtx DistinctCtx;
|
||||
struct DistinctCtx {
|
||||
u8 isTnct; /* True if the DISTINCT keyword is present */
|
||||
u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
|
||||
int tabTnct; /* Ephemeral table used for DISTINCT processing */
|
||||
int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the following object is used to record information about
|
||||
** the ORDER BY (or GROUP BY) clause of query is being coded.
|
||||
*/
|
||||
typedef struct SortCtx SortCtx;
|
||||
struct SortCtx {
|
||||
ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */
|
||||
int nOBSat; /* Number of ORDER BY terms satisfied by indices */
|
||||
int iECursor; /* Cursor number for the sorter */
|
||||
int regReturn; /* Register holding block-output return address */
|
||||
int labelBkOut; /* Start label for the block-output subroutine */
|
||||
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
|
||||
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
|
||||
};
|
||||
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
|
||||
|
||||
/*
|
||||
** Delete all the content of a Select structure but do not deallocate
|
||||
@@ -87,7 +115,6 @@ Select *sqlite3SelectNew(
|
||||
assert( pOffset==0 || pLimit!=0 );
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->addrOpenEphm[2] = -1;
|
||||
if( db->mallocFailed ) {
|
||||
clearSelect(db, pNew);
|
||||
if( pNew!=&standin ) sqlite3DbFree(db, pNew);
|
||||
@@ -419,34 +446,93 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Forward reference */
|
||||
static KeyInfo *keyInfoFromExprList(
|
||||
Parse *pParse, /* Parsing context */
|
||||
ExprList *pList, /* Form the KeyInfo object from this ExprList */
|
||||
int iStart, /* Begin with this column of pList */
|
||||
int nExtra /* Add this many extra columns to the end */
|
||||
);
|
||||
|
||||
/*
|
||||
** Insert code into "v" that will push the record on the top of the
|
||||
** stack into the sorter.
|
||||
** Generate code that will push the record in registers regData
|
||||
** through regData+nData-1 onto the sorter.
|
||||
*/
|
||||
static void pushOntoSorter(
|
||||
Parse *pParse, /* Parser context */
|
||||
ExprList *pOrderBy, /* The ORDER BY clause */
|
||||
SortCtx *pSort, /* Information about the ORDER BY clause */
|
||||
Select *pSelect, /* The whole SELECT statement */
|
||||
int regData /* Register holding data to be sorted */
|
||||
int regData, /* First register holding data to be sorted */
|
||||
int nData, /* Number of elements in the data array */
|
||||
int nPrefixReg /* No. of reg prior to regData available for use */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int nExpr = pOrderBy->nExpr;
|
||||
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
|
||||
int regRecord = sqlite3GetTempReg(pParse);
|
||||
int op;
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
|
||||
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord);
|
||||
if( pSelect->selFlags & SF_UseSorter ){
|
||||
Vdbe *v = pParse->pVdbe; /* Stmt under construction */
|
||||
int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter)==0);
|
||||
int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */
|
||||
int nBase = nExpr + bSeq + nData; /* Fields in sorter record */
|
||||
int regBase; /* Regs for sorter record */
|
||||
int regRecord = ++pParse->nMem; /* Assembled sorter record */
|
||||
int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
|
||||
int op; /* Opcode to add sorter record to sorter */
|
||||
|
||||
assert( bSeq==0 || bSeq==1 );
|
||||
if( nPrefixReg ){
|
||||
assert( nPrefixReg==nExpr+bSeq );
|
||||
regBase = regData - nExpr - bSeq;
|
||||
}else{
|
||||
regBase = pParse->nMem + 1;
|
||||
pParse->nMem += nBase;
|
||||
}
|
||||
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, SQLITE_ECEL_DUP);
|
||||
if( bSeq ){
|
||||
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
|
||||
}
|
||||
if( nPrefixReg==0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_Move, regData, regBase+nExpr+bSeq, nData);
|
||||
}
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
|
||||
if( nOBSat>0 ){
|
||||
int regPrevKey; /* The first nOBSat columns of the previous row */
|
||||
int addrFirst; /* Address of the OP_IfNot opcode */
|
||||
int addrJmp; /* Address of the OP_Jump opcode */
|
||||
VdbeOp *pOp; /* Opcode that opens the sorter */
|
||||
int nKey; /* Number of sorting key columns, including OP_Sequence */
|
||||
KeyInfo *pKI; /* Original KeyInfo on the sorter table */
|
||||
|
||||
regPrevKey = pParse->nMem+1;
|
||||
pParse->nMem += pSort->nOBSat;
|
||||
nKey = nExpr - pSort->nOBSat + bSeq;
|
||||
if( bSeq ){
|
||||
addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr);
|
||||
}else{
|
||||
addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor);
|
||||
}
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat);
|
||||
pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex);
|
||||
if( pParse->db->mallocFailed ) return;
|
||||
pOp->p2 = nKey + nData;
|
||||
pKI = pOp->p4.pKeyInfo;
|
||||
memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
|
||||
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
|
||||
pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1);
|
||||
addrJmp = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
|
||||
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
|
||||
pSort->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
|
||||
sqlite3VdbeJumpHere(v, addrFirst);
|
||||
sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat);
|
||||
sqlite3VdbeJumpHere(v, addrJmp);
|
||||
}
|
||||
if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
||||
op = OP_SorterInsert;
|
||||
}else{
|
||||
op = OP_IdxInsert;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, op, pOrderBy->iECursor, regRecord);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
|
||||
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
|
||||
if( pSelect->iLimit ){
|
||||
int addr1, addr2;
|
||||
int iLimit;
|
||||
@@ -459,8 +545,8 @@ static void pushOntoSorter(
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
|
||||
addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
|
||||
sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
|
||||
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
|
||||
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
}
|
||||
}
|
||||
@@ -473,7 +559,7 @@ static void codeOffset(
|
||||
int iOffset, /* Register holding the offset counter */
|
||||
int iContinue /* Jump here to skip the current record */
|
||||
){
|
||||
if( iOffset>0 && iContinue!=0 ){
|
||||
if( iOffset>0 ){
|
||||
int addr;
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v);
|
||||
@@ -534,19 +620,6 @@ static int checkForMultiColumnSelectError(
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** An instance of the following object is used to record information about
|
||||
** how to process the DISTINCT keyword, to simplify passing that information
|
||||
** into the selectInnerLoop() routine.
|
||||
*/
|
||||
typedef struct DistinctCtx DistinctCtx;
|
||||
struct DistinctCtx {
|
||||
u8 isTnct; /* True if the DISTINCT keyword is present */
|
||||
u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
|
||||
int tabTnct; /* Ephemeral table used for DISTINCT processing */
|
||||
int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
|
||||
};
|
||||
|
||||
/*
|
||||
** This routine generates the code for the inside of the inner loop
|
||||
** of a SELECT.
|
||||
@@ -561,7 +634,7 @@ static void selectInnerLoop(
|
||||
Select *p, /* The complete select statement being coded */
|
||||
ExprList *pEList, /* List of values being extracted */
|
||||
int srcTab, /* Pull data from this table */
|
||||
ExprList *pOrderBy, /* If not NULL, sort results using this key */
|
||||
SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */
|
||||
DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
|
||||
SelectDest *pDest, /* How to dispose of the results */
|
||||
int iContinue, /* Jump here to continue with next row */
|
||||
@@ -574,11 +647,14 @@ static void selectInnerLoop(
|
||||
int eDest = pDest->eDest; /* How to dispose of results */
|
||||
int iParm = pDest->iSDParm; /* First argument to disposal method */
|
||||
int nResultCol; /* Number of result columns */
|
||||
int nPrefixReg = 0; /* Number of extra registers before regResult */
|
||||
|
||||
assert( v );
|
||||
assert( pEList!=0 );
|
||||
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
|
||||
if( pOrderBy==0 && !hasDistinct ){
|
||||
if( pSort && pSort->pOrderBy==0 ) pSort = 0;
|
||||
if( pSort==0 && !hasDistinct ){
|
||||
assert( iContinue!=0 );
|
||||
codeOffset(v, p->iOffset, iContinue);
|
||||
}
|
||||
|
||||
@@ -587,6 +663,11 @@ static void selectInnerLoop(
|
||||
nResultCol = pEList->nExpr;
|
||||
|
||||
if( pDest->iSdst==0 ){
|
||||
if( pSort ){
|
||||
nPrefixReg = pSort->pOrderBy->nExpr;
|
||||
if( !(pSort->sortFlags & SORTFLAG_UseSorter) ) nPrefixReg++;
|
||||
pParse->nMem += nPrefixReg;
|
||||
}
|
||||
pDest->iSdst = pParse->nMem+1;
|
||||
pParse->nMem += nResultCol;
|
||||
}else if( pDest->iSdst+nResultCol > pParse->nMem ){
|
||||
@@ -668,7 +749,7 @@ static void selectInnerLoop(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( pOrderBy==0 ){
|
||||
if( pSort==0 ){
|
||||
codeOffset(v, p->iOffset, iContinue);
|
||||
}
|
||||
}
|
||||
@@ -699,16 +780,17 @@ static void selectInnerLoop(
|
||||
|
||||
/* Store the result as data using a unique key.
|
||||
*/
|
||||
case SRT_DistTable:
|
||||
case SRT_Fifo:
|
||||
case SRT_DistFifo:
|
||||
case SRT_Table:
|
||||
case SRT_EphemTab: {
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1);
|
||||
testcase( eDest==SRT_Table );
|
||||
testcase( eDest==SRT_EphemTab );
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
if( eDest==SRT_DistTable ){
|
||||
/* If the destination is DistTable, then cursor (iParm+1) is open
|
||||
if( eDest==SRT_DistFifo ){
|
||||
/* If the destination is DistFifo, then cursor (iParm+1) is open
|
||||
** on an ephemeral index. If the current row is already present
|
||||
** in the index, do not write it to the output. If not, add the
|
||||
** current row to the index and proceed with writing it to the
|
||||
@@ -716,11 +798,11 @@ static void selectInnerLoop(
|
||||
int addr = sqlite3VdbeCurrentAddr(v) + 4;
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
|
||||
assert( pOrderBy==0 );
|
||||
assert( pSort==0 );
|
||||
}
|
||||
#endif
|
||||
if( pOrderBy ){
|
||||
pushOntoSorter(pParse, pOrderBy, p, r1);
|
||||
if( pSort ){
|
||||
pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, 1, nPrefixReg);
|
||||
}else{
|
||||
int r2 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
|
||||
@@ -728,7 +810,7 @@ static void selectInnerLoop(
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
sqlite3ReleaseTempReg(pParse, r2);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -741,12 +823,12 @@ static void selectInnerLoop(
|
||||
assert( nResultCol==1 );
|
||||
pDest->affSdst =
|
||||
sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
|
||||
if( pOrderBy ){
|
||||
if( pSort ){
|
||||
/* At first glance you would think we could optimize out the
|
||||
** ORDER BY in this case since the order of entries in the set
|
||||
** does not matter. But there might be a LIMIT clause, in which
|
||||
** case the order does matter */
|
||||
pushOntoSorter(pParse, pOrderBy, p, regResult);
|
||||
pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
|
||||
}else{
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
|
||||
@@ -771,8 +853,8 @@ static void selectInnerLoop(
|
||||
*/
|
||||
case SRT_Mem: {
|
||||
assert( nResultCol==1 );
|
||||
if( pOrderBy ){
|
||||
pushOntoSorter(pParse, pOrderBy, p, regResult);
|
||||
if( pSort ){
|
||||
pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
|
||||
}else{
|
||||
sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
|
||||
/* The LIMIT clause will jump out of the loop for us */
|
||||
@@ -785,11 +867,8 @@ static void selectInnerLoop(
|
||||
case SRT_Output: { /* Return the results */
|
||||
testcase( eDest==SRT_Coroutine );
|
||||
testcase( eDest==SRT_Output );
|
||||
if( pOrderBy ){
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
|
||||
pushOntoSorter(pParse, pOrderBy, p, r1);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
if( pSort ){
|
||||
pushOntoSorter(pParse, pSort, p, regResult, nResultCol, nPrefixReg);
|
||||
}else if( eDest==SRT_Coroutine ){
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
|
||||
}else{
|
||||
@@ -865,7 +944,7 @@ static void selectInnerLoop(
|
||||
** there is a sorter, in which case the sorter has already limited
|
||||
** the output for us.
|
||||
*/
|
||||
if( pOrderBy==0 && p->iLimit ){
|
||||
if( pSort==0 && p->iLimit ){
|
||||
sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
|
||||
}
|
||||
}
|
||||
@@ -936,7 +1015,12 @@ int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; }
|
||||
** function is responsible for seeing that this structure is eventually
|
||||
** freed.
|
||||
*/
|
||||
static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){
|
||||
static KeyInfo *keyInfoFromExprList(
|
||||
Parse *pParse, /* Parsing context */
|
||||
ExprList *pList, /* Form the KeyInfo object from this ExprList */
|
||||
int iStart, /* Begin with this column of pList */
|
||||
int nExtra /* Add this many extra columns to the end */
|
||||
){
|
||||
int nExpr;
|
||||
KeyInfo *pInfo;
|
||||
struct ExprList_item *pItem;
|
||||
@@ -944,15 +1028,15 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){
|
||||
int i;
|
||||
|
||||
nExpr = pList->nExpr;
|
||||
pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra, 1);
|
||||
pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1);
|
||||
if( pInfo ){
|
||||
assert( sqlite3KeyInfoIsWriteable(pInfo) );
|
||||
for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
|
||||
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
|
||||
CollSeq *pColl;
|
||||
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
pInfo->aColl[i] = pColl;
|
||||
pInfo->aSortOrder[i] = pItem->sortOrder;
|
||||
pInfo->aColl[i-iStart] = pColl;
|
||||
pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
|
||||
}
|
||||
}
|
||||
return pInfo;
|
||||
@@ -1054,46 +1138,72 @@ static void explainComposite(
|
||||
static void generateSortTail(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Select *p, /* The SELECT statement */
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
SortCtx *pSort, /* Information on the ORDER BY clause */
|
||||
int nColumn, /* Number of columns of data */
|
||||
SelectDest *pDest /* Write the sorted results here */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe; /* The prepared statement */
|
||||
int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
|
||||
int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
|
||||
int addr;
|
||||
int addrOnce = 0;
|
||||
int iTab;
|
||||
int pseudoTab = 0;
|
||||
ExprList *pOrderBy = p->pOrderBy;
|
||||
|
||||
ExprList *pOrderBy = pSort->pOrderBy;
|
||||
int eDest = pDest->eDest;
|
||||
int iParm = pDest->iSDParm;
|
||||
|
||||
int regRow;
|
||||
int regRowid;
|
||||
int nKey;
|
||||
int iSortTab; /* Sorter cursor to read from */
|
||||
int nSortData; /* Trailing values to read from sorter */
|
||||
u8 p5; /* p5 parameter for 1st OP_Column */
|
||||
int i;
|
||||
int bSeq; /* True if sorter record includes seq. no. */
|
||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
struct ExprList_item *aOutEx = p->pEList->a;
|
||||
#endif
|
||||
|
||||
iTab = pOrderBy->iECursor;
|
||||
regRow = sqlite3GetTempReg(pParse);
|
||||
if( pSort->labelBkOut ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
|
||||
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
|
||||
}
|
||||
iTab = pSort->iECursor;
|
||||
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
|
||||
pseudoTab = pParse->nTab++;
|
||||
sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn);
|
||||
regRowid = 0;
|
||||
regRow = pDest->iSdst;
|
||||
nSortData = nColumn;
|
||||
}else{
|
||||
regRowid = sqlite3GetTempReg(pParse);
|
||||
regRow = sqlite3GetTempReg(pParse);
|
||||
nSortData = 1;
|
||||
}
|
||||
if( p->selFlags & SF_UseSorter ){
|
||||
nKey = pOrderBy->nExpr - pSort->nOBSat;
|
||||
if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
||||
int regSortOut = ++pParse->nMem;
|
||||
int ptab2 = pParse->nTab++;
|
||||
sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, pOrderBy->nExpr+2);
|
||||
iSortTab = pParse->nTab++;
|
||||
if( pSort->labelBkOut ){
|
||||
addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
|
||||
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
|
||||
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
|
||||
VdbeCoverage(v);
|
||||
codeOffset(v, p->iOffset, addrContinue);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, ptab2, pOrderBy->nExpr+1, regRow);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
|
||||
p5 = OPFLAG_CLEARCACHE;
|
||||
bSeq = 0;
|
||||
}else{
|
||||
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
|
||||
codeOffset(v, p->iOffset, addrContinue);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr+1, regRow);
|
||||
iSortTab = iTab;
|
||||
p5 = 0;
|
||||
bSeq = 1;
|
||||
}
|
||||
for(i=0; i<nSortData; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
|
||||
if( i==0 ) sqlite3VdbeChangeP5(v, p5);
|
||||
VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
|
||||
}
|
||||
switch( eDest ){
|
||||
case SRT_Table:
|
||||
@@ -1122,17 +1232,9 @@ static void generateSortTail(
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
int i;
|
||||
assert( eDest==SRT_Output || eDest==SRT_Coroutine );
|
||||
testcase( eDest==SRT_Output );
|
||||
testcase( eDest==SRT_Coroutine );
|
||||
for(i=0; i<nColumn; i++){
|
||||
assert( regRow!=pDest->iSdst+i );
|
||||
sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iSdst+i);
|
||||
if( i==0 ){
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
|
||||
}
|
||||
}
|
||||
if( eDest==SRT_Output ){
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn);
|
||||
sqlite3ExprCacheAffinityChange(pParse, pDest->iSdst, nColumn);
|
||||
@@ -1142,21 +1244,20 @@ static void generateSortTail(
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regRow);
|
||||
sqlite3ReleaseTempReg(pParse, regRowid);
|
||||
|
||||
if( regRowid ){
|
||||
sqlite3ReleaseTempReg(pParse, regRow);
|
||||
sqlite3ReleaseTempReg(pParse, regRowid);
|
||||
}
|
||||
/* The bottom of the loop
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, addrContinue);
|
||||
if( p->selFlags & SF_UseSorter ){
|
||||
if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
|
||||
}
|
||||
if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn);
|
||||
sqlite3VdbeResolveLabel(v, addrBreak);
|
||||
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
|
||||
sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1616,7 +1717,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
||||
assert( db->lookaside.bEnabled==0 );
|
||||
pTab->nRef = 1;
|
||||
pTab->zName = 0;
|
||||
pTab->nRowEst = 1048576;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
|
||||
selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
|
||||
pTab->iPKey = -1;
|
||||
@@ -1834,7 +1935,7 @@ static void generateWithRecursiveQuery(
|
||||
int regCurrent; /* Register holding Current table */
|
||||
int iQueue; /* The Queue table */
|
||||
int iDistinct = 0; /* To ensure unique results if UNION */
|
||||
int eDest = SRT_Table; /* How to write to Queue */
|
||||
int eDest = SRT_Fifo; /* How to write to Queue */
|
||||
SelectDest destQueue; /* SelectDest targetting the Queue table */
|
||||
int i; /* Loop counter */
|
||||
int rc; /* Result code */
|
||||
@@ -1866,13 +1967,13 @@ static void generateWithRecursiveQuery(
|
||||
|
||||
/* Allocate cursors numbers for Queue and Distinct. The cursor number for
|
||||
** the Distinct table must be exactly one greater than Queue in order
|
||||
** for the SRT_DistTable and SRT_DistQueue destinations to work. */
|
||||
** for the SRT_DistFifo and SRT_DistQueue destinations to work. */
|
||||
iQueue = pParse->nTab++;
|
||||
if( p->op==TK_UNION ){
|
||||
eDest = pOrderBy ? SRT_DistQueue : SRT_DistTable;
|
||||
eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo;
|
||||
iDistinct = pParse->nTab++;
|
||||
}else{
|
||||
eDest = pOrderBy ? SRT_Queue : SRT_Table;
|
||||
eDest = pOrderBy ? SRT_Queue : SRT_Fifo;
|
||||
}
|
||||
sqlite3SelectDestInit(&destQueue, eDest, iQueue);
|
||||
|
||||
@@ -1938,6 +2039,7 @@ static void generateWithRecursiveQuery(
|
||||
sqlite3VdbeResolveLabel(v, addrBreak);
|
||||
|
||||
end_of_recursive_query:
|
||||
sqlite3ExprListDelete(pParse->db, p->pOrderBy);
|
||||
p->pOrderBy = pOrderBy;
|
||||
p->pLimit = pLimit;
|
||||
p->pOffset = pOffset;
|
||||
@@ -3754,7 +3856,7 @@ static int withExpand(
|
||||
pTab->nRef = 1;
|
||||
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
|
||||
pTab->iPKey = -1;
|
||||
pTab->nRowEst = 1048576;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
pTab->tabFlags |= TF_Ephemeral;
|
||||
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
|
||||
if( db->mallocFailed ) return SQLITE_NOMEM;
|
||||
@@ -3930,7 +4032,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
while( pSel->pPrior ){ pSel = pSel->pPrior; }
|
||||
selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
|
||||
pTab->iPKey = -1;
|
||||
pTab->nRowEst = 1048576;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
pTab->tabFlags |= TF_Ephemeral;
|
||||
#endif
|
||||
}else{
|
||||
@@ -4309,7 +4411,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
"argument");
|
||||
pFunc->iDistinct = -1;
|
||||
}else{
|
||||
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0);
|
||||
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
|
||||
(char*)pKeyInfo, P4_KEYINFO);
|
||||
}
|
||||
@@ -4464,12 +4566,11 @@ int sqlite3Select(
|
||||
ExprList *pEList; /* List of columns to extract. */
|
||||
SrcList *pTabList; /* List of tables to select from */
|
||||
Expr *pWhere; /* The WHERE clause. May be NULL */
|
||||
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
|
||||
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
|
||||
Expr *pHaving; /* The HAVING clause. May be NULL */
|
||||
int rc = 1; /* Value to return from this function */
|
||||
int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
|
||||
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
|
||||
SortCtx sSort; /* Info on how to code the ORDER BY clause */
|
||||
AggInfo sAggInfo; /* Information used by aggregate queries */
|
||||
int iEnd; /* Address of the end of the query */
|
||||
sqlite3 *db; /* The database connection */
|
||||
@@ -4486,9 +4587,15 @@ int sqlite3Select(
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
||||
memset(&sAggInfo, 0, sizeof(sAggInfo));
|
||||
|
||||
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
|
||||
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
|
||||
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
|
||||
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
|
||||
if( IgnorableOrderby(pDest) ){
|
||||
assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
|
||||
pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard);
|
||||
pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
|
||||
pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo ||
|
||||
pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo);
|
||||
/* If ORDER BY makes no difference in the output then neither does
|
||||
** DISTINCT so it can be removed too. */
|
||||
sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
@@ -4496,7 +4603,8 @@ int sqlite3Select(
|
||||
p->selFlags &= ~SF_Distinct;
|
||||
}
|
||||
sqlite3SelectPrep(pParse, p, 0);
|
||||
pOrderBy = p->pOrderBy;
|
||||
memset(&sSort, 0, sizeof(sSort));
|
||||
sSort.pOrderBy = p->pOrderBy;
|
||||
pTabList = p->pSrc;
|
||||
pEList = p->pEList;
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
@@ -4574,7 +4682,7 @@ int sqlite3Select(
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
|
||||
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
||||
pItem->viaCoroutine = 1;
|
||||
pItem->regResult = dest.iSdst;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
|
||||
@@ -4605,7 +4713,7 @@ int sqlite3Select(
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
|
||||
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
||||
VdbeComment((v, "end %s", pItem->pTab->zName));
|
||||
@@ -4618,7 +4726,7 @@ int sqlite3Select(
|
||||
pParse->nHeight -= sqlite3SelectExprHeight(p);
|
||||
pTabList = p->pSrc;
|
||||
if( !IgnorableOrderby(pDest) ){
|
||||
pOrderBy = p->pOrderBy;
|
||||
sSort.pOrderBy = p->pOrderBy;
|
||||
}
|
||||
}
|
||||
pEList = p->pEList;
|
||||
@@ -4638,18 +4746,6 @@ int sqlite3Select(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
||||
** identical, then disable the ORDER BY clause since the GROUP BY
|
||||
** will cause elements to come out in the correct order. This is
|
||||
** an optimization - the correct answer should result regardless.
|
||||
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
|
||||
** to disable this optimization for testing purposes.
|
||||
*/
|
||||
if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy, -1)==0
|
||||
&& OptimizationEnabled(db, SQLITE_GroupByOrder) ){
|
||||
pOrderBy = 0;
|
||||
}
|
||||
|
||||
/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
|
||||
** if the select-list is the same as the ORDER BY list, then this query
|
||||
** can be rewritten as a GROUP BY. In other words, this:
|
||||
@@ -4666,12 +4762,12 @@ int sqlite3Select(
|
||||
** BY and DISTINCT, and an index or separate temp-table for the other.
|
||||
*/
|
||||
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
|
||||
&& sqlite3ExprListCompare(pOrderBy, p->pEList, -1)==0
|
||||
&& sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0
|
||||
){
|
||||
p->selFlags &= ~SF_Distinct;
|
||||
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
|
||||
pGroupBy = p->pGroupBy;
|
||||
pOrderBy = 0;
|
||||
sSort.pOrderBy = 0;
|
||||
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
|
||||
** the sDistinct.isTnct is still set. Hence, isTnct represents the
|
||||
** original setting of the SF_Distinct flag, not the current setting */
|
||||
@@ -4685,16 +4781,17 @@ int sqlite3Select(
|
||||
** we figure out that the sorting index is not needed. The addrSortIndex
|
||||
** variable is used to facilitate that change.
|
||||
*/
|
||||
if( pOrderBy ){
|
||||
if( sSort.pOrderBy ){
|
||||
KeyInfo *pKeyInfo;
|
||||
pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 0);
|
||||
pOrderBy->iECursor = pParse->nTab++;
|
||||
p->addrOpenEphm[2] = addrSortIndex =
|
||||
pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0);
|
||||
sSort.iECursor = pParse->nTab++;
|
||||
sSort.addrSortIndex =
|
||||
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
||||
pOrderBy->iECursor, pOrderBy->nExpr+2, 0,
|
||||
(char*)pKeyInfo, P4_KEYINFO);
|
||||
sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0,
|
||||
(char*)pKeyInfo, P4_KEYINFO
|
||||
);
|
||||
}else{
|
||||
addrSortIndex = -1;
|
||||
sSort.addrSortIndex = -1;
|
||||
}
|
||||
|
||||
/* If the output is destined for a temporary table, open that table.
|
||||
@@ -4708,9 +4805,9 @@ int sqlite3Select(
|
||||
iEnd = sqlite3VdbeMakeLabel(v);
|
||||
p->nSelectRow = LARGEST_INT64;
|
||||
computeLimitRegisters(pParse, p, iEnd);
|
||||
if( p->iLimit==0 && addrSortIndex>=0 ){
|
||||
sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen;
|
||||
p->selFlags |= SF_UseSorter;
|
||||
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
|
||||
sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen;
|
||||
sSort.sortFlags |= SORTFLAG_UseSorter;
|
||||
}
|
||||
|
||||
/* Open a virtual index to use for the distinct set.
|
||||
@@ -4719,7 +4816,7 @@ int sqlite3Select(
|
||||
sDistinct.tabTnct = pParse->nTab++;
|
||||
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
||||
sDistinct.tabTnct, 0, 0,
|
||||
(char*)keyInfoFromExprList(pParse, p->pEList, 0),
|
||||
(char*)keyInfoFromExprList(pParse, p->pEList,0,0),
|
||||
P4_KEYINFO);
|
||||
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
|
||||
@@ -4732,8 +4829,8 @@ int sqlite3Select(
|
||||
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
|
||||
|
||||
/* Begin the database scan. */
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, p->pEList,
|
||||
wctrlFlags, 0);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
|
||||
p->pEList, wctrlFlags, 0);
|
||||
if( pWInfo==0 ) goto select_end;
|
||||
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
|
||||
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
|
||||
@@ -4741,19 +4838,23 @@ int sqlite3Select(
|
||||
if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
|
||||
sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
|
||||
}
|
||||
if( pOrderBy && sqlite3WhereIsOrdered(pWInfo) ) pOrderBy = 0;
|
||||
if( sSort.pOrderBy ){
|
||||
sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
|
||||
if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
|
||||
sSort.pOrderBy = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If sorting index that was created by a prior OP_OpenEphemeral
|
||||
** instruction ended up not being needed, then change the OP_OpenEphemeral
|
||||
** into an OP_Noop.
|
||||
*/
|
||||
if( addrSortIndex>=0 && pOrderBy==0 ){
|
||||
sqlite3VdbeChangeToNoop(v, addrSortIndex);
|
||||
p->addrOpenEphm[2] = -1;
|
||||
if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){
|
||||
sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
|
||||
}
|
||||
|
||||
/* Use the standard inner loop. */
|
||||
selectInnerLoop(pParse, p, pEList, -1, pOrderBy, &sDistinct, pDest,
|
||||
selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
|
||||
sqlite3WhereContinueLabel(pWInfo),
|
||||
sqlite3WhereBreakLabel(pWInfo));
|
||||
|
||||
@@ -4774,6 +4875,7 @@ int sqlite3Select(
|
||||
int addrEnd; /* End of processing for this SELECT */
|
||||
int sortPTab = 0; /* Pseudotable used to decode sorting results */
|
||||
int sortOut = 0; /* Output register from the sorter */
|
||||
int orderByGrp = 0; /* True if the GROUP BY and ORDER BY are the same */
|
||||
|
||||
/* Remove any and all aliases between the result set and the
|
||||
** GROUP BY clause.
|
||||
@@ -4793,6 +4895,18 @@ int sqlite3Select(
|
||||
p->nSelectRow = 1;
|
||||
}
|
||||
|
||||
|
||||
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
||||
** identical, then it may be possible to disable the ORDER BY clause
|
||||
** on the grounds that the GROUP BY will cause elements to come out
|
||||
** in the correct order. It also may not - the GROUP BY may use a
|
||||
** database index that causes rows to be grouped together as required
|
||||
** but not actually sorted. Either way, record the fact that the
|
||||
** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
|
||||
** variable. */
|
||||
if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){
|
||||
orderByGrp = 1;
|
||||
}
|
||||
|
||||
/* Create a label to jump to when we want to abort the query */
|
||||
addrEnd = sqlite3VdbeMakeLabel(v);
|
||||
@@ -4806,10 +4920,10 @@ int sqlite3Select(
|
||||
sNC.pSrcList = pTabList;
|
||||
sNC.pAggInfo = &sAggInfo;
|
||||
sAggInfo.mnReg = pParse->nMem+1;
|
||||
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
|
||||
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
|
||||
sAggInfo.pGroupBy = pGroupBy;
|
||||
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
||||
sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
|
||||
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
||||
if( pHaving ){
|
||||
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
||||
}
|
||||
@@ -4843,7 +4957,7 @@ int sqlite3Select(
|
||||
** will be converted into a Noop.
|
||||
*/
|
||||
sAggInfo.sortingIdx = pParse->nTab++;
|
||||
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0);
|
||||
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0);
|
||||
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
||||
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
|
||||
0, (char*)pKeyInfo, P4_KEYINFO);
|
||||
@@ -4872,10 +4986,11 @@ int sqlite3Select(
|
||||
** in the right order to begin with.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
|
||||
WHERE_GROUPBY, 0);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
|
||||
WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0
|
||||
);
|
||||
if( pWInfo==0 ) goto select_end;
|
||||
if( sqlite3WhereIsOrdered(pWInfo) ){
|
||||
if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
|
||||
/* The optimizer is able to deliver rows in group by order so
|
||||
** we do not have to sort. The OP_OpenEphemeral table will be
|
||||
** cancelled later because we still need to use the pKeyInfo
|
||||
@@ -4898,8 +5013,8 @@ int sqlite3Select(
|
||||
|
||||
groupBySort = 1;
|
||||
nGroupBy = pGroupBy->nExpr;
|
||||
nCol = nGroupBy + 1;
|
||||
j = nGroupBy+1;
|
||||
nCol = nGroupBy;
|
||||
j = nGroupBy;
|
||||
for(i=0; i<sAggInfo.nColumn; i++){
|
||||
if( sAggInfo.aCol[i].iSorterColumn>=j ){
|
||||
nCol++;
|
||||
@@ -4909,8 +5024,7 @@ int sqlite3Select(
|
||||
regBase = sqlite3GetTempRange(pParse, nCol);
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Sequence, sAggInfo.sortingIdx,regBase+nGroupBy);
|
||||
j = nGroupBy+1;
|
||||
j = nGroupBy;
|
||||
for(i=0; i<sAggInfo.nColumn; i++){
|
||||
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
|
||||
if( pCol->iSorterColumn>=j ){
|
||||
@@ -4938,6 +5052,21 @@ int sqlite3Select(
|
||||
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
|
||||
sAggInfo.useSortingIdx = 1;
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
|
||||
}
|
||||
|
||||
/* If the index or temporary table used by the GROUP BY sort
|
||||
** will naturally deliver rows in the order required by the ORDER BY
|
||||
** clause, cancel the ephemeral table open coded earlier.
|
||||
**
|
||||
** This is an optimization - the correct answer should result regardless.
|
||||
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to
|
||||
** disable this optimization for testing purposes. */
|
||||
if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder)
|
||||
&& (groupBySort || sqlite3WhereIsSorted(pWInfo))
|
||||
){
|
||||
sSort.pOrderBy = 0;
|
||||
sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
|
||||
}
|
||||
|
||||
/* Evaluate the current GROUP BY terms and store in b0, b1, b2...
|
||||
@@ -5026,7 +5155,7 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
||||
finalizeAggFunctions(pParse, &sAggInfo);
|
||||
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
|
||||
selectInnerLoop(pParse, p, p->pEList, -1, pOrderBy,
|
||||
selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
|
||||
&sDistinct, pDest,
|
||||
addrOutputRow+1, addrSetAbort);
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
||||
@@ -5158,7 +5287,7 @@ int sqlite3Select(
|
||||
}
|
||||
updateAccumulator(pParse, &sAggInfo);
|
||||
assert( pMinMax==0 || pMinMax->nExpr==1 );
|
||||
if( sqlite3WhereIsOrdered(pWInfo) ){
|
||||
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo));
|
||||
VdbeComment((v, "%s() by index",
|
||||
(flag==WHERE_ORDERBY_MIN?"min":"max")));
|
||||
@@ -5167,7 +5296,7 @@ int sqlite3Select(
|
||||
finalizeAggFunctions(pParse, &sAggInfo);
|
||||
}
|
||||
|
||||
pOrderBy = 0;
|
||||
sSort.pOrderBy = 0;
|
||||
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
|
||||
selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
|
||||
pDest, addrEnd, addrEnd);
|
||||
@@ -5184,9 +5313,9 @@ int sqlite3Select(
|
||||
/* If there is an ORDER BY clause, then we need to sort the results
|
||||
** and send them to the callback one by one.
|
||||
*/
|
||||
if( pOrderBy ){
|
||||
explainTempTable(pParse, "ORDER BY");
|
||||
generateSortTail(pParse, p, v, pEList->nExpr, pDest);
|
||||
if( sSort.pOrderBy ){
|
||||
explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
|
||||
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
|
||||
}
|
||||
|
||||
/* Jump here to skip this query
|
||||
|
||||
+16
-7
@@ -1184,6 +1184,7 @@ static int str_in_array(const char *zStr, const char **azArray){
|
||||
** * For each "Goto", if the jump destination is earlier in the program
|
||||
** and ends on one of:
|
||||
** Yield SeekGt SeekLt RowSetRead Rewind
|
||||
** or if the P1 parameter is one instead of zero,
|
||||
** then indent all opcodes between the earlier instruction
|
||||
** and "Goto" by 2 spaces.
|
||||
*/
|
||||
@@ -1194,7 +1195,8 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
|
||||
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
|
||||
int iOp; /* Index of operation in p->aiIndent[] */
|
||||
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
|
||||
"NextIfOpen", "PrevIfOpen", 0 };
|
||||
const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", "Rewind", 0 };
|
||||
const char *azGoto[] = { "Goto", 0 };
|
||||
|
||||
@@ -1231,7 +1233,9 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
|
||||
if( str_in_array(zOp, azNext) ){
|
||||
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
if( str_in_array(zOp, azGoto) && p2op<p->nIndent && abYield[p2op] ){
|
||||
if( str_in_array(zOp, azGoto) && p2op<p->nIndent
|
||||
&& (abYield[p2op] || sqlite3_column_int(pSql, 2))
|
||||
){
|
||||
for(i=p2op+1; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
}
|
||||
@@ -2126,10 +2130,12 @@ static void tryToClone(struct callback_data *p, const char *zNewDb){
|
||||
fprintf(stderr, "Cannot create output database: %s\n",
|
||||
sqlite3_errmsg(newDb));
|
||||
}else{
|
||||
sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
|
||||
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
|
||||
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
|
||||
tryToCloneSchema(p, newDb, "type!='table'", 0);
|
||||
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
|
||||
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
|
||||
}
|
||||
sqlite3_close(newDb);
|
||||
}
|
||||
@@ -3021,6 +3027,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
|
||||
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
|
||||
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
|
||||
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
|
||||
};
|
||||
int testctrl = -1;
|
||||
int rc = 0;
|
||||
@@ -3061,9 +3068,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
break;
|
||||
|
||||
/* sqlite3_test_control(int) */
|
||||
case SQLITE_TESTCTRL_PRNG_SAVE:
|
||||
case SQLITE_TESTCTRL_PRNG_RESTORE:
|
||||
case SQLITE_TESTCTRL_PRNG_SAVE:
|
||||
case SQLITE_TESTCTRL_PRNG_RESTORE:
|
||||
case SQLITE_TESTCTRL_PRNG_RESET:
|
||||
case SQLITE_TESTCTRL_BYTEORDER:
|
||||
if( nArg==2 ){
|
||||
rc = sqlite3_test_control(testctrl);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
|
||||
@@ -3528,7 +3536,8 @@ static void main_init(struct callback_data *data) {
|
||||
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
|
||||
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
|
||||
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
|
||||
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
|
||||
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
|
||||
sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3817,8 +3826,8 @@ int main(int argc, char **argv){
|
||||
);
|
||||
if( warnInmemoryDb ){
|
||||
printf("Connected to a ");
|
||||
printBold("transient in-memory database.");
|
||||
printf("\nUse \".open FILENAME\" to reopen on a "
|
||||
printBold("transient in-memory database");
|
||||
printf(".\nUse \".open FILENAME\" to reopen on a "
|
||||
"persistent database.\n");
|
||||
}
|
||||
zHome = find_home_dir();
|
||||
|
||||
+20
-3
@@ -1715,6 +1715,16 @@ struct sqlite3_mem_methods {
|
||||
** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
|
||||
** that specifies the maximum size of the created heap.
|
||||
** </dl>
|
||||
**
|
||||
** [[SQLITE_CONFIG_WORKER_THREADS]]
|
||||
** <dt>SQLITE_CONFIG_WORKER_THREADS
|
||||
** <dd>^SQLITE_CONFIG_WORKER_THREADS takes a single argument of type int.
|
||||
** It is used to set the number of background worker threads that may be
|
||||
** launched when sorting large amounts of data. A value of 0 means launch
|
||||
** no background threads at all. The maximum number of background threads
|
||||
** allowed is configured at build-time by the SQLITE_MAX_WORKER_THREADS
|
||||
** pre-processor option.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
|
||||
#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
|
||||
@@ -1739,6 +1749,7 @@ struct sqlite3_mem_methods {
|
||||
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
|
||||
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
|
||||
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
|
||||
#define SQLITE_CONFIG_WORKER_THREADS 24 /* int nWorker */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Configuration Options
|
||||
@@ -5817,10 +5828,12 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_OPEN
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU2
|
||||
** <li> SQLITE_MUTEX_STATIC_PMEM
|
||||
** <li> SQLITE_MUTEX_STATIC_APP1
|
||||
** <li> SQLITE_MUTEX_STATIC_APP2
|
||||
** </ul>)^
|
||||
**
|
||||
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
|
||||
@@ -6024,6 +6037,8 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
|
||||
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
|
||||
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
|
||||
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
|
||||
#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
|
||||
#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Retrieve the mutex for a database connection
|
||||
@@ -6118,7 +6133,9 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
|
||||
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
|
||||
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
|
||||
#define SQLITE_TESTCTRL_LAST 21
|
||||
#define SQLITE_TESTCTRL_BYTEORDER 22
|
||||
#define SQLITE_TESTCTRL_SORTER_MMAP 23
|
||||
#define SQLITE_TESTCTRL_LAST 23
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
|
||||
+129
-37
@@ -47,8 +47,41 @@
|
||||
# define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For MinGW, check to see if we can include the header file containing its
|
||||
** version information, among other things. Normally, this internal MinGW
|
||||
** header file would [only] be included automatically by other MinGW header
|
||||
** files; however, the contained version information is now required by this
|
||||
** header file to work around binary compatibility issues (see below) and
|
||||
** this is the only known way to reliably obtain it. This entire #if block
|
||||
** would be completely unnecessary if there was any other way of detecting
|
||||
** MinGW via their preprocessor (e.g. if they customized their GCC to define
|
||||
** some MinGW-specific macros). When compiling for MinGW, either the
|
||||
** _HAVE_MINGW_H or _HAVE__MINGW_H (note the extra underscore) macro must be
|
||||
** defined; otherwise, detection of conditions specific to MinGW will be
|
||||
** disabled.
|
||||
*/
|
||||
#if defined(_HAVE_MINGW_H)
|
||||
# include "mingw.h"
|
||||
#elif defined(_HAVE__MINGW_H)
|
||||
# include "_mingw.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For MinGW version 4.x (and higher), check to see if the _USE_32BIT_TIME_T
|
||||
** define is required to maintain binary compatibility with the MSVC runtime
|
||||
** library in use (e.g. for Windows XP).
|
||||
*/
|
||||
#if !defined(_USE_32BIT_TIME_T) && !defined(_USE_64BIT_TIME_T) && \
|
||||
defined(_WIN32) && !defined(_WIN64) && \
|
||||
defined(__MINGW_MAJOR_VERSION) && __MINGW_MAJOR_VERSION >= 4 && \
|
||||
defined(__MSVCRT__)
|
||||
# define _USE_32BIT_TIME_T
|
||||
#endif
|
||||
|
||||
/* The public SQLite interface. The _FILE_OFFSET_BITS macro must appear
|
||||
** first in QNX.
|
||||
** first in QNX. Also, the _USE_32BIT_TIME_T macro must appear first for
|
||||
** MinGW.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
|
||||
@@ -389,6 +422,26 @@
|
||||
# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if
|
||||
** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
|
||||
** to zero.
|
||||
*/
|
||||
#if SQLITE_TEMP_STORE==3
|
||||
# undef SQLITE_MAX_WORKER_THREADS
|
||||
#endif
|
||||
#ifndef SQLITE_MAX_WORKER_THREADS
|
||||
# define SQLITE_MAX_WORKER_THREADS 0
|
||||
#endif
|
||||
#ifndef SQLITE_DEFAULT_WORKER_THREADS
|
||||
# define SQLITE_DEFAULT_WORKER_THREADS 0
|
||||
#endif
|
||||
#if SQLITE_DEFAULT_WORKER_THREADS>SQLITE_MAX_WORKER_THREADS
|
||||
# undef SQLITE_MAX_WORKER_THREADS
|
||||
# define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** GCC does not define the offsetof() macro so we'll have to do it
|
||||
** ourselves.
|
||||
@@ -492,10 +545,10 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
|
||||
** gives a possible range of values of approximately 1.0e986 to 1e-986.
|
||||
** But the allowed values are "grainy". Not every value is representable.
|
||||
** For example, quantities 16 and 17 are both represented by a LogEst
|
||||
** of 40. However, since LogEst quantatites are suppose to be estimates,
|
||||
** of 40. However, since LogEst quantaties are suppose to be estimates,
|
||||
** not exact values, this imprecision is not a problem.
|
||||
**
|
||||
** "LogEst" is short for "Logarithimic Estimate".
|
||||
** "LogEst" is short for "Logarithmic Estimate".
|
||||
**
|
||||
** Examples:
|
||||
** 1 -> 0 20 -> 43 10000 -> 132
|
||||
@@ -513,22 +566,39 @@ typedef INT16_TYPE LogEst;
|
||||
|
||||
/*
|
||||
** Macros to determine whether the machine is big or little endian,
|
||||
** evaluated at runtime.
|
||||
** and whether or not that determination is run-time or compile-time.
|
||||
**
|
||||
** For best performance, an attempt is made to guess at the byte-order
|
||||
** using C-preprocessor macros. If that is unsuccessful, or if
|
||||
** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
|
||||
** at run-time.
|
||||
*/
|
||||
#ifdef SQLITE_AMALGAMATION
|
||||
const int sqlite3one = 1;
|
||||
#else
|
||||
extern const int sqlite3one;
|
||||
#endif
|
||||
#if defined(i386) || defined(__i386__) || defined(_M_IX86)\
|
||||
|| defined(__x86_64) || defined(__x86_64__)
|
||||
#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \
|
||||
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
|
||||
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
|
||||
defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER)
|
||||
# define SQLITE_BYTEORDER 1234
|
||||
# define SQLITE_BIGENDIAN 0
|
||||
# define SQLITE_LITTLEENDIAN 1
|
||||
# define SQLITE_UTF16NATIVE SQLITE_UTF16LE
|
||||
#else
|
||||
#endif
|
||||
#if (defined(sparc) || defined(__ppc__)) \
|
||||
&& !defined(SQLITE_RUNTIME_BYTEORDER)
|
||||
# define SQLITE_BYTEORDER 4321
|
||||
# define SQLITE_BIGENDIAN 1
|
||||
# define SQLITE_LITTLEENDIAN 0
|
||||
# define SQLITE_UTF16NATIVE SQLITE_UTF16BE
|
||||
#endif
|
||||
#if !defined(SQLITE_BYTEORDER)
|
||||
# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
|
||||
# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
|
||||
# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
|
||||
# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
|
||||
# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -755,6 +825,7 @@ typedef struct PrintfArguments PrintfArguments;
|
||||
typedef struct RowSet RowSet;
|
||||
typedef struct Savepoint Savepoint;
|
||||
typedef struct Select Select;
|
||||
typedef struct SQLiteThread SQLiteThread;
|
||||
typedef struct SelectDest SelectDest;
|
||||
typedef struct SrcList SrcList;
|
||||
typedef struct StrAccum StrAccum;
|
||||
@@ -934,6 +1005,7 @@ struct sqlite3 {
|
||||
int nChange; /* Value returned by sqlite3_changes() */
|
||||
int nTotalChange; /* Value returned by sqlite3_total_changes() */
|
||||
int aLimit[SQLITE_N_LIMIT]; /* Limits */
|
||||
int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
|
||||
struct sqlite3InitInfo { /* Information used during initialization */
|
||||
int newTnum; /* Rootpage of table being initialized */
|
||||
u8 iDb; /* Which db file is being initialized */
|
||||
@@ -1421,7 +1493,7 @@ struct Table {
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
ExprList *pCheck; /* All CHECK constraints */
|
||||
#endif
|
||||
tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
|
||||
LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */
|
||||
int tnum; /* Root BTree node for this table (see note above) */
|
||||
i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
|
||||
i16 nCol; /* Number of columns in this table */
|
||||
@@ -1594,6 +1666,7 @@ struct UnpackedRecord {
|
||||
KeyInfo *pKeyInfo; /* Collation and sort-order information */
|
||||
u16 nField; /* Number of entries in apMem[] */
|
||||
i8 default_rc; /* Comparison result if keys are equal */
|
||||
u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
|
||||
Mem *aMem; /* Values */
|
||||
int r1; /* Value to return if (lhs > rhs) */
|
||||
int r2; /* Value to return if (rhs < lhs) */
|
||||
@@ -1629,7 +1702,7 @@ struct UnpackedRecord {
|
||||
struct Index {
|
||||
char *zName; /* Name of this index */
|
||||
i16 *aiColumn; /* Which columns are used by this index. 1st is 0 */
|
||||
tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
|
||||
LogEst *aiRowLogEst; /* From ANALYZE: Est. rows selected by each column */
|
||||
Table *pTable; /* The SQL table being indexed */
|
||||
char *zColAff; /* String defining the affinity of each column */
|
||||
Index *pNext; /* The next index associated with the same table */
|
||||
@@ -1860,8 +1933,8 @@ struct Expr {
|
||||
#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
|
||||
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
|
||||
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
|
||||
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */
|
||||
/* unused 0x000200 */
|
||||
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
|
||||
#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
|
||||
#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
|
||||
#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
|
||||
#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */
|
||||
@@ -1925,7 +1998,6 @@ struct Expr {
|
||||
*/
|
||||
struct ExprList {
|
||||
int nExpr; /* Number of expressions on the list */
|
||||
int iECursor; /* VDBE Cursor associated with this ExprList */
|
||||
struct ExprList_item { /* For each expression in the list */
|
||||
Expr *pExpr; /* The list of expressions */
|
||||
char *zName; /* Token associated with this expression */
|
||||
@@ -2018,8 +2090,8 @@ typedef u64 Bitmask;
|
||||
** contains more than 63 columns and the 64-th or later column is used.
|
||||
*/
|
||||
struct SrcList {
|
||||
u8 nSrc; /* Number of tables or subqueries in the FROM clause */
|
||||
u8 nAlloc; /* Number of entries allocated in a[] below */
|
||||
int nSrc; /* Number of tables or subqueries in the FROM clause */
|
||||
u32 nAlloc; /* Number of entries allocated in a[] below */
|
||||
struct SrcList_item {
|
||||
Schema *pSchema; /* Schema to which this item is fixed */
|
||||
char *zDatabase; /* Name of database holding this table */
|
||||
@@ -2075,6 +2147,7 @@ struct SrcList {
|
||||
#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */
|
||||
#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */
|
||||
#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */
|
||||
#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */
|
||||
|
||||
/* Allowed return values from sqlite3WhereIsDistinct()
|
||||
*/
|
||||
@@ -2149,7 +2222,7 @@ struct Select {
|
||||
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
||||
u16 selFlags; /* Various SF_* values */
|
||||
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
||||
int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
|
||||
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
|
||||
u64 nSelectRow; /* Estimated number of result rows */
|
||||
SrcList *pSrc; /* The FROM clause */
|
||||
Expr *pWhere; /* The WHERE clause */
|
||||
@@ -2173,9 +2246,9 @@ struct Select {
|
||||
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
|
||||
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
|
||||
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
|
||||
#define SF_UseSorter 0x0040 /* Sort using a sorter */
|
||||
/* 0x0040 NOT USED */
|
||||
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
|
||||
#define SF_Materialize 0x0100 /* NOT USED */
|
||||
/* 0x0100 NOT USED */
|
||||
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
||||
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
|
||||
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
|
||||
@@ -2228,13 +2301,15 @@ struct Select {
|
||||
** starting with pDest->iSdst.
|
||||
**
|
||||
** SRT_Table Store results in temporary table pDest->iSDParm.
|
||||
** This is like SRT_EphemTab except that the table
|
||||
** is assumed to already be open.
|
||||
** SRT_Fifo This is like SRT_EphemTab except that the table
|
||||
** is assumed to already be open. SRT_Fifo has
|
||||
** the additional property of being able to ignore
|
||||
** the ORDER BY clause.
|
||||
**
|
||||
** SRT_DistTable Store results in a temporary table pDest->iSDParm.
|
||||
** SRT_DistFifo Store results in a temporary table pDest->iSDParm.
|
||||
** But also use temporary table pDest->iSDParm+1 as
|
||||
** a record of all prior results and ignore any duplicate
|
||||
** rows. Name means: "Distinct Table".
|
||||
** rows. Name means: "Distinct Fifo".
|
||||
**
|
||||
** SRT_Queue Store results in priority queue pDest->iSDParm (really
|
||||
** an index). Append a sequence number so that all entries
|
||||
@@ -2248,19 +2323,20 @@ struct Select {
|
||||
#define SRT_Except 2 /* Remove result from a UNION index */
|
||||
#define SRT_Exists 3 /* Store 1 if the result is not empty */
|
||||
#define SRT_Discard 4 /* Do not save the results anywhere */
|
||||
#define SRT_Fifo 5 /* Store result as data with an automatic rowid */
|
||||
#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */
|
||||
#define SRT_Queue 7 /* Store result in an queue */
|
||||
#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */
|
||||
|
||||
/* The ORDER BY clause is ignored for all of the above */
|
||||
#define IgnorableOrderby(X) ((X->eDest)<=SRT_Discard)
|
||||
#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue)
|
||||
|
||||
#define SRT_Output 5 /* Output each row of result */
|
||||
#define SRT_Mem 6 /* Store result in a memory cell */
|
||||
#define SRT_Set 7 /* Store results as keys in an index */
|
||||
#define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */
|
||||
#define SRT_Coroutine 9 /* Generate a single row of result */
|
||||
#define SRT_Table 10 /* Store result as data with an automatic rowid */
|
||||
#define SRT_DistTable 11 /* Like SRT_Table, but unique results only */
|
||||
#define SRT_Queue 12 /* Store result in an queue */
|
||||
#define SRT_DistQueue 13 /* Like SRT_Queue, but unique results only */
|
||||
#define SRT_Output 9 /* Output each row of result */
|
||||
#define SRT_Mem 10 /* Store result in a memory cell */
|
||||
#define SRT_Set 11 /* Store results as keys in an index */
|
||||
#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
|
||||
#define SRT_Coroutine 13 /* Generate a single row of result */
|
||||
#define SRT_Table 14 /* Store result as data with an automatic rowid */
|
||||
|
||||
/*
|
||||
** An instance of this object describes where to put of the results of
|
||||
@@ -2358,8 +2434,6 @@ struct Parse {
|
||||
u8 checkSchema; /* Causes schema cookie check after an error */
|
||||
u8 nested; /* Number of nested calls to the parser/code generator */
|
||||
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
|
||||
u8 nColCache; /* Number of entries in aColCache[] */
|
||||
u8 iColCache; /* Next entry in aColCache[] to replace */
|
||||
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
|
||||
u8 mayAbort; /* True if statement may throw an ABORT exception */
|
||||
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
|
||||
@@ -2650,6 +2724,7 @@ struct Sqlite3Config {
|
||||
int nPage; /* Number of pages in pPage[] */
|
||||
int mxParserStack; /* maximum depth of the parser stack */
|
||||
int sharedCacheEnabled; /* true if shared-cache mode enabled */
|
||||
int nWorker; /* Number of worker threads to use */
|
||||
/* The above might be initialized to non-zero. The following need to always
|
||||
** initially be zero, however. */
|
||||
int isInit; /* True after initialization has finished */
|
||||
@@ -2985,7 +3060,7 @@ int sqlite3BitvecBuiltinTest(int,int*);
|
||||
RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
|
||||
void sqlite3RowSetClear(RowSet*);
|
||||
void sqlite3RowSetInsert(RowSet*, i64);
|
||||
int sqlite3RowSetTest(RowSet*, u8 iBatch, i64);
|
||||
int sqlite3RowSetTest(RowSet*, int iBatch, i64);
|
||||
int sqlite3RowSetNext(RowSet*, i64*);
|
||||
|
||||
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
|
||||
@@ -3041,6 +3116,7 @@ void sqlite3WhereEnd(WhereInfo*);
|
||||
u64 sqlite3WhereOutputRowCount(WhereInfo*);
|
||||
int sqlite3WhereIsDistinct(WhereInfo*);
|
||||
int sqlite3WhereIsOrdered(WhereInfo*);
|
||||
int sqlite3WhereIsSorted(WhereInfo*);
|
||||
int sqlite3WhereContinueLabel(WhereInfo*);
|
||||
int sqlite3WhereBreakLabel(WhereInfo*);
|
||||
int sqlite3WhereOkOnePass(WhereInfo*, int*);
|
||||
@@ -3049,7 +3125,7 @@ void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
|
||||
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
||||
void sqlite3ExprCacheStore(Parse*, int, int, int);
|
||||
void sqlite3ExprCachePush(Parse*);
|
||||
void sqlite3ExprCachePop(Parse*, int);
|
||||
void sqlite3ExprCachePop(Parse*);
|
||||
void sqlite3ExprCacheRemove(Parse*, int, int);
|
||||
void sqlite3ExprCacheClear(Parse*);
|
||||
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
||||
@@ -3101,6 +3177,7 @@ int sqlite3IsRowid(const char*);
|
||||
void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
|
||||
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
|
||||
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
|
||||
void sqlite3ResolvePartIdxLabel(Parse*,int);
|
||||
void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
|
||||
u8,u8,int,int*);
|
||||
void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
|
||||
@@ -3258,7 +3335,7 @@ int sqlite3ReadSchema(Parse *pParse);
|
||||
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
|
||||
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
|
||||
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*);
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*);
|
||||
Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
|
||||
Expr *sqlite3ExprSkipCollate(Expr*);
|
||||
int sqlite3CheckCollSeq(Parse *, CollSeq *);
|
||||
@@ -3599,4 +3676,19 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...);
|
||||
#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
|
||||
#define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */
|
||||
|
||||
/*
|
||||
** Threading interface
|
||||
*/
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
|
||||
int sqlite3ThreadJoin(SQLiteThread*, void**);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Win32 interface
|
||||
*/
|
||||
#if SQLITE_OS_WIN
|
||||
DWORD sqlite3Win32Wait(HANDLE hObject);
|
||||
#endif
|
||||
|
||||
#endif /* _SQLITEINT_H_ */
|
||||
|
||||
+164
@@ -2703,6 +2703,46 @@ bad_args:
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: add_test_utf16bin_collate <db ptr>
|
||||
**
|
||||
** Add a utf-16 collation sequence named "utf16bin" to the database
|
||||
** handle. This collation sequence compares arguments in the same way as the
|
||||
** built-in collation "binary".
|
||||
*/
|
||||
static int test_utf16bin_collate_func(
|
||||
void *pCtx,
|
||||
int nA, const void *zA,
|
||||
int nB, const void *zB
|
||||
){
|
||||
int nCmp = (nA>nB ? nB : nA);
|
||||
int res = memcmp(zA, zB, nCmp);
|
||||
if( res==0 ) res = nA - nB;
|
||||
return res;
|
||||
}
|
||||
static int test_utf16bin_collate(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
if( objc!=2 ) goto bad_args;
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
|
||||
rc = sqlite3_create_collation(db, "utf16bin", SQLITE_UTF16, 0,
|
||||
test_utf16bin_collate_func
|
||||
);
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
return TCL_OK;
|
||||
|
||||
bad_args:
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
** When the collation needed callback is invoked, record the name of
|
||||
** the requested collating function here. The recorded name is linked
|
||||
@@ -5844,6 +5884,7 @@ static int test_test_control(
|
||||
int i;
|
||||
} aVerb[] = {
|
||||
{ "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT },
|
||||
{ "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP },
|
||||
};
|
||||
int iVerb;
|
||||
int iFlag;
|
||||
@@ -5871,6 +5912,19 @@ static int test_test_control(
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, val);
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_TESTCTRL_SORTER_MMAP: {
|
||||
int val;
|
||||
sqlite3 *db;
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "DB LIMIT");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR;
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
@@ -6282,6 +6336,113 @@ static int tclLoadStaticExtensionCmd(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** sorter_test_fakeheap BOOL
|
||||
**
|
||||
*/
|
||||
static int sorter_test_fakeheap(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int bArg;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[1], &bArg) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( bArg ){
|
||||
if( sqlite3GlobalConfig.pHeap==0 ){
|
||||
sqlite3GlobalConfig.pHeap = SQLITE_INT_TO_PTR(-1);
|
||||
}
|
||||
}else{
|
||||
if( sqlite3GlobalConfig.pHeap==SQLITE_INT_TO_PTR(-1) ){
|
||||
sqlite3GlobalConfig.pHeap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** sorter_test_sort4_helper DB SQL1 NSTEP SQL2
|
||||
**
|
||||
** Compile SQL statement $SQL1 and step it $NSTEP times. For each row,
|
||||
** check that the leftmost and rightmost columns returned are both integers,
|
||||
** and that both contain the same value.
|
||||
**
|
||||
** Then execute statement $SQL2. Check that the statement returns the same
|
||||
** set of integers in the same order as in the previous step (using $SQL1).
|
||||
*/
|
||||
static int sorter_test_sort4_helper(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
const char *zSql1;
|
||||
const char *zSql2;
|
||||
int nStep;
|
||||
int iStep;
|
||||
int iCksum1 = 0;
|
||||
int iCksum2 = 0;
|
||||
int rc;
|
||||
int iB;
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *pStmt;
|
||||
|
||||
if( objc!=5 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB SQL1 NSTEP SQL2");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zSql1 = Tcl_GetString(objv[2]);
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &nStep) ) return TCL_ERROR;
|
||||
zSql2 = Tcl_GetString(objv[4]);
|
||||
|
||||
rc = sqlite3_prepare_v2(db, zSql1, -1, &pStmt, 0);
|
||||
if( rc!=SQLITE_OK ) goto sql_error;
|
||||
|
||||
iB = sqlite3_column_count(pStmt)-1;
|
||||
for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){
|
||||
int a = sqlite3_column_int(pStmt, 0);
|
||||
if( a!=sqlite3_column_int(pStmt, iB) ){
|
||||
Tcl_AppendResult(interp, "data error: (a!=b)", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
iCksum1 += (iCksum1 << 3) + a;
|
||||
}
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc!=SQLITE_OK ) goto sql_error;
|
||||
|
||||
rc = sqlite3_prepare_v2(db, zSql2, -1, &pStmt, 0);
|
||||
if( rc!=SQLITE_OK ) goto sql_error;
|
||||
for(iStep=0; SQLITE_ROW==sqlite3_step(pStmt); iStep++){
|
||||
int a = sqlite3_column_int(pStmt, 0);
|
||||
iCksum2 += (iCksum2 << 3) + a;
|
||||
}
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc!=SQLITE_OK ) goto sql_error;
|
||||
|
||||
if( iCksum1!=iCksum2 ){
|
||||
Tcl_AppendResult(interp, "checksum mismatch", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
sql_error:
|
||||
Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
@@ -6481,6 +6642,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "add_test_collate", test_collate, 0 },
|
||||
{ "add_test_collate_needed", test_collate_needed, 0 },
|
||||
{ "add_test_function", test_function, 0 },
|
||||
{ "add_test_utf16bin_collate", test_utf16bin_collate, 0 },
|
||||
#endif
|
||||
{ "sqlite3_test_errstr", test_errstr, 0 },
|
||||
{ "tcl_variable_type", tcl_variable_type, 0 },
|
||||
@@ -6514,6 +6676,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "getrusage", test_getrusage },
|
||||
#endif
|
||||
{ "load_static_extension", tclLoadStaticExtensionCmd },
|
||||
{ "sorter_test_fakeheap", sorter_test_fakeheap },
|
||||
{ "sorter_test_sort4_helper", sorter_test_sort4_helper },
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
int i;
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ void sqlite3BtreeCursorList(Btree *p){
|
||||
BtShared *pBt = p->pBt;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
MemPage *pPage = pCur->apPage[pCur->iPage];
|
||||
char *zMode = pCur->wrFlag ? "rw" : "ro";
|
||||
char *zMode = (pCur->curFlags & BTCF_WriteFlag) ? "rw" : "ro";
|
||||
sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n",
|
||||
pCur, pCur->pgnoRoot, zMode,
|
||||
pPage ? pPage->pgno : 0, pCur->aiIdx[pCur->iPage],
|
||||
|
||||
@@ -99,6 +99,10 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "mmap", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
Tcl_SetVar2(interp, "sqlite_options", "worker_threads",
|
||||
STRINGVALUE(SQLITE_MAX_WORKER_THREADS), TCL_GLOBAL_ONLY
|
||||
);
|
||||
|
||||
#if 1 /* def SQLITE_MEMDEBUG */
|
||||
Tcl_SetVar2(interp, "sqlite_options", "memdebug", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
@@ -1253,6 +1253,32 @@ static int test_config_cis(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_config_worker_threads N
|
||||
*/
|
||||
static int test_config_worker_threads(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int rc;
|
||||
int nThread;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "N");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp, objv[1], &nThread) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, nThread);
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_dump_memsys3 FILENAME
|
||||
** sqlite3_dump_memsys5 FILENAME
|
||||
@@ -1506,6 +1532,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_config_error", test_config_error ,0 },
|
||||
{ "sqlite3_config_uri", test_config_uri ,0 },
|
||||
{ "sqlite3_config_cis", test_config_cis ,0 },
|
||||
{ "sqlite3_config_worker_threads", test_config_worker_threads ,0 },
|
||||
{ "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
|
||||
{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
|
||||
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
|
||||
|
||||
+183
-17
@@ -35,6 +35,8 @@ struct Circle {
|
||||
double centerx;
|
||||
double centery;
|
||||
double radius;
|
||||
double mxArea;
|
||||
int eScoreType;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -50,11 +52,7 @@ static void circle_del(void *p){
|
||||
static int circle_geom(
|
||||
sqlite3_rtree_geometry *p,
|
||||
int nCoord,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
sqlite3_int64 *aCoord,
|
||||
#else
|
||||
double *aCoord,
|
||||
#endif
|
||||
sqlite3_rtree_dbl *aCoord,
|
||||
int *pRes
|
||||
){
|
||||
int i; /* Iterator variable */
|
||||
@@ -62,7 +60,12 @@ static int circle_geom(
|
||||
double xmin, xmax; /* X dimensions of box being tested */
|
||||
double ymin, ymax; /* X dimensions of box being tested */
|
||||
|
||||
if( p->pUser==0 ){
|
||||
xmin = aCoord[0];
|
||||
xmax = aCoord[1];
|
||||
ymin = aCoord[2];
|
||||
ymax = aCoord[3];
|
||||
pCircle = (Circle *)p->pUser;
|
||||
if( pCircle==0 ){
|
||||
/* If pUser is still 0, then the parameter values have not been tested
|
||||
** for correctness or stored into a Circle structure yet. Do this now. */
|
||||
|
||||
@@ -108,14 +111,9 @@ static int circle_geom(
|
||||
pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius;
|
||||
pCircle->aBox[1].ymin = pCircle->centery;
|
||||
pCircle->aBox[1].ymax = pCircle->centery;
|
||||
pCircle->mxArea = (xmax - xmin)*(ymax - ymin) + 1.0;
|
||||
}
|
||||
|
||||
pCircle = (Circle *)p->pUser;
|
||||
xmin = aCoord[0];
|
||||
xmax = aCoord[1];
|
||||
ymin = aCoord[2];
|
||||
ymax = aCoord[3];
|
||||
|
||||
/* Check if any of the 4 corners of the bounding-box being tested lie
|
||||
** inside the circular region. If they do, then the bounding-box does
|
||||
** intersect the region of interest. Set the output variable to true and
|
||||
@@ -154,6 +152,170 @@ static int circle_geom(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of "circle" r-tree geometry callback using the
|
||||
** 2nd-generation interface that allows scoring.
|
||||
*/
|
||||
static int circle_query_func(sqlite3_rtree_query_info *p){
|
||||
int i; /* Iterator variable */
|
||||
Circle *pCircle; /* Structure defining circular region */
|
||||
double xmin, xmax; /* X dimensions of box being tested */
|
||||
double ymin, ymax; /* X dimensions of box being tested */
|
||||
int nWithin = 0; /* Number of corners inside the circle */
|
||||
|
||||
xmin = p->aCoord[0];
|
||||
xmax = p->aCoord[1];
|
||||
ymin = p->aCoord[2];
|
||||
ymax = p->aCoord[3];
|
||||
pCircle = (Circle *)p->pUser;
|
||||
if( pCircle==0 ){
|
||||
/* If pUser is still 0, then the parameter values have not been tested
|
||||
** for correctness or stored into a Circle structure yet. Do this now. */
|
||||
|
||||
/* This geometry callback is for use with a 2-dimensional r-tree table.
|
||||
** Return an error if the table does not have exactly 2 dimensions. */
|
||||
if( p->nCoord!=4 ) return SQLITE_ERROR;
|
||||
|
||||
/* Test that the correct number of parameters (4) have been supplied,
|
||||
** and that the parameters are in range (that the radius of the circle
|
||||
** radius is greater than zero). */
|
||||
if( p->nParam!=4 || p->aParam[2]<0.0 ) return SQLITE_ERROR;
|
||||
|
||||
/* Allocate a structure to cache parameter data in. Return SQLITE_NOMEM
|
||||
** if the allocation fails. */
|
||||
pCircle = (Circle *)(p->pUser = sqlite3_malloc(sizeof(Circle)));
|
||||
if( !pCircle ) return SQLITE_NOMEM;
|
||||
p->xDelUser = circle_del;
|
||||
|
||||
/* Record the center and radius of the circular region. One way that
|
||||
** tested bounding boxes that intersect the circular region are detected
|
||||
** is by testing if each corner of the bounding box lies within radius
|
||||
** units of the center of the circle. */
|
||||
pCircle->centerx = p->aParam[0];
|
||||
pCircle->centery = p->aParam[1];
|
||||
pCircle->radius = p->aParam[2];
|
||||
pCircle->eScoreType = (int)p->aParam[3];
|
||||
|
||||
/* Define two bounding box regions. The first, aBox[0], extends to
|
||||
** infinity in the X dimension. It covers the same range of the Y dimension
|
||||
** as the circular region. The second, aBox[1], extends to infinity in
|
||||
** the Y dimension and is constrained to the range of the circle in the
|
||||
** X dimension.
|
||||
**
|
||||
** Then imagine each box is split in half along its short axis by a line
|
||||
** that intersects the center of the circular region. A bounding box
|
||||
** being tested can be said to intersect the circular region if it contains
|
||||
** points from each half of either of the two infinite bounding boxes.
|
||||
*/
|
||||
pCircle->aBox[0].xmin = pCircle->centerx;
|
||||
pCircle->aBox[0].xmax = pCircle->centerx;
|
||||
pCircle->aBox[0].ymin = pCircle->centery + pCircle->radius;
|
||||
pCircle->aBox[0].ymax = pCircle->centery - pCircle->radius;
|
||||
pCircle->aBox[1].xmin = pCircle->centerx + pCircle->radius;
|
||||
pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius;
|
||||
pCircle->aBox[1].ymin = pCircle->centery;
|
||||
pCircle->aBox[1].ymax = pCircle->centery;
|
||||
pCircle->mxArea = 200.0*200.0;
|
||||
}
|
||||
|
||||
/* Check if any of the 4 corners of the bounding-box being tested lie
|
||||
** inside the circular region. If they do, then the bounding-box does
|
||||
** intersect the region of interest. Set the output variable to true and
|
||||
** return SQLITE_OK in this case. */
|
||||
for(i=0; i<4; i++){
|
||||
double x = (i&0x01) ? xmax : xmin;
|
||||
double y = (i&0x02) ? ymax : ymin;
|
||||
double d2;
|
||||
|
||||
d2 = (x-pCircle->centerx)*(x-pCircle->centerx);
|
||||
d2 += (y-pCircle->centery)*(y-pCircle->centery);
|
||||
if( d2<(pCircle->radius*pCircle->radius) ) nWithin++;
|
||||
}
|
||||
|
||||
/* Check if the bounding box covers any other part of the circular region.
|
||||
** See comments above for a description of how this test works. If it does
|
||||
** cover part of the circular region, set the output variable to true
|
||||
** and return SQLITE_OK. */
|
||||
if( nWithin==0 ){
|
||||
for(i=0; i<2; i++){
|
||||
if( xmin<=pCircle->aBox[i].xmin
|
||||
&& xmax>=pCircle->aBox[i].xmax
|
||||
&& ymin<=pCircle->aBox[i].ymin
|
||||
&& ymax>=pCircle->aBox[i].ymax
|
||||
){
|
||||
nWithin = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pCircle->eScoreType==1 ){
|
||||
/* Depth first search */
|
||||
p->rScore = p->iLevel;
|
||||
}else if( pCircle->eScoreType==2 ){
|
||||
/* Breadth first search */
|
||||
p->rScore = 100 - p->iLevel;
|
||||
}else if( pCircle->eScoreType==3 ){
|
||||
/* Depth-first search, except sort the leaf nodes by area with
|
||||
** the largest area first */
|
||||
if( p->iLevel==1 ){
|
||||
p->rScore = 1.0 - (xmax-xmin)*(ymax-ymin)/pCircle->mxArea;
|
||||
if( p->rScore<0.01 ) p->rScore = 0.01;
|
||||
}else{
|
||||
p->rScore = 0.0;
|
||||
}
|
||||
}else if( pCircle->eScoreType==4 ){
|
||||
/* Depth-first search, except exclude odd rowids */
|
||||
p->rScore = p->iLevel;
|
||||
if( p->iRowid&1 ) nWithin = 0;
|
||||
}else{
|
||||
/* Breadth-first search, except exclude odd rowids */
|
||||
p->rScore = 100 - p->iLevel;
|
||||
if( p->iRowid&1 ) nWithin = 0;
|
||||
}
|
||||
if( nWithin==0 ){
|
||||
p->eWithin = NOT_WITHIN;
|
||||
}else if( nWithin>=4 ){
|
||||
p->eWithin = FULLY_WITHIN;
|
||||
}else{
|
||||
p->eWithin = PARTLY_WITHIN;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
/*
|
||||
** Implementation of "breadthfirstsearch" r-tree geometry callback using the
|
||||
** 2nd-generation interface that allows scoring.
|
||||
**
|
||||
** ... WHERE id MATCH breadthfirstsearch($x0,$x1,$y0,$y1) ...
|
||||
**
|
||||
** It returns all entries whose bounding boxes overlap with $x0,$x1,$y0,$y1.
|
||||
*/
|
||||
static int bfs_query_func(sqlite3_rtree_query_info *p){
|
||||
double x0,x1,y0,y1; /* Dimensions of box being tested */
|
||||
double bx0,bx1,by0,by1; /* Boundary of the query function */
|
||||
|
||||
if( p->nParam!=4 ) return SQLITE_ERROR;
|
||||
x0 = p->aCoord[0];
|
||||
x1 = p->aCoord[1];
|
||||
y0 = p->aCoord[2];
|
||||
y1 = p->aCoord[3];
|
||||
bx0 = p->aParam[0];
|
||||
bx1 = p->aParam[1];
|
||||
by0 = p->aParam[2];
|
||||
by1 = p->aParam[3];
|
||||
p->rScore = 100 - p->iLevel;
|
||||
if( p->eParentWithin==FULLY_WITHIN ){
|
||||
p->eWithin = FULLY_WITHIN;
|
||||
}else if( x0>=bx0 && x1<=bx1 && y0>=by0 && y1<=by1 ){
|
||||
p->eWithin = FULLY_WITHIN;
|
||||
}else if( x1>=bx0 && x0<=bx1 && y1>=by0 && y0<=by1 ){
|
||||
p->eWithin = PARTLY_WITHIN;
|
||||
}else{
|
||||
p->eWithin = NOT_WITHIN;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* END of implementation of "circle" geometry callback.
|
||||
**************************************************************************
|
||||
*************************************************************************/
|
||||
@@ -194,11 +356,7 @@ static int gHere = 42;
|
||||
static int cube_geom(
|
||||
sqlite3_rtree_geometry *p,
|
||||
int nCoord,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
sqlite3_int64 *aCoord,
|
||||
#else
|
||||
double *aCoord,
|
||||
#endif
|
||||
sqlite3_rtree_dbl *aCoord,
|
||||
int *piRes
|
||||
){
|
||||
Cube *pCube = (Cube *)p->pUser;
|
||||
@@ -293,6 +451,14 @@ static int register_circle_geom(
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_rtree_geometry_callback(db, "circle", circle_geom, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_rtree_query_callback(db, "Qcircle",
|
||||
circle_query_func, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_rtree_query_callback(db, "breadthfirstsearch",
|
||||
bfs_query_func, 0, 0);
|
||||
}
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
|
||||
#endif
|
||||
return TCL_OK;
|
||||
|
||||
+48
-1
@@ -67,6 +67,11 @@
|
||||
** test_syscall list
|
||||
** Return a list of all system calls. The list is constructed using
|
||||
** the xNextSystemCall() VFS method.
|
||||
**
|
||||
** test_syscall pagesize PGSZ
|
||||
** If PGSZ is a power of two greater than 256, install a wrapper around
|
||||
** OS function getpagesize() that reports the system page size as PGSZ.
|
||||
** Or, if PGSZ is less than zero, remove any wrapper already installed.
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
@@ -89,7 +94,9 @@ static struct TestSyscallGlobal {
|
||||
int bPersist; /* 1 for persistent errors, 0 for transient */
|
||||
int nCount; /* Fail after this many more calls */
|
||||
int nFail; /* Number of failures that have occurred */
|
||||
} gSyscall = { 0, 0 };
|
||||
int pgsz;
|
||||
sqlite3_syscall_ptr orig_getpagesize;
|
||||
} gSyscall = { 0, 0, 0, 0, 0 };
|
||||
|
||||
static int ts_open(const char *, int, int);
|
||||
static int ts_close(int fd);
|
||||
@@ -650,6 +657,45 @@ static int test_syscall_defaultvfs(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int ts_getpagesize(void){
|
||||
return gSyscall.pgsz;
|
||||
}
|
||||
|
||||
static int test_syscall_pagesize(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
|
||||
int pgsz;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "PGSZ");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &pgsz) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( pgsz<0 ){
|
||||
if( gSyscall.orig_getpagesize ){
|
||||
pVfs->xSetSystemCall(pVfs, "getpagesize", gSyscall.orig_getpagesize);
|
||||
}
|
||||
}else{
|
||||
if( pgsz<512 || (pgsz & (pgsz-1)) ){
|
||||
Tcl_AppendResult(interp, "pgsz out of range", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
gSyscall.orig_getpagesize = pVfs->xGetSystemCall(pVfs, "getpagesize");
|
||||
gSyscall.pgsz = pgsz;
|
||||
pVfs->xSetSystemCall(
|
||||
pVfs, "getpagesize", (sqlite3_syscall_ptr)ts_getpagesize
|
||||
);
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_syscall(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
@@ -668,6 +714,7 @@ static int test_syscall(
|
||||
{ "exists", test_syscall_exists },
|
||||
{ "list", test_syscall_list },
|
||||
{ "defaultvfs", test_syscall_defaultvfs },
|
||||
{ "pagesize", test_syscall_pagesize },
|
||||
{ 0, 0 }
|
||||
};
|
||||
int iCmd;
|
||||
|
||||
+1
-1
@@ -678,7 +678,7 @@ static int vfstraceAccess(
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
|
||||
vfstrace_printf(pInfo, "%s.xAccess(\"%s\",%d)",
|
||||
pInfo->zVfsName, zPath, flags);
|
||||
rc = pRoot->xAccess(pRoot, zPath, flags, pResOut);
|
||||
vfstrace_print_errcode(pInfo, " -> %s", rc);
|
||||
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
** 2012 July 21
|
||||
**
|
||||
** 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 presents a simple cross-platform threading interface for
|
||||
** use internally by SQLite.
|
||||
**
|
||||
** A "thread" can be created using sqlite3ThreadCreate(). This thread
|
||||
** runs independently of its creator until it is joined using
|
||||
** sqlite3ThreadJoin(), at which point it terminates.
|
||||
**
|
||||
** Threads do not have to be real. It could be that the work of the
|
||||
** "thread" is done by the main thread at either the sqlite3ThreadCreate()
|
||||
** or sqlite3ThreadJoin() call. This is, in fact, what happens in
|
||||
** single threaded systems. Nothing in SQLite requires multiple threads.
|
||||
** This interface exists so that applications that want to take advantage
|
||||
** of multiple cores can do so, while also allowing applications to stay
|
||||
** single-threaded if desired.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
|
||||
/********************************* Unix Pthreads ****************************/
|
||||
#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
|
||||
|
||||
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
|
||||
#include <pthread.h>
|
||||
|
||||
/* A running thread */
|
||||
struct SQLiteThread {
|
||||
pthread_t tid; /* Thread ID */
|
||||
int done; /* Set to true when thread finishes */
|
||||
void *pOut; /* Result returned by the thread */
|
||||
void *(*xTask)(void*); /* The thread routine */
|
||||
void *pIn; /* Argument to the thread */
|
||||
};
|
||||
|
||||
/* Create a new thread */
|
||||
int sqlite3ThreadCreate(
|
||||
SQLiteThread **ppThread, /* OUT: Write the thread object here */
|
||||
void *(*xTask)(void*), /* Routine to run in a separate thread */
|
||||
void *pIn /* Argument passed into xTask() */
|
||||
){
|
||||
SQLiteThread *p;
|
||||
|
||||
assert( ppThread!=0 );
|
||||
assert( xTask!=0 );
|
||||
*ppThread = 0;
|
||||
p = sqlite3Malloc(sizeof(*p));
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->xTask = xTask;
|
||||
p->pIn = pIn;
|
||||
if( sqlite3GlobalConfig.bCoreMutex==0
|
||||
|| pthread_create(&p->tid, 0, xTask, pIn)!=0
|
||||
){
|
||||
p->done = 1;
|
||||
p->pOut = xTask(pIn);
|
||||
}
|
||||
*ppThread = p;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Get the results of the thread */
|
||||
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
|
||||
int rc;
|
||||
|
||||
assert( ppOut!=0 );
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
if( p->done ){
|
||||
*ppOut = p->pOut;
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = pthread_join(p->tid, ppOut);
|
||||
}
|
||||
sqlite3_free(p);
|
||||
return rc ? SQLITE_ERROR : SQLITE_OK;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
|
||||
/******************************** End Unix Pthreads *************************/
|
||||
|
||||
|
||||
/********************************* Win32 Threads ****************************/
|
||||
#if SQLITE_OS_WIN && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0
|
||||
|
||||
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
|
||||
#include <process.h>
|
||||
|
||||
/* A running thread */
|
||||
struct SQLiteThread {
|
||||
uintptr_t tid; /* The thread handle */
|
||||
void *(*xTask)(void*); /* The routine to run as a thread */
|
||||
void *pIn; /* Argument to xTask */
|
||||
void *pResult; /* Result of xTask */
|
||||
};
|
||||
|
||||
/* Thread procedure Win32 compatibility shim */
|
||||
static void sqlite3ThreadProc(
|
||||
void *pArg /* IN: Pointer to the SQLiteThread structure */
|
||||
){
|
||||
SQLiteThread *p = (SQLiteThread *)pArg;
|
||||
|
||||
assert( p!=0 );
|
||||
assert( p->xTask!=0 );
|
||||
p->pResult = p->xTask(p->pIn);
|
||||
_endthread();
|
||||
}
|
||||
|
||||
/* Create a new thread */
|
||||
int sqlite3ThreadCreate(
|
||||
SQLiteThread **ppThread, /* OUT: Write the thread object here */
|
||||
void *(*xTask)(void*), /* Routine to run in a separate thread */
|
||||
void *pIn /* Argument passed into xTask() */
|
||||
){
|
||||
SQLiteThread *p;
|
||||
|
||||
assert( ppThread!=0 );
|
||||
assert( xTask!=0 );
|
||||
*ppThread = 0;
|
||||
p = sqlite3Malloc(sizeof(*p));
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
if( sqlite3GlobalConfig.bCoreMutex==0 ){
|
||||
memset(p, 0, sizeof(*p));
|
||||
}else{
|
||||
p->xTask = xTask;
|
||||
p->pIn = pIn;
|
||||
p->tid = _beginthread(sqlite3ThreadProc, 0, p);
|
||||
if( p->tid==(uintptr_t)-1 ){
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
}
|
||||
if( p->xTask==0 ){
|
||||
p->pResult = xTask(pIn);
|
||||
}
|
||||
*ppThread = p;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Get the results of the thread */
|
||||
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
|
||||
DWORD rc;
|
||||
|
||||
assert( ppOut!=0 );
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
if( p->xTask==0 ){
|
||||
rc = WAIT_OBJECT_0;
|
||||
}else{
|
||||
rc = sqlite3Win32Wait((HANDLE)p->tid);
|
||||
assert( rc!=WAIT_IO_COMPLETION );
|
||||
}
|
||||
if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
|
||||
sqlite3_free(p);
|
||||
return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINRT */
|
||||
/******************************** End Win32 Threads *************************/
|
||||
|
||||
|
||||
/********************************* Single-Threaded **************************/
|
||||
#ifndef SQLITE_THREADS_IMPLEMENTED
|
||||
/*
|
||||
** This implementation does not actually create a new thread. It does the
|
||||
** work of the thread in the main thread, when either the thread is created
|
||||
** or when it is joined
|
||||
*/
|
||||
|
||||
/* A running thread */
|
||||
struct SQLiteThread {
|
||||
void *(*xTask)(void*); /* The routine to run as a thread */
|
||||
void *pIn; /* Argument to xTask */
|
||||
void *pResult; /* Result of xTask */
|
||||
};
|
||||
|
||||
/* Create a new thread */
|
||||
int sqlite3ThreadCreate(
|
||||
SQLiteThread **ppThread, /* OUT: Write the thread object here */
|
||||
void *(*xTask)(void*), /* Routine to run in a separate thread */
|
||||
void *pIn /* Argument passed into xTask() */
|
||||
){
|
||||
SQLiteThread *p;
|
||||
|
||||
assert( ppThread!=0 );
|
||||
assert( xTask!=0 );
|
||||
*ppThread = 0;
|
||||
p = sqlite3Malloc(sizeof(*p));
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
|
||||
p->xTask = xTask;
|
||||
p->pIn = pIn;
|
||||
}else{
|
||||
p->xTask = 0;
|
||||
p->pResult = xTask(pIn);
|
||||
}
|
||||
*ppThread = p;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Get the results of the thread */
|
||||
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
|
||||
|
||||
assert( ppOut!=0 );
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
if( p->xTask ){
|
||||
*ppOut = p->xTask(p->pIn);
|
||||
}else{
|
||||
*ppOut = p->pResult;
|
||||
}
|
||||
sqlite3_free(p);
|
||||
|
||||
#if defined(SQLITE_TEST)
|
||||
{
|
||||
void *pTstAlloc = sqlite3Malloc(10);
|
||||
if (!pTstAlloc) return SQLITE_NOMEM;
|
||||
sqlite3_free(pTstAlloc);
|
||||
}
|
||||
#endif
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
|
||||
/****************************** End Single-Threaded *************************/
|
||||
#endif /* SQLITE_MAX_WORKER_THREADS>0 */
|
||||
+1
-1
@@ -566,7 +566,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
||||
assert( pTable!=0 );
|
||||
if( (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
int base;
|
||||
static const int iLn = __LINE__+2;
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList dropTrigger[] = {
|
||||
{ OP_Rewind, 0, ADDR(9), 0},
|
||||
{ OP_String8, 0, 1, 0}, /* 1 */
|
||||
|
||||
+2
-2
@@ -1246,8 +1246,8 @@ LogEst sqlite3LogEstAdd(LogEst a, LogEst b){
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert an integer into a LogEst. In other words, compute a
|
||||
** good approximatation for 10*log2(x).
|
||||
** Convert an integer into a LogEst. In other words, compute an
|
||||
** approximation for 10*log2(x).
|
||||
*/
|
||||
LogEst sqlite3LogEst(u64 x){
|
||||
static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
|
||||
|
||||
+103
-24
@@ -28,7 +28,7 @@
|
||||
** pointer to the string or blob, not the content. If the original
|
||||
** is changed while the copy is still in use, the string or blob might
|
||||
** be changed out from under the copy. This macro verifies that nothing
|
||||
** like that every happens.
|
||||
** like that ever happens.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
# define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M)
|
||||
@@ -310,6 +310,29 @@ void sqlite3ValueApplyAffinity(
|
||||
applyAffinity((Mem *)pVal, affinity, enc);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
|
||||
** none.
|
||||
**
|
||||
** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
|
||||
** But it does set pMem->r and pMem->u.i appropriately.
|
||||
*/
|
||||
static u16 numericType(Mem *pMem){
|
||||
if( pMem->flags & (MEM_Int|MEM_Real) ){
|
||||
return pMem->flags & (MEM_Int|MEM_Real);
|
||||
}
|
||||
if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
||||
if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){
|
||||
return 0;
|
||||
}
|
||||
if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
|
||||
return MEM_Int;
|
||||
}
|
||||
return MEM_Real;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Write a nice string representation of the contents of cell pMem
|
||||
@@ -671,6 +694,11 @@ int sqlite3VdbeExec(
|
||||
** The next instruction executed will be
|
||||
** the one at index P2 from the beginning of
|
||||
** the program.
|
||||
**
|
||||
** The P1 parameter is not actually used by this opcode. However, it
|
||||
** is sometimes set to 1 instead of 0 as a hint to the command-line shell
|
||||
** that this Goto is the bottom of a loop and that the lines from P2 down
|
||||
** to the current line should be indented for EXPLAIN output.
|
||||
*/
|
||||
case OP_Goto: { /* jump */
|
||||
pc = pOp->p2 - 1;
|
||||
@@ -1075,10 +1103,11 @@ case OP_Variable: { /* out2-prerelease */
|
||||
/* Opcode: Move P1 P2 P3 * *
|
||||
** Synopsis: r[P2@P3]=r[P1@P3]
|
||||
**
|
||||
** Move the values in register P1..P1+P3 over into
|
||||
** registers P2..P2+P3. Registers P1..P1+P3 are
|
||||
** Move the P3 values in register P1..P1+P3-1 over into
|
||||
** registers P2..P2+P3-1. Registers P1..P1+P3-1 are
|
||||
** left holding a NULL. It is an error for register ranges
|
||||
** P1..P1+P3 and P2..P2+P3 to overlap.
|
||||
** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error
|
||||
** for P3 to be less than 1.
|
||||
*/
|
||||
case OP_Move: {
|
||||
char *zMalloc; /* Holding variable for allocated memory */
|
||||
@@ -1089,7 +1118,7 @@ case OP_Move: {
|
||||
n = pOp->p3;
|
||||
p1 = pOp->p1;
|
||||
p2 = pOp->p2;
|
||||
assert( n>=0 && p1>0 && p2>0 );
|
||||
assert( n>0 && p1>0 && p2>0 );
|
||||
assert( p1+n<=p2 || p2+n<=p1 );
|
||||
|
||||
pIn1 = &aMem[p1];
|
||||
@@ -1113,7 +1142,7 @@ case OP_Move: {
|
||||
REGISTER_TRACE(p2++, pOut);
|
||||
pIn1++;
|
||||
pOut++;
|
||||
}while( n-- );
|
||||
}while( --n );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1345,20 +1374,22 @@ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
|
||||
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
|
||||
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
char bIntint; /* Started out as two integer operands */
|
||||
int flags; /* Combined MEM_* flags from both inputs */
|
||||
u16 flags; /* Combined MEM_* flags from both inputs */
|
||||
u16 type1; /* Numeric type of left operand */
|
||||
u16 type2; /* Numeric type of right operand */
|
||||
i64 iA; /* Integer value of left operand */
|
||||
i64 iB; /* Integer value of right operand */
|
||||
double rA; /* Real value of left operand */
|
||||
double rB; /* Real value of right operand */
|
||||
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
applyNumericAffinity(pIn1);
|
||||
type1 = numericType(pIn1);
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
applyNumericAffinity(pIn2);
|
||||
type2 = numericType(pIn2);
|
||||
pOut = &aMem[pOp->p3];
|
||||
flags = pIn1->flags | pIn2->flags;
|
||||
if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
|
||||
if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
|
||||
if( (type1 & type2 & MEM_Int)!=0 ){
|
||||
iA = pIn1->u.i;
|
||||
iB = pIn2->u.i;
|
||||
bIntint = 1;
|
||||
@@ -1414,7 +1445,7 @@ fp_math:
|
||||
}
|
||||
pOut->r = rB;
|
||||
MemSetTypeFlag(pOut, MEM_Real);
|
||||
if( (flags & MEM_Real)==0 && !bIntint ){
|
||||
if( ((type1|type2)&MEM_Real)==0 && !bIntint ){
|
||||
sqlite3VdbeIntegerAffinity(pOut);
|
||||
}
|
||||
#endif
|
||||
@@ -1990,6 +2021,7 @@ case OP_Permutation: {
|
||||
}
|
||||
|
||||
/* Opcode: Compare P1 P2 P3 P4 P5
|
||||
** Synopsis: r[P1@P3] <-> r[P2@P3]
|
||||
**
|
||||
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
|
||||
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
|
||||
@@ -2166,8 +2198,8 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
||||
**
|
||||
** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
|
||||
** set the flag and fall through to the next instruction. In other words,
|
||||
** this opcode causes all following up codes up through P2 (but not including
|
||||
** P2) to run just once and skipped on subsequent times through the loop.
|
||||
** this opcode causes all following opcodes up through P2 (but not including
|
||||
** P2) to run just once and to be skipped on subsequent times through the loop.
|
||||
*/
|
||||
case OP_Once: { /* jump */
|
||||
assert( pOp->p1<p->nOnceFlag );
|
||||
@@ -3325,6 +3357,7 @@ case OP_OpenEphemeral: {
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
pCx->isEphemeral = 1;
|
||||
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
|
||||
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -3357,11 +3390,15 @@ case OP_OpenEphemeral: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SorterOpen P1 P2 * P4 *
|
||||
/* Opcode: SorterOpen P1 P2 P3 P4 *
|
||||
**
|
||||
** This opcode works like OP_OpenEphemeral except that it opens
|
||||
** a transient index that is specifically designed to sort large
|
||||
** tables using an external merge-sort algorithm.
|
||||
**
|
||||
** If argument P3 is non-zero, then it indicates that the sorter may
|
||||
** assume that a stable sort considering the first P3 fields of each
|
||||
** key is sufficient to produce the required results.
|
||||
*/
|
||||
case OP_SorterOpen: {
|
||||
VdbeCursor *pCx;
|
||||
@@ -3373,7 +3410,25 @@ case OP_SorterOpen: {
|
||||
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
||||
assert( pCx->pKeyInfo->db==db );
|
||||
assert( pCx->pKeyInfo->enc==ENC(db) );
|
||||
rc = sqlite3VdbeSorterInit(db, pCx);
|
||||
rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SequenceTest P1 P2 * * *
|
||||
** Synopsis: if( cursor[P1].ctr++ ) pc = P2
|
||||
**
|
||||
** P1 is a sorter cursor. If the sequence counter is currently zero, jump
|
||||
** to P2. Regardless of whether or not the jump is taken, increment the
|
||||
** the sequence value.
|
||||
*/
|
||||
case OP_SequenceTest: {
|
||||
VdbeCursor *pC;
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC->pSorter );
|
||||
if( (pC->seqCount++)==0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3815,7 +3870,7 @@ case OP_NotExists: { /* jump, in3 */
|
||||
}
|
||||
|
||||
/* Opcode: Sequence P1 P2 * * *
|
||||
** Synopsis: r[P2]=rowid
|
||||
** Synopsis: r[P2]=cursor[P1].ctr++
|
||||
**
|
||||
** Find the next available sequence number for cursor P1.
|
||||
** Write the sequence number into register P2.
|
||||
@@ -4179,6 +4234,7 @@ case OP_SorterCompare: {
|
||||
assert( pOp->p4type==P4_INT32 );
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
nIgnore = pOp->p4.i;
|
||||
res = 0;
|
||||
rc = sqlite3VdbeSorterCompare(pC, pIn3, nIgnore, &res);
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ){
|
||||
@@ -4199,6 +4255,7 @@ case OP_SorterData: {
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( isSorter(pC) );
|
||||
rc = sqlite3VdbeSorterRowkey(pC, pOut);
|
||||
assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4428,7 +4485,7 @@ case OP_Rewind: { /* jump */
|
||||
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
|
||||
res = 1;
|
||||
if( isSorter(pC) ){
|
||||
rc = sqlite3VdbeSorterRewind(db, pC, &res);
|
||||
rc = sqlite3VdbeSorterRewind(pC, &res);
|
||||
}else{
|
||||
pCrsr = pC->pCursor;
|
||||
assert( pCrsr );
|
||||
@@ -4506,6 +4563,7 @@ case OP_SorterNext: { /* jump */
|
||||
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( isSorter(pC) );
|
||||
res = 0;
|
||||
rc = sqlite3VdbeSorterNext(db, pC, &res);
|
||||
goto next_tail;
|
||||
case OP_PrevIfOpen: /* jump */
|
||||
@@ -4586,7 +4644,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
rc = ExpandBlob(pIn2);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( isSorter(pC) ){
|
||||
rc = sqlite3VdbeSorterWrite(db, pC, pIn2);
|
||||
rc = sqlite3VdbeSorterWrite(pC, pIn2);
|
||||
}else{
|
||||
nKey = pIn2->n;
|
||||
zKey = pIn2->z;
|
||||
@@ -4864,6 +4922,29 @@ case OP_Clear: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: ResetSorter P1 * * * *
|
||||
**
|
||||
** Delete all contents from the ephemeral table or sorter
|
||||
** that is open on cursor P1.
|
||||
**
|
||||
** This opcode only works for cursors used for sorting and
|
||||
** opened with OP_OpenEphemeral or OP_SorterOpen.
|
||||
*/
|
||||
case OP_ResetSorter: {
|
||||
VdbeCursor *pC;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
if( pC->pSorter ){
|
||||
sqlite3VdbeSorterReset(db, pC->pSorter);
|
||||
}else{
|
||||
assert( pC->isEphemeral );
|
||||
rc = sqlite3BtreeClearTableOfCursor(pC->pCursor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: CreateTable P1 P2 * * *
|
||||
** Synopsis: r[P2]=root iDb=P1
|
||||
**
|
||||
@@ -5170,9 +5251,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
||||
assert( pOp->p4type==P4_INT32 );
|
||||
assert( iSet==-1 || iSet>=0 );
|
||||
if( iSet ){
|
||||
exists = sqlite3RowSetTest(pIn1->u.pRowSet,
|
||||
(u8)(iSet>=0 ? iSet & 0xf : 0xff),
|
||||
pIn3->u.i);
|
||||
exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i);
|
||||
VdbeBranchTaken(exists!=0,2);
|
||||
if( exists ){
|
||||
pc = pOp->p2 - 1;
|
||||
@@ -5872,7 +5951,7 @@ case OP_VOpen: {
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/* Opcode: VFilter P1 P2 P3 P4 *
|
||||
** Synopsis: iPlan=r[P3] zPlan='P4'
|
||||
** Synopsis: iplan=r[P3] zplan='P4'
|
||||
**
|
||||
** P1 is a cursor opened using VOpen. P2 is an address to jump to if
|
||||
** the filtered result set is empty.
|
||||
@@ -6268,8 +6347,8 @@ default: { /* This is really OP_Noop and OP_Explain */
|
||||
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
u64 elapsed = sqlite3Hwtime() - start;
|
||||
pOp->cycles += elapsed;
|
||||
u64 endTime = sqlite3Hwtime();
|
||||
if( endTime>start ) pOp->cycles += endTime - start;
|
||||
pOp->cnt++;
|
||||
}
|
||||
#endif
|
||||
|
||||
+4
-2
@@ -211,10 +211,10 @@ void sqlite3VdbeSetVarmask(Vdbe*, int);
|
||||
#endif
|
||||
|
||||
void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,const UnpackedRecord*,int);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int);
|
||||
UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
|
||||
|
||||
typedef int (*RecordCompare)(int,const void*,const UnpackedRecord*,int);
|
||||
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int);
|
||||
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
@@ -272,11 +272,13 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
|
||||
# define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__)
|
||||
# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2);
|
||||
# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1);
|
||||
# define VDBE_OFFSET_LINENO(x) (__LINE__+x)
|
||||
#else
|
||||
# define VdbeCoverage(v)
|
||||
# define VdbeCoverageIf(v,x)
|
||||
# define VdbeCoverageAlwaysTaken(v)
|
||||
# define VdbeCoverageNeverTaken(v)
|
||||
# define VDBE_OFFSET_LINENO(x) 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+6
-4
@@ -72,6 +72,7 @@ struct VdbeCursor {
|
||||
u8 nullRow; /* True if pointing to a row with no data */
|
||||
u8 rowidIsValid; /* True if lastRowid is valid */
|
||||
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||
Bool isEphemeral:1; /* True for an ephemeral table */
|
||||
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
|
||||
Bool isTable:1; /* True if a table requiring integer keys */
|
||||
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
|
||||
@@ -391,7 +392,7 @@ u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
||||
void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
|
||||
|
||||
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
|
||||
int sqlite3VdbeIdxKeyCompare(VdbeCursor*,const UnpackedRecord*,int*);
|
||||
int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
|
||||
int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
|
||||
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
|
||||
int sqlite3VdbeExec(Vdbe*);
|
||||
@@ -436,12 +437,13 @@ void sqlite3VdbeFrameDelete(VdbeFrame*);
|
||||
int sqlite3VdbeFrameRestore(VdbeFrame *);
|
||||
int sqlite3VdbeTransferError(Vdbe *p);
|
||||
|
||||
int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
|
||||
int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
|
||||
void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
|
||||
void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
|
||||
int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
|
||||
int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
|
||||
int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *);
|
||||
int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *);
|
||||
int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
|
||||
int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
|
||||
int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
|
||||
|
||||
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
|
||||
|
||||
+25
-23
@@ -135,7 +135,6 @@ const void *sqlite3_value_blob(sqlite3_value *pVal){
|
||||
Mem *p = (Mem*)pVal;
|
||||
if( p->flags & (MEM_Blob|MEM_Str) ){
|
||||
sqlite3VdbeMemExpandBlob(p);
|
||||
p->flags &= ~MEM_Str;
|
||||
p->flags |= MEM_Blob;
|
||||
return p->n ? p->z : 0;
|
||||
}else{
|
||||
@@ -727,6 +726,30 @@ int sqlite3_data_count(sqlite3_stmt *pStmt){
|
||||
return pVm->nResColumn;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to static memory containing an SQL NULL value.
|
||||
*/
|
||||
static const Mem *columnNullValue(void){
|
||||
/* Even though the Mem structure contains an element
|
||||
** of type i64, on certain architectures (x86) with certain compiler
|
||||
** switches (-Os), gcc may align this Mem object on a 4-byte boundary
|
||||
** instead of an 8-byte one. This all works fine, except that when
|
||||
** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s
|
||||
** that a Mem structure is located on an 8-byte boundary. To prevent
|
||||
** these assert()s from failing, when building with SQLITE_DEBUG defined
|
||||
** using gcc, we force nullMem to be 8-byte aligned using the magical
|
||||
** __attribute__((aligned(8))) macro. */
|
||||
static const Mem nullMem
|
||||
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
|
||||
__attribute__((aligned(8)))
|
||||
#endif
|
||||
= {0, "", (double)0, {0}, 0, MEM_Null, 0,
|
||||
#ifdef SQLITE_DEBUG
|
||||
0, 0, /* pScopyFrom, pFiller */
|
||||
#endif
|
||||
0, 0 };
|
||||
return &nullMem;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if column iCol of the given statement is valid. If
|
||||
@@ -743,32 +766,11 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
|
||||
sqlite3_mutex_enter(pVm->db->mutex);
|
||||
pOut = &pVm->pResultSet[i];
|
||||
}else{
|
||||
/* If the value passed as the second argument is out of range, return
|
||||
** a pointer to the following static Mem object which contains the
|
||||
** value SQL NULL. Even though the Mem structure contains an element
|
||||
** of type i64, on certain architectures (x86) with certain compiler
|
||||
** switches (-Os), gcc may align this Mem object on a 4-byte boundary
|
||||
** instead of an 8-byte one. This all works fine, except that when
|
||||
** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s
|
||||
** that a Mem structure is located on an 8-byte boundary. To prevent
|
||||
** these assert()s from failing, when building with SQLITE_DEBUG defined
|
||||
** using gcc, we force nullMem to be 8-byte aligned using the magical
|
||||
** __attribute__((aligned(8))) macro. */
|
||||
static const Mem nullMem
|
||||
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
|
||||
__attribute__((aligned(8)))
|
||||
#endif
|
||||
= {0, "", (double)0, {0}, 0, MEM_Null, 0,
|
||||
#ifdef SQLITE_DEBUG
|
||||
0, 0, /* pScopyFrom, pFiller */
|
||||
#endif
|
||||
0, 0 };
|
||||
|
||||
if( pVm && ALWAYS(pVm->db) ){
|
||||
sqlite3_mutex_enter(pVm->db->mutex);
|
||||
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
|
||||
}
|
||||
pOut = (Mem*)&nullMem;
|
||||
pOut = (Mem*)columnNullValue();
|
||||
}
|
||||
return pOut;
|
||||
}
|
||||
|
||||
+91
-37
@@ -276,7 +276,7 @@ void sqlite3VdbeResolveLabel(Vdbe *v, int x){
|
||||
int j = -1-x;
|
||||
assert( v->magic==VDBE_MAGIC_INIT );
|
||||
assert( j<p->nLabel );
|
||||
if( j>=0 && p->aLabel ){
|
||||
if( ALWAYS(j>=0) && p->aLabel ){
|
||||
p->aLabel[j] = v->nOp;
|
||||
}
|
||||
p->iFixedOp = v->nOp - 1;
|
||||
@@ -783,7 +783,9 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
||||
addr = p->nOp - 1;
|
||||
}
|
||||
pOp = &p->aOp[addr];
|
||||
assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 );
|
||||
assert( pOp->p4type==P4_NOTUSED
|
||||
|| pOp->p4type==P4_INT32
|
||||
|| pOp->p4type==P4_KEYINFO );
|
||||
freeP4(db, pOp->p4type, pOp->p4.p);
|
||||
pOp->p4.p = 0;
|
||||
if( n==P4_INT32 ){
|
||||
@@ -1234,6 +1236,10 @@ static void releaseMemArray(Mem *p, int N){
|
||||
** with no indexes using a single prepared INSERT statement, bind()
|
||||
** and reset(). Inserts are grouped into a transaction.
|
||||
*/
|
||||
testcase( p->flags & MEM_Agg );
|
||||
testcase( p->flags & MEM_Dyn );
|
||||
testcase( p->flags & MEM_Frame );
|
||||
testcase( p->flags & MEM_RowSet );
|
||||
if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
|
||||
sqlite3VdbeMemRelease(p);
|
||||
}else if( p->zMalloc ){
|
||||
@@ -2729,7 +2735,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
||||
if( rc ) return rc;
|
||||
if( hasMoved ){
|
||||
p->cacheStatus = CACHE_STALE;
|
||||
p->nullRow = 1;
|
||||
if( hasMoved==2 ) p->nullRow = 1;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
@@ -2962,27 +2968,32 @@ u32 sqlite3VdbeSerialGet(
|
||||
case 1: { /* 1-byte signed integer */
|
||||
pMem->u.i = ONE_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 1;
|
||||
}
|
||||
case 2: { /* 2-byte signed integer */
|
||||
pMem->u.i = TWO_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 2;
|
||||
}
|
||||
case 3: { /* 3-byte signed integer */
|
||||
pMem->u.i = THREE_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 3;
|
||||
}
|
||||
case 4: { /* 4-byte signed integer */
|
||||
y = FOUR_BYTE_UINT(buf);
|
||||
pMem->u.i = (i64)*(int*)&y;
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 4;
|
||||
}
|
||||
case 5: { /* 6-byte signed integer */
|
||||
pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 6;
|
||||
}
|
||||
case 6: /* 8-byte signed integer */
|
||||
@@ -3005,6 +3016,7 @@ u32 sqlite3VdbeSerialGet(
|
||||
if( serial_type==6 ){
|
||||
pMem->u.i = *(i64*)&x;
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
}else{
|
||||
assert( sizeof(x)==8 && sizeof(pMem->r)==8 );
|
||||
swapMixedEndianFloat(x);
|
||||
@@ -3125,10 +3137,14 @@ void sqlite3VdbeRecordUnpack(
|
||||
** sqlite3VdbeSerialGet() and sqlite3MemCompare() functions. It is used
|
||||
** in assert() statements to ensure that the optimized code in
|
||||
** sqlite3VdbeRecordCompare() returns results with these two primitives.
|
||||
**
|
||||
** Return true if the result of comparison is equivalent to desiredResult.
|
||||
** Return false if there is a disagreement.
|
||||
*/
|
||||
static int vdbeRecordCompareDebug(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
const UnpackedRecord *pPKey2 /* Right key */
|
||||
const UnpackedRecord *pPKey2, /* Right key */
|
||||
int desiredResult /* Correct answer */
|
||||
){
|
||||
u32 d1; /* Offset into aKey[] of next data element */
|
||||
u32 idx1; /* Offset into aKey[] of next header element */
|
||||
@@ -3140,6 +3156,7 @@ static int vdbeRecordCompareDebug(
|
||||
Mem mem1;
|
||||
|
||||
pKeyInfo = pPKey2->pKeyInfo;
|
||||
if( pKeyInfo->db==0 ) return 1;
|
||||
mem1.enc = pKeyInfo->enc;
|
||||
mem1.db = pKeyInfo->db;
|
||||
/* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */
|
||||
@@ -3190,7 +3207,7 @@ static int vdbeRecordCompareDebug(
|
||||
if( pKeyInfo->aSortOrder[i] ){
|
||||
rc = -rc; /* Invert the result for DESC sort order. */
|
||||
}
|
||||
return rc;
|
||||
goto debugCompareEnd;
|
||||
}
|
||||
i++;
|
||||
}while( idx1<szHdr1 && i<pPKey2->nField );
|
||||
@@ -3204,7 +3221,15 @@ static int vdbeRecordCompareDebug(
|
||||
/* rc==0 here means that one of the keys ran out of fields and
|
||||
** all the fields up to that point were equal. Return the the default_rc
|
||||
** value. */
|
||||
return pPKey2->default_rc;
|
||||
rc = pPKey2->default_rc;
|
||||
|
||||
debugCompareEnd:
|
||||
if( desiredResult==0 && rc==0 ) return 1;
|
||||
if( desiredResult<0 && rc<0 ) return 1;
|
||||
if( desiredResult>0 && rc>0 ) return 1;
|
||||
if( CORRUPT_DB ) return 1;
|
||||
if( pKeyInfo->db->mallocFailed ) return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3217,7 +3242,8 @@ static int vdbeRecordCompareDebug(
|
||||
static int vdbeCompareMemString(
|
||||
const Mem *pMem1,
|
||||
const Mem *pMem2,
|
||||
const CollSeq *pColl
|
||||
const CollSeq *pColl,
|
||||
u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */
|
||||
){
|
||||
if( pMem1->enc==pColl->enc ){
|
||||
/* The strings are already in the correct encoding. Call the
|
||||
@@ -3240,6 +3266,7 @@ static int vdbeCompareMemString(
|
||||
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
|
||||
sqlite3VdbeMemRelease(&c1);
|
||||
sqlite3VdbeMemRelease(&c2);
|
||||
if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@@ -3322,7 +3349,7 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
assert( !pColl || pColl->xCmp );
|
||||
|
||||
if( pColl ){
|
||||
return vdbeCompareMemString(pMem1, pMem2, pColl);
|
||||
return vdbeCompareMemString(pMem1, pMem2, pColl, 0);
|
||||
}
|
||||
/* If a NULL pointer was passed as the collate function, fall through
|
||||
** to the blob case and use memcmp(). */
|
||||
@@ -3350,20 +3377,26 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
||||
switch( serial_type ){
|
||||
case 0:
|
||||
case 1:
|
||||
testcase( aKey[0]&0x80 );
|
||||
return ONE_BYTE_INT(aKey);
|
||||
case 2:
|
||||
testcase( aKey[0]&0x80 );
|
||||
return TWO_BYTE_INT(aKey);
|
||||
case 3:
|
||||
testcase( aKey[0]&0x80 );
|
||||
return THREE_BYTE_INT(aKey);
|
||||
case 4: {
|
||||
testcase( aKey[0]&0x80 );
|
||||
y = FOUR_BYTE_UINT(aKey);
|
||||
return (i64)*(int*)&y;
|
||||
}
|
||||
case 5: {
|
||||
testcase( aKey[0]&0x80 );
|
||||
return FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey);
|
||||
}
|
||||
case 6: {
|
||||
u64 x = FOUR_BYTE_UINT(aKey);
|
||||
testcase( aKey[0]&0x80 );
|
||||
x = (x<<32) | FOUR_BYTE_UINT(aKey+4);
|
||||
return (i64)*(i64*)&x;
|
||||
}
|
||||
@@ -3387,10 +3420,15 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
||||
** Key1 and Key2 do not have to contain the same number of fields. If all
|
||||
** fields that appear in both keys are equal, then pPKey2->default_rc is
|
||||
** returned.
|
||||
**
|
||||
** If database corruption is discovered, set pPKey2->errCode to
|
||||
** SQLITE_CORRUPT and return 0. If an OOM error is encountered,
|
||||
** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
|
||||
** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
|
||||
*/
|
||||
int sqlite3VdbeRecordCompare(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
const UnpackedRecord *pPKey2, /* Right key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip /* If true, skip the first field */
|
||||
){
|
||||
u32 d1; /* Offset into aKey[] of next data element */
|
||||
@@ -3416,6 +3454,10 @@ int sqlite3VdbeRecordCompare(
|
||||
}else{
|
||||
idx1 = getVarint32(aKey1, szHdr1);
|
||||
d1 = szHdr1;
|
||||
if( d1>(unsigned)nKey1 ){
|
||||
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
|
||||
@@ -3431,6 +3473,7 @@ int sqlite3VdbeRecordCompare(
|
||||
/* RHS is an integer */
|
||||
if( pRhs->flags & MEM_Int ){
|
||||
serial_type = aKey1[idx1];
|
||||
testcase( serial_type==12 );
|
||||
if( serial_type>=12 ){
|
||||
rc = +1;
|
||||
}else if( serial_type==0 ){
|
||||
@@ -3481,20 +3524,26 @@ int sqlite3VdbeRecordCompare(
|
||||
/* RHS is a string */
|
||||
else if( pRhs->flags & MEM_Str ){
|
||||
getVarint32(&aKey1[idx1], serial_type);
|
||||
testcase( serial_type==12 );
|
||||
if( serial_type<12 ){
|
||||
rc = -1;
|
||||
}else if( !(serial_type & 0x01) ){
|
||||
rc = +1;
|
||||
}else{
|
||||
mem1.n = (serial_type - 12) / 2;
|
||||
testcase( (d1+mem1.n)==(unsigned)nKey1 );
|
||||
testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
|
||||
if( (d1+mem1.n) > (unsigned)nKey1 ){
|
||||
rc = 1; /* Corruption */
|
||||
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}else if( pKeyInfo->aColl[i] ){
|
||||
mem1.enc = pKeyInfo->enc;
|
||||
mem1.db = pKeyInfo->db;
|
||||
mem1.flags = MEM_Str;
|
||||
mem1.z = (char*)&aKey1[d1];
|
||||
rc = vdbeCompareMemString(&mem1, pRhs, pKeyInfo->aColl[i]);
|
||||
rc = vdbeCompareMemString(
|
||||
&mem1, pRhs, pKeyInfo->aColl[i], &pPKey2->errCode
|
||||
);
|
||||
}else{
|
||||
int nCmp = MIN(mem1.n, pRhs->n);
|
||||
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
|
||||
@@ -3506,12 +3555,16 @@ int sqlite3VdbeRecordCompare(
|
||||
/* RHS is a blob */
|
||||
else if( pRhs->flags & MEM_Blob ){
|
||||
getVarint32(&aKey1[idx1], serial_type);
|
||||
testcase( serial_type==12 );
|
||||
if( serial_type<12 || (serial_type & 0x01) ){
|
||||
rc = -1;
|
||||
}else{
|
||||
int nStr = (serial_type - 12) / 2;
|
||||
testcase( (d1+nStr)==(unsigned)nKey1 );
|
||||
testcase( (d1+nStr+1)==(unsigned)nKey1 );
|
||||
if( (d1+nStr) > (unsigned)nKey1 ){
|
||||
rc = 1; /* Corruption */
|
||||
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}else{
|
||||
int nCmp = MIN(nStr, pRhs->n);
|
||||
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
|
||||
@@ -3530,11 +3583,7 @@ int sqlite3VdbeRecordCompare(
|
||||
if( pKeyInfo->aSortOrder[i] ){
|
||||
rc = -rc;
|
||||
}
|
||||
assert( CORRUPT_DB
|
||||
|| (rc<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|
||||
|| (rc>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|
||||
|| pKeyInfo->db->mallocFailed
|
||||
);
|
||||
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) );
|
||||
assert( mem1.zMalloc==0 ); /* See comment below */
|
||||
return rc;
|
||||
}
|
||||
@@ -3553,9 +3602,7 @@ int sqlite3VdbeRecordCompare(
|
||||
/* rc==0 here means that one or both of the keys ran out of fields and
|
||||
** all the fields up to that point were equal. Return the the default_rc
|
||||
** value. */
|
||||
assert( CORRUPT_DB
|
||||
|| pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)
|
||||
);
|
||||
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) );
|
||||
return pPKey2->default_rc;
|
||||
}
|
||||
|
||||
@@ -3564,10 +3611,13 @@ int sqlite3VdbeRecordCompare(
|
||||
** that (a) the first field of pPKey2 is an integer, and (b) the
|
||||
** size-of-header varint at the start of (pKey1/nKey1) fits in a single
|
||||
** byte (i.e. is less than 128).
|
||||
**
|
||||
** To avoid concerns about buffer overreads, this routine is only used
|
||||
** on schemas where the maximum valid header size is 63 bytes or less.
|
||||
*/
|
||||
static int vdbeRecordCompareInt(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
const UnpackedRecord *pPKey2, /* Right key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip /* Ignored */
|
||||
){
|
||||
const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
|
||||
@@ -3580,32 +3630,39 @@ static int vdbeRecordCompareInt(
|
||||
UNUSED_PARAMETER(bSkip);
|
||||
|
||||
assert( bSkip==0 );
|
||||
assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
|
||||
switch( serial_type ){
|
||||
case 1: { /* 1-byte signed integer */
|
||||
lhs = ONE_BYTE_INT(aKey);
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 2: { /* 2-byte signed integer */
|
||||
lhs = TWO_BYTE_INT(aKey);
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 3: { /* 3-byte signed integer */
|
||||
lhs = THREE_BYTE_INT(aKey);
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 4: { /* 4-byte signed integer */
|
||||
y = FOUR_BYTE_UINT(aKey);
|
||||
lhs = (i64)*(int*)&y;
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 5: { /* 6-byte signed integer */
|
||||
lhs = FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey);
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 6: { /* 8-byte signed integer */
|
||||
x = FOUR_BYTE_UINT(aKey);
|
||||
x = (x<<32) | FOUR_BYTE_UINT(aKey+4);
|
||||
lhs = *(i64*)&x;
|
||||
testcase( lhs<0 );
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
@@ -3642,11 +3699,7 @@ static int vdbeRecordCompareInt(
|
||||
res = pPKey2->default_rc;
|
||||
}
|
||||
|
||||
assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0)
|
||||
|| (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|
||||
|| (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|
||||
|| CORRUPT_DB
|
||||
);
|
||||
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) );
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -3658,7 +3711,7 @@ static int vdbeRecordCompareInt(
|
||||
*/
|
||||
static int vdbeRecordCompareString(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
const UnpackedRecord *pPKey2, /* Right key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip
|
||||
){
|
||||
const u8 *aKey1 = (const u8*)pKey1;
|
||||
@@ -3679,7 +3732,10 @@ static int vdbeRecordCompareString(
|
||||
int szHdr = aKey1[0];
|
||||
|
||||
nStr = (serial_type-12) / 2;
|
||||
if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */
|
||||
if( (szHdr + nStr) > nKey1 ){
|
||||
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
||||
return 0; /* Corruption */
|
||||
}
|
||||
nCmp = MIN( pPKey2->aMem[0].n, nStr );
|
||||
res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
|
||||
|
||||
@@ -3703,11 +3759,7 @@ static int vdbeRecordCompareString(
|
||||
}
|
||||
}
|
||||
|
||||
assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0)
|
||||
|| (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|
||||
|| (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|
||||
|| CORRUPT_DB
|
||||
);
|
||||
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) );
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -3742,9 +3794,11 @@ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
|
||||
if( (flags & MEM_Int) ){
|
||||
return vdbeRecordCompareInt;
|
||||
}
|
||||
if( (flags & (MEM_Int|MEM_Real|MEM_Null|MEM_Blob))==0
|
||||
&& p->pKeyInfo->aColl[0]==0
|
||||
){
|
||||
testcase( flags & MEM_Real );
|
||||
testcase( flags & MEM_Null );
|
||||
testcase( flags & MEM_Blob );
|
||||
if( (flags & (MEM_Real|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){
|
||||
assert( flags & MEM_Str );
|
||||
return vdbeRecordCompareString;
|
||||
}
|
||||
}
|
||||
@@ -3842,7 +3896,7 @@ idx_rowid_corruption:
|
||||
*/
|
||||
int sqlite3VdbeIdxKeyCompare(
|
||||
VdbeCursor *pC, /* The cursor to compare against */
|
||||
const UnpackedRecord *pUnpacked, /* Unpacked version of key */
|
||||
UnpackedRecord *pUnpacked, /* Unpacked version of key */
|
||||
int *res /* Write the comparison result here */
|
||||
){
|
||||
i64 nCellKey = 0;
|
||||
|
||||
+2
-4
@@ -77,9 +77,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
|
||||
p->iOffset = pC->aType[p->iCol + pC->nField];
|
||||
p->nByte = sqlite3VdbeSerialTypeLen(type);
|
||||
p->pCsr = pC->pCursor;
|
||||
sqlite3BtreeEnterCursor(p->pCsr);
|
||||
sqlite3BtreeCacheOverflow(p->pCsr);
|
||||
sqlite3BtreeLeaveCursor(p->pCsr);
|
||||
sqlite3BtreeIncrblobCursor(p->pCsr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +131,7 @@ int sqlite3_blob_open(
|
||||
** which closes the b-tree cursor and (possibly) commits the
|
||||
** transaction.
|
||||
*/
|
||||
static const int iLn = __LINE__+4;
|
||||
static const int iLn = VDBE_OFFSET_LINENO(4);
|
||||
static const VdbeOpList openBlob[] = {
|
||||
/* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */
|
||||
{OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */
|
||||
|
||||
+1822
-452
File diff suppressed because it is too large
Load Diff
+563
-273
File diff suppressed because it is too large
Load Diff
+5
-4
@@ -121,7 +121,7 @@ struct WhereLoop {
|
||||
struct { /* Information for virtual tables */
|
||||
int idxNum; /* Index number */
|
||||
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
|
||||
u8 isOrdered; /* True if satisfies ORDER BY */
|
||||
i8 isOrdered; /* True if satisfies ORDER BY */
|
||||
u16 omitMask; /* Terms that may be omitted */
|
||||
char *idxStr; /* Index identifier string */
|
||||
} vtab;
|
||||
@@ -183,8 +183,7 @@ struct WherePath {
|
||||
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
|
||||
LogEst nRow; /* Estimated number of rows generated by this path */
|
||||
LogEst rCost; /* Total cost of this path */
|
||||
u8 isOrdered; /* True if this path satisfies ORDER BY */
|
||||
u8 isOrderedValid; /* True if the isOrdered field is valid */
|
||||
i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
|
||||
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
|
||||
};
|
||||
|
||||
@@ -398,7 +397,8 @@ struct WhereInfo {
|
||||
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
|
||||
LogEst nRowOut; /* Estimated number of output rows */
|
||||
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
|
||||
u8 bOBSat; /* ORDER BY satisfied by indices */
|
||||
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
|
||||
u8 sorted; /* True if really sorted (not just grouped) */
|
||||
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
|
||||
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
|
||||
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
|
||||
@@ -458,3 +458,4 @@ struct WhereInfo {
|
||||
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
|
||||
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
|
||||
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
|
||||
#define WHERE_LIKELIHOOD 0x00020000 /* A likelihood() is affecting nOut */
|
||||
|
||||
@@ -875,4 +875,42 @@ do_execsql_test alter-16.2 {
|
||||
SELECT * FROM t16a_rn ORDER BY a;
|
||||
} {abc 1.25 99 xyzzy cba 5.5 98 fizzle}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Verify that NULL values into the internal-use-only sqlite_rename_*()
|
||||
# functions do not cause problems.
|
||||
#
|
||||
do_execsql_test alter-17.1 {
|
||||
SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)','abc');
|
||||
} {{CREATE TABLE "abc"(a,b,c)}}
|
||||
do_execsql_test alter-17.2 {
|
||||
SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)',NULL);
|
||||
} {{CREATE TABLE "(NULL)"(a,b,c)}}
|
||||
do_execsql_test alter-17.3 {
|
||||
SELECT sqlite_rename_table(NULL,'abc');
|
||||
} {{}}
|
||||
do_execsql_test alter-17.4 {
|
||||
SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN','abc');
|
||||
} {{CREATE TRIGGER r1 ON "abc" WHEN}}
|
||||
do_execsql_test alter-17.5 {
|
||||
SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN',NULL);
|
||||
} {{CREATE TRIGGER r1 ON "(NULL)" WHEN}}
|
||||
do_execsql_test alter-17.6 {
|
||||
SELECT sqlite_rename_trigger(NULL,'abc');
|
||||
} {{}}
|
||||
do_execsql_test alter-17.7 {
|
||||
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
|
||||
'xyzzy','lmnop');
|
||||
} {{CREATE TABLE t1(a REFERENCES "lmnop")}}
|
||||
do_execsql_test alter-17.8 {
|
||||
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
|
||||
'xyzzy',NULL);
|
||||
} {{CREATE TABLE t1(a REFERENCES "(NULL)")}}
|
||||
do_execsql_test alter-17.9 {
|
||||
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
|
||||
NULL, 'lmnop');
|
||||
} {{}}
|
||||
do_execsql_test alter-17.10 {
|
||||
SELECT sqlite_rename_parent(NULL,'abc','xyz');
|
||||
} {{}}
|
||||
|
||||
finish_test
|
||||
|
||||
+30
-12
@@ -103,12 +103,21 @@ do_test analyze3-1.1.1 {
|
||||
}
|
||||
} {1}
|
||||
|
||||
do_execsql_test analyze3-1.1.x {
|
||||
SELECT count(*) FROM t1 WHERE x>200 AND x<300;
|
||||
SELECT count(*) FROM t1 WHERE x>0 AND x<1100;
|
||||
} {99 1000}
|
||||
|
||||
# The first of the following two SELECT statements visits 99 rows. So
|
||||
# it is better to use the index. But the second visits every row in
|
||||
# the table (1000 in total) so it is better to do a full-table scan.
|
||||
#
|
||||
do_eqp_test analyze3-1.1.2 {
|
||||
SELECT sum(y) FROM t1 WHERE x>200 AND x<300
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
|
||||
do_eqp_test analyze3-1.1.3 {
|
||||
SELECT sum(y) FROM t1 WHERE x>0 AND x<1100
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
|
||||
} {0 0 0 {SCAN TABLE t1}}
|
||||
|
||||
do_test analyze3-1.1.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 }
|
||||
@@ -125,17 +134,17 @@ do_test analyze3-1.1.6 {
|
||||
} {199 0 14850}
|
||||
do_test analyze3-1.1.7 {
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
do_test analyze3-1.1.8 {
|
||||
set l [string range "0" 0 end]
|
||||
set u [string range "1100" 0 end]
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
do_test analyze3-1.1.9 {
|
||||
set l [expr int(0)]
|
||||
set u [expr int(1100)]
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
|
||||
|
||||
# The following tests are similar to the block above. The difference is
|
||||
@@ -152,12 +161,17 @@ do_test analyze3-1.2.1 {
|
||||
ANALYZE;
|
||||
}
|
||||
} {}
|
||||
do_execsql_test analyze3-2.1.x {
|
||||
SELECT count(*) FROM t2 WHERE x>1 AND x<2;
|
||||
SELECT count(*) FROM t2 WHERE x>0 AND x<99;
|
||||
} {200 990}
|
||||
do_eqp_test analyze3-1.2.2 {
|
||||
SELECT sum(y) FROM t2 WHERE x>1 AND x<2
|
||||
} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}}
|
||||
do_eqp_test analyze3-1.2.3 {
|
||||
SELECT sum(y) FROM t2 WHERE x>0 AND x<99
|
||||
} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}}
|
||||
} {0 0 0 {SCAN TABLE t2}}
|
||||
|
||||
do_test analyze3-1.2.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 }
|
||||
} {161 0 4760}
|
||||
@@ -173,17 +187,17 @@ do_test analyze3-1.2.6 {
|
||||
} {161 0 integer integer 4760}
|
||||
do_test analyze3-1.2.7 {
|
||||
sf_execsql { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 }
|
||||
} {1981 0 490555}
|
||||
} {999 999 490555}
|
||||
do_test analyze3-1.2.8 {
|
||||
set l [string range "0" 0 end]
|
||||
set u [string range "99" 0 end]
|
||||
sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u}
|
||||
} {1981 0 text text 490555}
|
||||
} {999 999 text text 490555}
|
||||
do_test analyze3-1.2.9 {
|
||||
set l [expr int(0)]
|
||||
set u [expr int(99)]
|
||||
sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u}
|
||||
} {1981 0 integer integer 490555}
|
||||
} {999 999 integer integer 490555}
|
||||
|
||||
# Same tests a third time. This time, column x has INTEGER affinity and
|
||||
# is not the leftmost column of the table. This triggered a bug causing
|
||||
@@ -199,12 +213,16 @@ do_test analyze3-1.3.1 {
|
||||
ANALYZE;
|
||||
}
|
||||
} {}
|
||||
do_execsql_test analyze3-1.3.x {
|
||||
SELECT count(*) FROM t3 WHERE x>200 AND x<300;
|
||||
SELECT count(*) FROM t3 WHERE x>0 AND x<1100
|
||||
} {99 1000}
|
||||
do_eqp_test analyze3-1.3.2 {
|
||||
SELECT sum(y) FROM t3 WHERE x>200 AND x<300
|
||||
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}}
|
||||
do_eqp_test analyze3-1.3.3 {
|
||||
SELECT sum(y) FROM t3 WHERE x>0 AND x<1100
|
||||
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}}
|
||||
} {0 0 0 {SCAN TABLE t3}}
|
||||
|
||||
do_test analyze3-1.3.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 }
|
||||
@@ -221,17 +239,17 @@ do_test analyze3-1.3.6 {
|
||||
} {199 0 14850}
|
||||
do_test analyze3-1.3.7 {
|
||||
sf_execsql { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
do_test analyze3-1.3.8 {
|
||||
set l [string range "0" 0 end]
|
||||
set u [string range "1100" 0 end]
|
||||
sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
do_test analyze3-1.3.9 {
|
||||
set l [expr int(0)]
|
||||
set u [expr int(1100)]
|
||||
sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u }
|
||||
} {2000 0 499500}
|
||||
} {999 999 499500}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that the values of bound SQL variables may be used for the LIKE
|
||||
|
||||
+5
-5
@@ -566,7 +566,7 @@ foreach {tn schema} {
|
||||
drop_all_tables
|
||||
do_test 13.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE TABLE t1(a, b, c, d);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(b, c);
|
||||
}
|
||||
@@ -577,16 +577,16 @@ do_test 13.1 {
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
do_eqp_test 13.2.1 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<20
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<12
|
||||
} {/SEARCH TABLE t1 USING INDEX i1/}
|
||||
do_eqp_test 13.2.2 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<20
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<12
|
||||
} {/SEARCH TABLE t1 USING INDEX i1/}
|
||||
do_eqp_test 13.3.1 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<20
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<12
|
||||
} {/SEARCH TABLE t1 USING INDEX i2/}
|
||||
do_eqp_test 13.3.2 {
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<20
|
||||
SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<12
|
||||
} {/SEARCH TABLE t1 USING INDEX i2/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -97,6 +97,8 @@ do_test autoindex1-210 {
|
||||
PRAGMA automatic_index=ON;
|
||||
ANALYZE;
|
||||
UPDATE sqlite_stat1 SET stat='10000' WHERE tbl='t1';
|
||||
-- Table t2 actually contains 8 rows.
|
||||
UPDATE sqlite_stat1 SET stat='16' WHERE tbl='t2';
|
||||
ANALYZE sqlite_master;
|
||||
SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix capi3
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
@@ -1221,6 +1222,23 @@ do_test capi3-19.1 {
|
||||
sqlite3_prepare_tkt3134 db
|
||||
} {}
|
||||
|
||||
# Test that calling sqlite3_column_blob() on a TEXT value does not change
|
||||
# the return type of subsequent calls to sqlite3_column_type().
|
||||
#
|
||||
do_execsql_test 20.1 {
|
||||
CREATE TABLE t4(x);
|
||||
INSERT INTO t4 VALUES('abcdefghij');
|
||||
}
|
||||
do_test 20.2 {
|
||||
set stmt [sqlite3_prepare db "SELECT * FROM t4" -1 dummy]
|
||||
sqlite3_step $stmt
|
||||
} {SQLITE_ROW}
|
||||
do_test 20.3 { sqlite3_column_type $stmt 0 } {TEXT}
|
||||
do_test 20.4 { sqlite3_column_blob $stmt 0 } {abcdefghij}
|
||||
do_test 20.5 { sqlite3_column_type $stmt 0 } {TEXT}
|
||||
do_test 20.6 { sqlite3_finalize $stmt } SQLITE_OK
|
||||
|
||||
|
||||
# Tests of the interface when no VFS is registered.
|
||||
#
|
||||
if {![info exists tester_do_binarylog]} {
|
||||
|
||||
+3
-8
@@ -47,12 +47,12 @@ do_test 1.2 {
|
||||
catchsql {
|
||||
SELECT c FROM t1 WHERE a>'abc';
|
||||
}
|
||||
} {0 {}}
|
||||
} {1 {database disk image is malformed}}
|
||||
do_test 1.3 {
|
||||
catchsql {
|
||||
PRAGMA integrity_check
|
||||
}
|
||||
} {0 ok}
|
||||
} {1 {database disk image is malformed}}
|
||||
do_test 1.4 {
|
||||
catchsql {
|
||||
SELECT c FROM t1 ORDER BY a;
|
||||
@@ -71,11 +71,6 @@ do_test 2.1 {
|
||||
catchsql {
|
||||
SELECT rowid FROM t1 WHERE a='abc' and b='xyz123456789XYZ';
|
||||
}
|
||||
# The following test result is brittle. The point above is to try to
|
||||
# force a buffer overread by a corrupt database file. If we get an
|
||||
# incorrect answer from a corrupt database file, that is OK. If the
|
||||
# result below changes, that just means that "undefined behavior" has
|
||||
# changed.
|
||||
} {/0 .*/}
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
finish_test
|
||||
|
||||
+13
-11
@@ -20,6 +20,18 @@ set testprefix corruptH
|
||||
do_not_use_codec
|
||||
database_may_be_corrupt
|
||||
|
||||
# The corruption migrations tested by the code in this file are not detected
|
||||
# mmap mode.
|
||||
#
|
||||
# The reason is that in mmap mode, the different queries may use different
|
||||
# PgHdr objects for the same page (same data, but different PgHdr container
|
||||
# objects). And so the corruption is not detected.
|
||||
#
|
||||
if {[permutation]=="mmap"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Initialize the database.
|
||||
#
|
||||
do_execsql_test 1.1 {
|
||||
@@ -52,6 +64,7 @@ do_test 1.2 {
|
||||
} {}
|
||||
|
||||
do_test 1.3 {
|
||||
breakpoint
|
||||
db eval { PRAGMA secure_delete=1 }
|
||||
list [catch {
|
||||
db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
|
||||
@@ -97,9 +110,6 @@ do_test 2.2 {
|
||||
} {}
|
||||
|
||||
|
||||
# The corruption migration caused by the test case below does not
|
||||
# cause corruption to be detected in mmap mode.
|
||||
#
|
||||
# The trick here is that the root page of the tree scanned by the outer
|
||||
# query is also currently on the free-list. So while the first seek on
|
||||
# the table (for a==1) works, by the time the second is attempted The
|
||||
@@ -109,15 +119,7 @@ do_test 2.2 {
|
||||
# the cursor (as it is now marked with PgHdr.intKey==0) and returns
|
||||
# SQLITE_CORRUPT.
|
||||
#
|
||||
# However, in mmap mode, the outer query and the inner queries use
|
||||
# different PgHdr objects (same data, but different PgHdr container
|
||||
# objects). And so the corruption is not detected. Instead, the second
|
||||
# seek fails to find anything and only a single row is returned.
|
||||
#
|
||||
set res23 {1 {database disk image is malformed}}
|
||||
if {[permutation]=="mmap"} {
|
||||
set res23 {0 one}
|
||||
}
|
||||
do_test 2.3 {
|
||||
list [catch {
|
||||
set res [list]
|
||||
|
||||
+37
-5
@@ -14,6 +14,11 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix corruptI
|
||||
|
||||
if {[permutation]=="mmap"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
@@ -27,21 +32,48 @@ do_execsql_test 1.1 {
|
||||
PRAGMA auto_vacuum=0;
|
||||
CREATE TABLE t1(a);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
INSERT INTO t1 VALUES('a');
|
||||
INSERT INTO t1 VALUES('abcdefghijklmnop');
|
||||
} {}
|
||||
db close
|
||||
|
||||
do_test 1.2 {
|
||||
set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]]
|
||||
set off [expr 2*1024 + $offset + 1]
|
||||
hexio_write test.db $off FF06
|
||||
|
||||
breakpoint
|
||||
hexio_write test.db $off 7f06
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM t1 WHERE a = 10 }
|
||||
} {0 {}}
|
||||
|
||||
do_test 1.3 {
|
||||
db close
|
||||
set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]]
|
||||
set off [expr 2*1024 + $offset + 1]
|
||||
hexio_write test.db $off FFFF7f02
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM t1 WHERE a = 10 }
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
do_test 2.0 {
|
||||
execsql {
|
||||
CREATE TABLE r(x);
|
||||
INSERT INTO r VALUES('ABCDEFGHIJK');
|
||||
CREATE INDEX r1 ON r(x);
|
||||
}
|
||||
set pg [db one {SELECT rootpage FROM sqlite_master WHERE name = 'r1'}]
|
||||
} {5}
|
||||
|
||||
do_test 2.1 {
|
||||
db close
|
||||
set offset [hexio_get_int [hexio_read test.db [expr (5-1)*1024 + 8] 2]]
|
||||
set off [expr (5-1)*1024 + $offset + 1]
|
||||
hexio_write test.db $off FFFF0004
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM r WHERE x >= 10.0 }
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
do_test 2.2 {
|
||||
catchsql { SELECT * FROM r WHERE x >= 10 }
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
# 2014-04-26
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix cost
|
||||
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t3(id INTEGER PRIMARY KEY, b NOT NULL);
|
||||
CREATE TABLE t4(c, d, e);
|
||||
CREATE UNIQUE INDEX i3 ON t3(b);
|
||||
CREATE UNIQUE INDEX i4 ON t4(c, d);
|
||||
}
|
||||
do_eqp_test 1.2 {
|
||||
SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t3 USING COVERING INDEX i3}
|
||||
0 1 1 {SEARCH TABLE t4 USING INDEX i4 (c=?)}
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
}
|
||||
|
||||
# It is better to use an index for ORDER BY than sort externally, even
|
||||
# if the index is a non-covering index.
|
||||
do_eqp_test 2.2 {
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1 USING INDEX i1}
|
||||
}
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
|
||||
CREATE INDEX t5b ON t5(b);
|
||||
CREATE INDEX t5c ON t5(c);
|
||||
CREATE INDEX t5d ON t5(d);
|
||||
CREATE INDEX t5e ON t5(e);
|
||||
CREATE INDEX t5f ON t5(f);
|
||||
CREATE INDEX t5g ON t5(g);
|
||||
}
|
||||
|
||||
do_eqp_test 3.2 {
|
||||
SELECT a FROM t5
|
||||
WHERE b IS NULL OR c IS NULL OR d IS NULL
|
||||
ORDER BY a;
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t5 USING INDEX t5b (b=?)}
|
||||
0 0 0 {SEARCH TABLE t5 USING INDEX t5c (c=?)}
|
||||
0 0 0 {SEARCH TABLE t5 USING INDEX t5d (d=?)}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# If there is no likelihood() or stat3 data, SQLite assumes that a closed
|
||||
# range scan (e.g. one constrained by "col BETWEEN ? AND ?" constraint)
|
||||
# visits 1/64 of the rows in a table.
|
||||
#
|
||||
# Note: 1/63 =~ 0.016
|
||||
# Note: 1/65 =~ 0.015
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(b);
|
||||
}
|
||||
do_eqp_test 4.2 {
|
||||
SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?;
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
|
||||
}
|
||||
do_eqp_test 4.3 {
|
||||
SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?;
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b>? AND b<?)}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.1 {
|
||||
CREATE TABLE t2(x, y);
|
||||
CREATE INDEX t2i1 ON t2(x);
|
||||
}
|
||||
|
||||
do_eqp_test 5.2 {
|
||||
SELECT * FROM t2 ORDER BY x, y;
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
0 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
}
|
||||
|
||||
do_eqp_test 5.3 {
|
||||
SELECT * FROM t2 WHERE x BETWEEN ? AND ? ORDER BY rowid;
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t2 USING INDEX t2i1 (x>? AND x<?)}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
# where7.test, where8.test:
|
||||
#
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c);
|
||||
CREATE INDEX t3i1 ON t3(b);
|
||||
CREATE INDEX t3i2 ON t3(c);
|
||||
}
|
||||
|
||||
do_eqp_test 6.2 {
|
||||
SELECT a FROM t3 WHERE (b BETWEEN 2 AND 4) OR c=100 ORDER BY a
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)}
|
||||
0 0 0 {SEARCH TABLE t3 USING INDEX t3i2 (c=?)}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
CREATE INDEX t1c ON t1(c);
|
||||
CREATE INDEX t1d ON t1(d);
|
||||
CREATE INDEX t1e ON t1(e);
|
||||
CREATE INDEX t1f ON t1(f);
|
||||
CREATE INDEX t1g ON t1(g);
|
||||
}
|
||||
|
||||
do_eqp_test 7.2 {
|
||||
SELECT a FROM t1
|
||||
WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL)
|
||||
ORDER BY a
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
do_eqp_test 7.3 {
|
||||
SELECT rowid FROM t1
|
||||
WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL)
|
||||
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
|
||||
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
}
|
||||
|
||||
do_eqp_test 7.4 {
|
||||
SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.1 {
|
||||
CREATE TABLE composer(
|
||||
cid INTEGER PRIMARY KEY,
|
||||
cname TEXT
|
||||
);
|
||||
CREATE TABLE album(
|
||||
aid INTEGER PRIMARY KEY,
|
||||
aname TEXT
|
||||
);
|
||||
CREATE TABLE track(
|
||||
tid INTEGER PRIMARY KEY,
|
||||
cid INTEGER REFERENCES composer,
|
||||
aid INTEGER REFERENCES album,
|
||||
title TEXT
|
||||
);
|
||||
CREATE INDEX track_i1 ON track(cid);
|
||||
CREATE INDEX track_i2 ON track(aid);
|
||||
}
|
||||
|
||||
do_eqp_test 8.2 {
|
||||
SELECT DISTINCT aname
|
||||
FROM album, composer, track
|
||||
WHERE cname LIKE '%bach%'
|
||||
AND unlikely(composer.cid=track.cid)
|
||||
AND unlikely(album.aid=track.aid);
|
||||
} {
|
||||
0 0 2 {SCAN TABLE track}
|
||||
0 1 0 {SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
0 2 1 {SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 9.1 {
|
||||
CREATE TABLE t1(
|
||||
a,b,c,d,e, f,g,h,i,j,
|
||||
k,l,m,n,o, p,q,r,s,t
|
||||
);
|
||||
CREATE INDEX i1 ON t1(k,l,m,n,o,p,q,r,s,t);
|
||||
}
|
||||
do_test 9.2 {
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
execsql { INSERT INTO t1 DEFAULT VALUES }
|
||||
}
|
||||
execsql {
|
||||
ANALYZE;
|
||||
CREATE INDEX i2 ON t1(a,b,c,d,e,f,g,h,i,j);
|
||||
}
|
||||
} {}
|
||||
|
||||
set L [list a=? b=? c=? d=? e=? f=? g=? h=? i=? j=?]
|
||||
foreach {tn nTerm nRow} {
|
||||
1 1 10
|
||||
2 2 9
|
||||
3 3 8
|
||||
4 4 7
|
||||
5 5 6
|
||||
6 6 5
|
||||
7 7 5
|
||||
8 8 5
|
||||
9 9 5
|
||||
10 10 5
|
||||
} {
|
||||
set w [join [lrange $L 0 [expr $nTerm-1]] " AND "]
|
||||
set p1 [expr ($nRow-1) / 100.0]
|
||||
set p2 [expr ($nRow+1) / 100.0]
|
||||
|
||||
set sql1 "SELECT * FROM t1 WHERE likelihood(k=?, $p1) AND $w"
|
||||
set sql2 "SELECT * FROM t1 WHERE likelihood(k=?, $p2) AND $w"
|
||||
|
||||
do_eqp_test 9.3.$tn.1 $sql1 {/INDEX i1/}
|
||||
do_eqp_test 9.3.$tn.2 $sql2 {/INDEX i2/}
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ do_execsql_test 2.0 {
|
||||
foreach {tn sql temptables res} {
|
||||
1 "a, b FROM t1" {} {A B a b}
|
||||
2 "b, a FROM t1" {} {B A b a}
|
||||
3 "a, b, c FROM t1" {hash} {a b c A B C}
|
||||
3 "a, b, c FROM t1" {hash} {A B C a b c}
|
||||
4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c}
|
||||
5 "b FROM t1 WHERE a = 'a'" {} {b}
|
||||
6 "b FROM t1 ORDER BY +b COLLATE binary" {btree hash} {B b}
|
||||
|
||||
@@ -884,9 +884,10 @@ do_execsql_test e_createtable-3.3.1 {
|
||||
);
|
||||
} {}
|
||||
|
||||
# EVIDENCE-OF: R-10288-43169 For the purposes of the DEFAULT clause, an
|
||||
# EVIDENCE-OF: R-36381-62919 For the purposes of the DEFAULT clause, an
|
||||
# expression is considered constant provided that it does not contain
|
||||
# any sub-queries or string constants enclosed in double quotes.
|
||||
# any sub-queries, column or table references, or string literals
|
||||
# enclosed in double-quotes instead of single-quotes.
|
||||
#
|
||||
do_createtable_tests 3.4.1 -error {
|
||||
default value of column [x] is not constant
|
||||
|
||||
+6
-5
@@ -135,9 +135,9 @@ reset_db
|
||||
#
|
||||
# This also tests that foreign key constraints are disabled by default.
|
||||
#
|
||||
# EVIDENCE-OF: R-59578-04990 Foreign key constraints are disabled by
|
||||
# EVIDENCE-OF: R-44261-39702 Foreign key constraints are disabled by
|
||||
# default (for backwards compatibility), so must be enabled separately
|
||||
# for each database connection separately.
|
||||
# for each database connection.
|
||||
#
|
||||
drop_all_tables
|
||||
do_test e_fkey-4.1 {
|
||||
@@ -163,9 +163,10 @@ do_test e_fkey-4.2 {
|
||||
} {world}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-15278-54456 The application can can also use a PRAGMA
|
||||
# EVIDENCE-OF: R-08013-37737 The application can also use a PRAGMA
|
||||
# foreign_keys statement to determine if foreign keys are currently
|
||||
# enabled.
|
||||
|
||||
#
|
||||
# This also tests the example code in section 2 of foreignkeys.in.
|
||||
#
|
||||
@@ -2990,8 +2991,8 @@ if {[clang_sanitize_address]==0} {
|
||||
# The setting of the recursive_triggers pragma does not affect foreign
|
||||
# key actions.
|
||||
#
|
||||
# EVIDENCE-OF: R-51769-32730 The PRAGMA recursive_triggers setting does
|
||||
# not not affect the operation of foreign key actions.
|
||||
# EVIDENCE-OF: R-44355-00270 The PRAGMA recursive_triggers setting does
|
||||
# not affect the operation of foreign key actions.
|
||||
#
|
||||
foreach recursive_triggers_setting [list 0 1 ON OFF] {
|
||||
drop_all_tables
|
||||
|
||||
+6
-6
@@ -312,8 +312,8 @@ do_eqp_test 4.2.3 {
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)}
|
||||
}
|
||||
do_eqp_test 4.2.4 {
|
||||
@@ -321,8 +321,8 @@ do_eqp_test 4.2.4 {
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)}
|
||||
}
|
||||
do_eqp_test 4.2.5 {
|
||||
@@ -330,8 +330,8 @@ do_eqp_test 4.2.5 {
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t1}
|
||||
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2}
|
||||
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,4 +219,32 @@ do_execsql_test 5.2 {
|
||||
SELECT count(*) FROM sqlite_master WHERE name LIKE 't8%';
|
||||
} {0 6}
|
||||
|
||||
# At one point this was causing a memory leak.
|
||||
#
|
||||
foreach {tn sql} {
|
||||
1 {}
|
||||
2 { INSERT INTO ft(ft) VALUES('merge=2,2'); }
|
||||
} {
|
||||
reset_db
|
||||
do_execsql_test 6.$tn.1 "
|
||||
CREATE TABLE t1(x);
|
||||
CREATE VIRTUAL TABLE ft USING fts3;
|
||||
INSERT INTO ft VALUES('hello world');
|
||||
$sql
|
||||
"
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 6.$tn.2 { SELECT * FROM t1 } {}
|
||||
|
||||
do_test 6.$tn.3 {
|
||||
sqlite3 db2 test.db
|
||||
db2 eval { DROP TABLE t1 }
|
||||
db2 close
|
||||
set stmt [sqlite3_prepare db { SELECT * FROM ft } -1 dummy]
|
||||
sqlite3_finalize $stmt
|
||||
} {SQLITE_OK}
|
||||
db close
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -354,6 +354,17 @@ do_test fts3d-6.5 {
|
||||
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
|
||||
}
|
||||
} {xyz_content xyz_segdir xyz_segments}
|
||||
|
||||
# ALTER TABLE RENAME on an FTS3 table following an incr-merge op.
|
||||
#
|
||||
do_test fts3d-6.6 {
|
||||
execsql { INSERT INTO xyz(xyz) VALUES('merge=2,2') }
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
ALTER TABLE xyz RENAME TO ott;
|
||||
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
|
||||
}
|
||||
} {ott_content ott_segdir ott_segments ott_stat}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+12
-5
@@ -1301,11 +1301,13 @@ do_test func-29.3 {
|
||||
db eval {SELECT typeof(+x) FROM t29 ORDER BY id}
|
||||
} {integer null real blob text}
|
||||
if {[permutation] != "mmap"} {
|
||||
do_test func-29.4 {
|
||||
set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1]
|
||||
if {$x>100} {set x many}
|
||||
set x
|
||||
} {many}
|
||||
ifcapable !direct_read {
|
||||
do_test func-29.4 {
|
||||
set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1]
|
||||
if {$x>100} {set x many}
|
||||
set x
|
||||
} {many}
|
||||
}
|
||||
}
|
||||
do_test func-29.5 {
|
||||
db close
|
||||
@@ -1361,4 +1363,9 @@ for {set i 65536} {$i<=0x10ffff} {incr i 139} {
|
||||
do_execsql_test func-30.5.$i {SELECT unicode(char($i))} $i
|
||||
}
|
||||
|
||||
# Test char().
|
||||
#
|
||||
do_execsql_test func-31.1 {
|
||||
SELECT char(), length(char()), typeof(char())
|
||||
} {{} 0 text}
|
||||
finish_test
|
||||
|
||||
+177
@@ -159,4 +159,181 @@ do_test in4-3.12 {
|
||||
execsql { SELECT * FROM t3 WHERE x IN (1, 2) AND y IN ()}
|
||||
} {}
|
||||
|
||||
# Tests for "... IN (?)" and "... NOT IN (?)". In other words, tests
|
||||
# for when the RHS of IN is a single expression. This should work the
|
||||
# same as the == and <> operators.
|
||||
#
|
||||
do_execsql_test in4-3.21 {
|
||||
SELECT * FROM t3 WHERE x=10 AND y IN (10);
|
||||
} {10 10 10}
|
||||
do_execsql_test in4-3.22 {
|
||||
SELECT * FROM t3 WHERE x IN (10) AND y=10;
|
||||
} {10 10 10}
|
||||
do_execsql_test in4-3.23 {
|
||||
SELECT * FROM t3 WHERE x IN (10) AND y IN (10);
|
||||
} {10 10 10}
|
||||
do_execsql_test in4-3.24 {
|
||||
SELECT * FROM t3 WHERE x=1 AND y NOT IN (10);
|
||||
} {1 1 1}
|
||||
do_execsql_test in4-3.25 {
|
||||
SELECT * FROM t3 WHERE x NOT IN (10) AND y=1;
|
||||
} {1 1 1}
|
||||
do_execsql_test in4-3.26 {
|
||||
SELECT * FROM t3 WHERE x NOT IN (10) AND y NOT IN (10);
|
||||
} {1 1 1}
|
||||
|
||||
# The query planner recognizes that "x IN (?)" only generates a
|
||||
# single match and can use this information to optimize-out ORDER BY
|
||||
# clauses.
|
||||
#
|
||||
do_execsql_test in4-3.31 {
|
||||
DROP INDEX t3i1;
|
||||
CREATE UNIQUE INDEX t3xy ON t3(x,y);
|
||||
|
||||
SELECT *, '|' FROM t3 A, t3 B
|
||||
WHERE A.x=10 AND A.y IN (10)
|
||||
AND B.x=1 AND B.y IN (1);
|
||||
} {10 10 10 1 1 1 |}
|
||||
do_execsql_test in4-3.32 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT *, '|' FROM t3 A, t3 B
|
||||
WHERE A.x=10 AND A.y IN (10)
|
||||
AND B.x=1 AND B.y IN (1);
|
||||
} {~/B-TREE/} ;# No separate sorting pass
|
||||
do_execsql_test in4-3.33 {
|
||||
SELECT *, '|' FROM t3 A, t3 B
|
||||
WHERE A.x IN (10) AND A.y=10
|
||||
AND B.x IN (1) AND B.y=1;
|
||||
} {10 10 10 1 1 1 |}
|
||||
do_execsql_test in4-3.34 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT *, '|' FROM t3 A, t3 B
|
||||
WHERE A.x IN (10) AND A.y=10
|
||||
AND B.x IN (1) AND B.y=1;
|
||||
} {~/B-TREE/} ;# No separate sorting pass
|
||||
|
||||
# An expression of the form "x IN (?,?)" creates an ephemeral table to
|
||||
# hold the list of values on the RHS. But "x IN (?)" does not create
|
||||
# an ephemeral table.
|
||||
#
|
||||
do_execsql_test in4-3.41 {
|
||||
SELECT * FROM t3 WHERE x IN (10,11);
|
||||
} {10 10 10}
|
||||
do_execsql_test in4-3.42 {
|
||||
EXPLAIN
|
||||
SELECT * FROM t3 WHERE x IN (10,11);
|
||||
} {/OpenEphemeral/}
|
||||
do_execsql_test in4-3.43 {
|
||||
SELECT * FROM t3 WHERE x IN (10);
|
||||
} {10 10 10}
|
||||
do_execsql_test in4-3.44 {
|
||||
EXPLAIN
|
||||
SELECT * FROM t3 WHERE x IN (10);
|
||||
} {~/OpenEphemeral/}
|
||||
do_execsql_test in4-3.45 {
|
||||
SELECT * FROM t3 WHERE x NOT IN (10,11);
|
||||
} {1 1 1}
|
||||
do_execsql_test in4-3.46 {
|
||||
EXPLAIN
|
||||
SELECT * FROM t3 WHERE x NOT IN (10,11);
|
||||
} {/OpenEphemeral/}
|
||||
do_execsql_test in4-3.47 {
|
||||
SELECT * FROM t3 WHERE x NOT IN (10);
|
||||
} {1 1 1}
|
||||
do_execsql_test in4-3.48 {
|
||||
EXPLAIN
|
||||
SELECT * FROM t3 WHERE x NOT IN (10);
|
||||
} {~/OpenEphemeral/}
|
||||
|
||||
# Make sure that when "x IN (?)" is converted into "x==?" that collating
|
||||
# sequence and affinity computations do not get messed up.
|
||||
#
|
||||
do_execsql_test in4-4.1 {
|
||||
CREATE TABLE t4a(a TEXT, b TEXT COLLATE nocase, c);
|
||||
INSERT INTO t4a VALUES('ABC','abc',1);
|
||||
INSERT INTO t4a VALUES('def','xyz',2);
|
||||
INSERT INTO t4a VALUES('ghi','ghi',3);
|
||||
SELECT c FROM t4a WHERE a=b ORDER BY c;
|
||||
} {3}
|
||||
do_execsql_test in4-4.2 {
|
||||
SELECT c FROM t4a WHERE b=a ORDER BY c;
|
||||
} {1 3}
|
||||
do_execsql_test in4-4.3 {
|
||||
SELECT c FROM t4a WHERE (a||'')=b ORDER BY c;
|
||||
} {1 3}
|
||||
do_execsql_test in4-4.4 {
|
||||
SELECT c FROM t4a WHERE (a||'')=(b||'') ORDER BY c;
|
||||
} {3}
|
||||
do_execsql_test in4-4.5 {
|
||||
SELECT c FROM t4a WHERE a IN (b) ORDER BY c;
|
||||
} {3}
|
||||
do_execsql_test in4-4.6 {
|
||||
SELECT c FROM t4a WHERE (a||'') IN (b) ORDER BY c;
|
||||
} {3}
|
||||
|
||||
|
||||
do_execsql_test in4-4.11 {
|
||||
CREATE TABLE t4b(a TEXT, b NUMERIC, c);
|
||||
INSERT INTO t4b VALUES('1.0',1,4);
|
||||
SELECT c FROM t4b WHERE a=b;
|
||||
} {4}
|
||||
do_execsql_test in4-4.12 {
|
||||
SELECT c FROM t4b WHERE b=a;
|
||||
} {4}
|
||||
do_execsql_test in4-4.13 {
|
||||
SELECT c FROM t4b WHERE +a=b;
|
||||
} {4}
|
||||
do_execsql_test in4-4.14 {
|
||||
SELECT c FROM t4b WHERE a=+b;
|
||||
} {}
|
||||
do_execsql_test in4-4.15 {
|
||||
SELECT c FROM t4b WHERE +b=a;
|
||||
} {}
|
||||
do_execsql_test in4-4.16 {
|
||||
SELECT c FROM t4b WHERE b=+a;
|
||||
} {4}
|
||||
do_execsql_test in4-4.17 {
|
||||
SELECT c FROM t4b WHERE a IN (b);
|
||||
} {}
|
||||
do_execsql_test in4-4.18 {
|
||||
SELECT c FROM t4b WHERE b IN (a);
|
||||
} {4}
|
||||
do_execsql_test in4-4.19 {
|
||||
SELECT c FROM t4b WHERE +b IN (a);
|
||||
} {}
|
||||
|
||||
do_execsql_test in4-5.1 {
|
||||
CREATE TABLE t5(c INTEGER PRIMARY KEY, d TEXT COLLATE nocase);
|
||||
INSERT INTO t5 VALUES(17, 'fuzz');
|
||||
SELECT 1 FROM t5 WHERE 'fuzz' IN (d); -- match
|
||||
SELECT 2 FROM t5 WHERE 'FUZZ' IN (d); -- no match
|
||||
SELECT 3 FROM t5 WHERE d IN ('fuzz'); -- match
|
||||
SELECT 4 FROM t5 WHERE d IN ('FUZZ'); -- match
|
||||
} {1 3 4}
|
||||
|
||||
# An expression of the form "x IN (y)" can be used as "x=y" by the
|
||||
# query planner when computing transitive constraints or to run the
|
||||
# query using an index on y.
|
||||
#
|
||||
do_execsql_test in4-6.1 {
|
||||
CREATE TABLE t6a(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t6a VALUES(1,2),(3,4),(5,6);
|
||||
CREATE TABLE t6b(c INTEGER PRIMARY KEY, d);
|
||||
INSERT INTO t6b VALUES(4,44),(5,55),(6,66);
|
||||
|
||||
SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c);
|
||||
} {3 4 4 44}
|
||||
do_execsql_test in4-6.1-eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c);
|
||||
} {~/SCAN/}
|
||||
do_execsql_test in4-6.2 {
|
||||
SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b);
|
||||
} {3 4 4 44}
|
||||
do_execsql_test in4-6.2-eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b);
|
||||
} {~/SCAN/}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+22
-2
@@ -145,11 +145,11 @@ do_test index6-2.1 {
|
||||
execsql {
|
||||
CREATE TABLE t2(a,b);
|
||||
INSERT INTO t2(a,b) SELECT value, value FROM nums WHERE value<1000;
|
||||
UPDATE t2 SET a=NULL WHERE b%5==0;
|
||||
UPDATE t2 SET a=NULL WHERE b%2==0;
|
||||
CREATE INDEX t2a1 ON t2(a) WHERE a IS NOT NULL;
|
||||
SELECT count(*) FROM t2 WHERE a IS NOT NULL;
|
||||
}
|
||||
} {800}
|
||||
} {500}
|
||||
do_test index6-2.2 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
@@ -157,6 +157,7 @@ do_test index6-2.2 {
|
||||
}
|
||||
} {/.* TABLE t2 USING INDEX t2a1 .*/}
|
||||
ifcapable stat4||stat3 {
|
||||
execsql ANALYZE
|
||||
do_test index6-2.3stat4 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
@@ -248,4 +249,23 @@ do_execsql_test index6-5.0 {
|
||||
SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b';
|
||||
} {6 6}
|
||||
|
||||
# Test case for ticket [2ea3e9fe6379fc3f6ce7e090ce483c1a3a80d6c9] from
|
||||
# 2014-04-13: Partial index causes assertion fault on UPDATE OR REPLACE.
|
||||
#
|
||||
do_execsql_test index6-6.0 {
|
||||
CREATE TABLE t6(a,b);
|
||||
CREATE UNIQUE INDEX t6ab ON t1(a,b);
|
||||
CREATE INDEX t6b ON t6(b) WHERE b=1;
|
||||
INSERT INTO t6(a,b) VALUES(123,456);
|
||||
SELECT * FROM t6;
|
||||
} {123 456}
|
||||
do_execsql_test index6-6.1 {
|
||||
UPDATE OR REPLACE t6 SET b=789;
|
||||
SELECT * FROM t6;
|
||||
} {123 789}
|
||||
do_execsql_test index6-6.2 {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -641,4 +641,39 @@ do_test join-11.10 {
|
||||
execsql { SELECT * FROM t2 NATURAL JOIN t1 }
|
||||
} {1 one 2 two}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that at most 64 tables are allowed in a join.
|
||||
#
|
||||
do_execsql_test join-12.1 {
|
||||
CREATE TABLE t14(x);
|
||||
INSERT INTO t14 VALUES('abcdefghij');
|
||||
}
|
||||
|
||||
proc jointest {tn nTbl res} {
|
||||
set sql "SELECT 1 FROM [string repeat t14, [expr $nTbl-1]] t14;"
|
||||
uplevel [list do_catchsql_test $tn $sql $res]
|
||||
}
|
||||
|
||||
jointest join-12.2 30 {0 1}
|
||||
jointest join-12.3 63 {0 1}
|
||||
jointest join-12.4 64 {0 1}
|
||||
jointest join-12.5 65 {1 {at most 64 tables in a join}}
|
||||
jointest join-12.6 66 {1 {at most 64 tables in a join}}
|
||||
jointest join-12.7 127 {1 {at most 64 tables in a join}}
|
||||
jointest join-12.8 128 {1 {at most 64 tables in a join}}
|
||||
jointest join-12.9 1000 {1 {at most 64 tables in a join}}
|
||||
|
||||
# If SQLite is built with SQLITE_MEMDEBUG, then the huge number of realloc()
|
||||
# calls made by the following test cases are too time consuming to run.
|
||||
# Without SQLITE_MEMDEBUG, realloc() is fast enough that these are not
|
||||
# a problem.
|
||||
ifcapable pragma&&compileoption_diags {
|
||||
if {[lsearch [db eval {PRAGMA compile_options}] MEMDEBUG]<0} {
|
||||
jointest join-12.10 65534 {1 {at most 64 tables in a join}}
|
||||
jointest join-12.11 65535 {1 {too many references to "t14": max 65535}}
|
||||
jointest join-12.12 65536 {1 {too many references to "t14": max 65535}}
|
||||
jointest join-12.13 65537 {1 {too many references to "t14": max 65535}}
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -616,4 +616,24 @@ do_test limit-13.81 {
|
||||
db eval {SELECT z FROM v13c LIMIT 1 OFFSET 8}
|
||||
} {}
|
||||
|
||||
do_execsql_test limit-14.1 {
|
||||
SELECT 123 LIMIT 1 OFFSET 0
|
||||
} {123}
|
||||
do_execsql_test limit-14.2 {
|
||||
SELECT 123 LIMIT 1 OFFSET 1
|
||||
} {}
|
||||
do_execsql_test limit-14.3 {
|
||||
SELECT 123 LIMIT 0 OFFSET 0
|
||||
} {}
|
||||
do_execsql_test limit-14.4 {
|
||||
SELECT 123 LIMIT 0 OFFSET 1
|
||||
} {}
|
||||
do_execsql_test limit-14.6 {
|
||||
SELECT 123 LIMIT -1 OFFSET 0
|
||||
} {123}
|
||||
do_execsql_test limit-14.7 {
|
||||
SELECT 123 LIMIT -1 OFFSET 1
|
||||
} {}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -880,6 +880,48 @@ do_malloc_test 39 -tclprep {
|
||||
db close
|
||||
}
|
||||
|
||||
reset_db
|
||||
add_test_utf16bin_collate db
|
||||
do_execsql_test 40.1 {
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES('fghij');
|
||||
INSERT INTO t1 VALUES('pqrst');
|
||||
INSERT INTO t1 VALUES('abcde');
|
||||
INSERT INTO t1 VALUES('uvwxy');
|
||||
INSERT INTO t1 VALUES('klmno');
|
||||
}
|
||||
do_execsql_test 40.2 {
|
||||
SELECT * FROM t1 ORDER BY 1 COLLATE utf16bin;
|
||||
} {abcde fghij klmno pqrst uvwxy}
|
||||
do_faultsim_test 40.3 -faults oom-trans* -body {
|
||||
execsql {
|
||||
SELECT * FROM t1 ORDER BY 1 COLLATE utf16bin;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {abcde fghij klmno pqrst uvwxy}}
|
||||
faultsim_integrity_check
|
||||
}
|
||||
|
||||
reset_db
|
||||
add_test_utf16bin_collate db
|
||||
set big [string repeat x 200]
|
||||
do_execsql_test 41.1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a COLLATE utf16bin);
|
||||
INSERT INTO t1 VALUES('fghij' || $::big);
|
||||
INSERT INTO t1 VALUES('pqrst' || $::big);
|
||||
INSERT INTO t1 VALUES('abcde' || $::big);
|
||||
INSERT INTO t1 VALUES('uvwxy' || $::big);
|
||||
INSERT INTO t1 VALUES('klmno' || $::big);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
}
|
||||
do_faultsim_test 41.2 -faults oom* -body {
|
||||
execsql { SELECT * FROM t1 WHERE a = ('abcde' || $::big)}
|
||||
} -test {
|
||||
faultsim_test_result [list 0 "abcde$::big"]
|
||||
faultsim_integrity_check
|
||||
}
|
||||
|
||||
# Ensure that no file descriptors were leaked.
|
||||
do_test malloc-99.X {
|
||||
catch {db close}
|
||||
|
||||
+22
-1
@@ -25,7 +25,6 @@ if {!$MEMDEBUG} {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
# Construct a test database
|
||||
#
|
||||
forcedelete test.db.bu
|
||||
@@ -116,6 +115,28 @@ ifcapable stat3 {
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 7.0 {
|
||||
PRAGMA cache_size = 5;
|
||||
}
|
||||
do_faultsim_test 7 -faults oom-trans* -prep {
|
||||
if {$iFail < 500} { set iFail 2000 }
|
||||
if {$iFail > 1215} { set iFail 2000 }
|
||||
} -body {
|
||||
execsql {
|
||||
WITH r(x,y) AS (
|
||||
SELECT 1, randomblob(100)
|
||||
UNION ALL
|
||||
SELECT x+1, randomblob(100) FROM r
|
||||
LIMIT 1000
|
||||
)
|
||||
SELECT count(x), length(y) FROM r GROUP BY (x%5)
|
||||
}
|
||||
} -test {
|
||||
set res [list 200 100 200 100 200 100 200 100 200 100]
|
||||
faultsim_test_result [list 0 $res]
|
||||
}
|
||||
|
||||
|
||||
# Ensure that no file descriptors were leaked.
|
||||
do_test malloc-99.X {
|
||||
catch {db close}
|
||||
|
||||
+20
-2
@@ -64,10 +64,28 @@ do_execsql_test 1.7 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT DISTINCT c, b, a FROM t1 WHERE +a=0;
|
||||
} {/B-TREE/}
|
||||
do_execsql_test 2.1 {
|
||||
|
||||
# In some cases, it is faster to do repeated index lookups than it is to
|
||||
# sort. But in other cases, it is faster to sort than to do repeated index
|
||||
# lookups.
|
||||
#
|
||||
do_execsql_test 2.1a {
|
||||
CREATE TABLE t2(a,b,c);
|
||||
CREATE INDEX t2bc ON t2(b,c);
|
||||
ANALYZE;
|
||||
INSERT INTO sqlite_stat1 VALUES('t1','t1bc','1000000 10 9');
|
||||
INSERT INTO sqlite_stat1 VALUES('t2','t2bc','100 10 5');
|
||||
ANALYZE sqlite_master;
|
||||
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t1 WHERE a=0 ORDER BY a, b, c;
|
||||
SELECT * FROM t2 WHERE a=0 ORDER BY a, b, c;
|
||||
} {~/B-TREE/}
|
||||
|
||||
do_execsql_test 2.1b {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t1 WHERE likelihood(a=0, 0.05) ORDER BY a, b, c;
|
||||
} {/B-TREE/}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t1 WHERE +a=0 ORDER BY a, b, c;
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
# 2014-03-21
|
||||
#
|
||||
# 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. The
|
||||
# focus of this file is testing that the block-sort optimization.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix orderby6
|
||||
|
||||
# Run all tests twice. Once with a normal table and a second time
|
||||
# with a WITHOUT ROWID table
|
||||
#
|
||||
foreach {tn rowidclause} {1 {} 2 {WITHOUT ROWID}} {
|
||||
|
||||
# Construct a table with 1000 rows and a split primary key
|
||||
#
|
||||
reset_db
|
||||
do_test $tn.1 {
|
||||
db eval "CREATE TABLE t1(a,b,c,PRIMARY KEY(b,c)) $rowidclause;"
|
||||
db eval {
|
||||
WITH RECURSIVE
|
||||
cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<1000)
|
||||
INSERT INTO t1 SELECT x, x%40, x/40 FROM cnt;
|
||||
}
|
||||
} {}
|
||||
|
||||
# Run various ORDER BY queries that can benefit from block-sort.
|
||||
# Compare the output to the same output using a full-sort enforced
|
||||
# by adding + to each term of the ORDER BY clause.
|
||||
#
|
||||
do_execsql_test $tn.2 {
|
||||
SELECT b,a,c FROM t1 ORDER BY b,a,c;
|
||||
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b,+a,+c}]
|
||||
do_execsql_test $tn.3 {
|
||||
SELECT b,a,c FROM t1 ORDER BY b,c DESC,a;
|
||||
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b,+c DESC,+a}]
|
||||
do_execsql_test $tn.4 {
|
||||
SELECT b,a,c FROM t1 ORDER BY b DESC,c,a;
|
||||
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b DESC,+c,+a}]
|
||||
do_execsql_test $tn.5 {
|
||||
SELECT b,a,c FROM t1 ORDER BY b DESC,a,c;
|
||||
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b DESC,+a,+c}]
|
||||
|
||||
# LIMIT and OFFSET clauses on block-sort queries.
|
||||
#
|
||||
do_execsql_test $tn.11 {
|
||||
SELECT a FROM t1 ORDER BY b, a LIMIT 10 OFFSET 20;
|
||||
} {840 880 920 960 1000 1 41 81 121 161}
|
||||
do_execsql_test $tn.11x {
|
||||
SELECT a FROM t1 ORDER BY +b, a LIMIT 10 OFFSET 20;
|
||||
} {840 880 920 960 1000 1 41 81 121 161}
|
||||
|
||||
do_execsql_test $tn.12 {
|
||||
SELECT a FROM t1 ORDER BY b DESC, a LIMIT 10 OFFSET 20;
|
||||
} {839 879 919 959 999 38 78 118 158 198}
|
||||
do_execsql_test $tn.12 {
|
||||
SELECT a FROM t1 ORDER BY +b DESC, a LIMIT 10 OFFSET 20;
|
||||
} {839 879 919 959 999 38 78 118 158 198}
|
||||
|
||||
do_execsql_test $tn.13 {
|
||||
SELECT a FROM t1 ORDER BY b, a DESC LIMIT 10 OFFSET 45;
|
||||
} {161 121 81 41 1 962 922 882 842 802}
|
||||
do_execsql_test $tn.13x {
|
||||
SELECT a FROM t1 ORDER BY +b, a DESC LIMIT 10 OFFSET 45;
|
||||
} {161 121 81 41 1 962 922 882 842 802}
|
||||
|
||||
do_execsql_test $tn.14 {
|
||||
SELECT a FROM t1 ORDER BY b DESC, a LIMIT 10 OFFSET 45;
|
||||
} {838 878 918 958 998 37 77 117 157 197}
|
||||
do_execsql_test $tn.14x {
|
||||
SELECT a FROM t1 ORDER BY +b DESC, a LIMIT 10 OFFSET 45;
|
||||
} {838 878 918 958 998 37 77 117 157 197}
|
||||
|
||||
# Many test cases where the LIMIT+OFFSET window is in various
|
||||
# alignments with block-sort boundaries.
|
||||
#
|
||||
foreach {tx limit offset orderby} {
|
||||
1 10 24 {+b,+a}
|
||||
2 10 25 {+b,+a}
|
||||
3 10 26 {+b,+a}
|
||||
4 10 39 {+b,+a}
|
||||
5 10 40 {+b,+a}
|
||||
6 10 41 {+b,+a}
|
||||
7 27 24 {+b,+a}
|
||||
8 27 49 {+b,+a}
|
||||
11 10 24 {+b DESC,+a}
|
||||
12 10 25 {+b DESC,+a}
|
||||
13 10 26 {+b DESC,+a}
|
||||
14 10 39 {+b DESC,+a}
|
||||
15 10 40 {+b DESC,+a}
|
||||
16 10 41 {+b DESC,+a}
|
||||
17 27 24 {+b DESC,+a}
|
||||
18 27 49 {+b DESC,+a}
|
||||
21 10 24 {+b,+a DESC}
|
||||
22 10 25 {+b,+a DESC}
|
||||
23 10 26 {+b,+a DESC}
|
||||
24 10 39 {+b,+a DESC}
|
||||
25 10 40 {+b,+a DESC}
|
||||
26 10 41 {+b,+a DESC}
|
||||
27 27 24 {+b,+a DESC}
|
||||
28 27 49 {+b,+a DESC}
|
||||
31 10 24 {+b DESC,+a DESC}
|
||||
32 10 25 {+b DESC,+a DESC}
|
||||
33 10 26 {+b DESC,+a DESC}
|
||||
34 10 39 {+b DESC,+a DESC}
|
||||
35 10 40 {+b DESC,+a DESC}
|
||||
36 10 41 {+b DESC,+a DESC}
|
||||
37 27 24 {+b DESC,+a DESC}
|
||||
38 27 49 {+b DESC,+a DESC}
|
||||
} {
|
||||
set sql1 "SELECT a FROM t1 ORDER BY $orderby LIMIT $limit OFFSET $offset;"
|
||||
set sql2 [string map {+ {}} $sql1]
|
||||
# puts $sql2\n$sql1\n[db eval $sql2]
|
||||
do_test $tn.21.$tx {db eval $::sql2} [db eval $sql1]
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# A second test table, t2, has many columns open to sorting.
|
||||
do_test $tn.31 {
|
||||
db eval "CREATE TABLE t2(a,b,c,d,e,f,PRIMARY KEY(b,c,d,e,f)) $rowidclause;"
|
||||
db eval {
|
||||
WITH RECURSIVE
|
||||
cnt(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM cnt WHERE x<242)
|
||||
INSERT INTO t2 SELECT x, x%3, (x/3)%3, (x/9)%3, (x/27)%3, (x/81)%3
|
||||
FROM cnt;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test $tn.32 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,e,f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||
do_execsql_test $tn.33 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,e,+f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||
do_execsql_test $tn.34 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,+e,+f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||
do_execsql_test $tn.35 {
|
||||
SELECT a FROM t2 ORDER BY b,c,+d,+e,+f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||
do_execsql_test $tn.36 {
|
||||
SELECT a FROM t2 ORDER BY b,+c,+d,+e,+f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
|
||||
|
||||
do_execsql_test $tn.37 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,e,f DESC;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f DESC;}]
|
||||
do_execsql_test $tn.38 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,e DESC,f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e DESC,+f;}]
|
||||
do_execsql_test $tn.39 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d DESC,e,f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d DESC,+e,+f;}]
|
||||
do_execsql_test $tn.40 {
|
||||
SELECT a FROM t2 ORDER BY b,c DESC,d,e,f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c DESC,+d,+e,+f;}]
|
||||
do_execsql_test $tn.41 {
|
||||
SELECT a FROM t2 ORDER BY b DESC,c,d,e,f;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b DESC,+c,+d,+e,+f;}]
|
||||
|
||||
do_execsql_test $tn.42 {
|
||||
SELECT a FROM t2 ORDER BY b DESC,c DESC,d,e,f LIMIT 31;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b DESC,+c DESC,+d,+e,+f LIMIT 31}]
|
||||
do_execsql_test $tn.43 {
|
||||
SELECT a FROM t2 ORDER BY b,c,d,e,f DESC LIMIT 8 OFFSET 7;
|
||||
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f DESC LIMIT 8 OFFSET 7}]
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,106 @@
|
||||
# 2014-04-25
|
||||
#
|
||||
# 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. The
|
||||
# focus of this file is testing ORDER BY optimizations on joins
|
||||
# that involve virtual tables.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix orderby7
|
||||
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE fts USING fts3(content TEXT);
|
||||
INSERT INTO fts(rowid,content)
|
||||
VALUES(1,'this is a test of the fts3 virtual'),
|
||||
(2,'table used as part of a join together'),
|
||||
(3,'with the DISTINCT keyword. There was'),
|
||||
(4,'a bug at one time (2013-06 through 2014-04)'),
|
||||
(5,'that prevented this from working correctly.'),
|
||||
(11,'a row that occurs twice'),
|
||||
(12,'a row that occurs twice');
|
||||
|
||||
CREATE TABLE t1(x TEXT PRIMARY KEY, y);
|
||||
INSERT OR IGNORE INTO t1 SELECT content, rowid+100 FROM fts;
|
||||
} {}
|
||||
do_execsql_test 1.1 {
|
||||
SELECT DISTINCT fts.rowid, t1.y
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x
|
||||
ORDER BY y;
|
||||
} {11 111 12 111}
|
||||
do_execsql_test 1.2 {
|
||||
SELECT DISTINCT fts.rowid, t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x
|
||||
ORDER BY 1;
|
||||
} {11 {a row that occurs twice} 12 {a row that occurs twice}}
|
||||
do_execsql_test 1.3 {
|
||||
SELECT DISTINCT t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x
|
||||
ORDER BY 1;
|
||||
} {{a row that occurs twice}}
|
||||
do_execsql_test 1.4 {
|
||||
SELECT t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x
|
||||
ORDER BY 1;
|
||||
} {{a row that occurs twice} {a row that occurs twice}}
|
||||
do_execsql_test 1.5 {
|
||||
SELECT DISTINCT t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x;
|
||||
} {{a row that occurs twice}}
|
||||
do_execsql_test 1.6 {
|
||||
SELECT t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts MATCH 'that twice'
|
||||
AND content=x;
|
||||
} {{a row that occurs twice} {a row that occurs twice}}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT DISTINCT t1.x
|
||||
FROM fts, t1
|
||||
WHERE fts.rowid=11
|
||||
AND content=x
|
||||
ORDER BY fts.rowid;
|
||||
} {{a row that occurs twice}}
|
||||
do_execsql_test 2.2 {
|
||||
SELECT DISTINCT t1.*
|
||||
FROM fts, t1
|
||||
WHERE fts.rowid=11
|
||||
AND content=x
|
||||
ORDER BY fts.rowid;
|
||||
} {{a row that occurs twice} 111}
|
||||
do_execsql_test 2.3 {
|
||||
SELECT DISTINCT t1.*
|
||||
FROM fts, t1
|
||||
WHERE fts.rowid=11
|
||||
AND content=x
|
||||
ORDER BY t1.y
|
||||
} {{a row that occurs twice} 111}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -112,6 +112,7 @@ set allquicktests [test_set $alltests -exclude {
|
||||
incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test
|
||||
vtab_err.test walslow.test walcrash.test walcrash3.test
|
||||
walthread.test rtree3.test indexfault.test securedel2.test
|
||||
sort3.test sort4.test
|
||||
}]
|
||||
if {[info exists ::env(QUICKTEST_INCLUDE)]} {
|
||||
set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)]
|
||||
@@ -331,6 +332,12 @@ test_suite "coverage-analyze" -description {
|
||||
analyze.test analyzeB.test mallocA.test
|
||||
}
|
||||
|
||||
test_suite "coverage-sorter" -description {
|
||||
Coverage tests for file vdbesort.c.
|
||||
} -files {
|
||||
sort.test sortfault.test
|
||||
}
|
||||
|
||||
|
||||
lappend ::testsuitelist xxx
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -462,7 +469,7 @@ test_suite "multithread" -description {
|
||||
} -files {
|
||||
delete.test delete2.test insert.test rollback.test select1.test
|
||||
select2.test trans.test update.test vacuum.test types.test
|
||||
types2.test types3.test
|
||||
types2.test types3.test sort4.test
|
||||
} -shutdown {
|
||||
catch {db close}
|
||||
sqlite3_shutdown
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix selectA
|
||||
|
||||
ifcapable !compound {
|
||||
finish_test
|
||||
@@ -1310,4 +1311,68 @@ do_execsql_test selectA-3.98 {
|
||||
SELECT n FROM xyz ORDER BY +n;
|
||||
} {MAD MAD+ MAD++}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# At one point the following code exposed a temp register reuse problem.
|
||||
#
|
||||
proc f {args} { return 1 }
|
||||
db func f f
|
||||
|
||||
do_execsql_test 4.1.1 {
|
||||
CREATE TABLE t4(a, b);
|
||||
CREATE TABLE t5(c, d);
|
||||
|
||||
INSERT INTO t5 VALUES(1, 'x');
|
||||
INSERT INTO t5 VALUES(2, 'x');
|
||||
INSERT INTO t4 VALUES(3, 'x');
|
||||
INSERT INTO t4 VALUES(4, 'x');
|
||||
|
||||
CREATE INDEX i1 ON t4(a);
|
||||
CREATE INDEX i2 ON t5(c);
|
||||
}
|
||||
|
||||
do_eqp_test 4.1.2 {
|
||||
SELECT c, d FROM t5
|
||||
UNION ALL
|
||||
SELECT a, b FROM t4 WHERE f()==f()
|
||||
ORDER BY 1,2
|
||||
} {
|
||||
1 0 0 {SCAN TABLE t5 USING INDEX i2}
|
||||
1 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
2 0 0 {SCAN TABLE t4 USING INDEX i1}
|
||||
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
|
||||
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)}
|
||||
}
|
||||
|
||||
do_execsql_test 4.1.3 {
|
||||
SELECT c, d FROM t5
|
||||
UNION ALL
|
||||
SELECT a, b FROM t4 WHERE f()==f()
|
||||
ORDER BY 1,2
|
||||
} {
|
||||
1 x 2 x 3 x 4 x
|
||||
}
|
||||
|
||||
do_execsql_test 4.2.1 {
|
||||
CREATE TABLE t6(a, b);
|
||||
CREATE TABLE t7(c, d);
|
||||
|
||||
INSERT INTO t7 VALUES(2, 9);
|
||||
INSERT INTO t6 VALUES(3, 0);
|
||||
INSERT INTO t6 VALUES(4, 1);
|
||||
INSERT INTO t7 VALUES(5, 6);
|
||||
INSERT INTO t6 VALUES(6, 0);
|
||||
INSERT INTO t7 VALUES(7, 6);
|
||||
|
||||
CREATE INDEX i6 ON t6(a);
|
||||
CREATE INDEX i7 ON t7(c);
|
||||
}
|
||||
|
||||
do_execsql_test 4.2.2 {
|
||||
SELECT c, f(d,c,d,c,d) FROM t7
|
||||
UNION ALL
|
||||
SELECT a, b FROM t6
|
||||
ORDER BY 1,2
|
||||
} {/2 . 3 . 4 . 5 . 6 . 7 ./}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/tclsh
|
||||
#
|
||||
# This script displays the field of rectangles used by --testset rtree
|
||||
# of speedtest1. Run this script as follows:
|
||||
#
|
||||
# rm test.db
|
||||
# ./speedtest1 --testset rtree --size 25 test.db
|
||||
# sqlite3 --separator ' ' test.db 'SELECT * FROM rt1' >data.txt
|
||||
# wish show_speedtest1_rtree.tcl
|
||||
#
|
||||
# The filename "data.txt" is hard coded into this script and so that name
|
||||
# must be used on lines 3 and 4 above. Elsewhere, different filenames can
|
||||
# be used. The --size N parameter can be adjusted as desired.
|
||||
#
|
||||
package require Tk
|
||||
set f [open data.txt rb]
|
||||
set data [read $f]
|
||||
close $f
|
||||
canvas .c
|
||||
frame .b
|
||||
button .b.b1 -text X-Y -command refill-xy
|
||||
button .b.b2 -text X-Z -command refill-xz
|
||||
button .b.b3 -text Y-Z -command refill-yz
|
||||
pack .b.b1 .b.b2 .b.b3 -side left
|
||||
pack .c -side top -fill both -expand 1
|
||||
pack .b -side top
|
||||
proc resize_canvas_to_fit {} {
|
||||
foreach {x0 y0 x1 y1} [.c bbox all] break
|
||||
set w [expr {$x1-$x0}]
|
||||
set h [expr {$y1-$y0}]
|
||||
.c config -width $w -height $h
|
||||
}
|
||||
proc refill-xy {} {
|
||||
.c delete all
|
||||
foreach {id x0 x1 y0 y1 z0 z1} $::data {
|
||||
.c create rectangle $x0 $y0 $x1 $y1
|
||||
}
|
||||
.c scale all 0 0 0.05 0.05
|
||||
resize_canvas_to_fit
|
||||
}
|
||||
proc refill-xz {} {
|
||||
.c delete all
|
||||
foreach {id x0 x1 y0 y1 z0 z1} $::data {
|
||||
.c create rectangle $x0 $z0 $x1 $z1
|
||||
}
|
||||
.c scale all 0 0 0.05 0.05
|
||||
resize_canvas_to_fit
|
||||
}
|
||||
proc refill-yz {} {
|
||||
.c delete all
|
||||
foreach {id x0 x1 y0 y1 z0 z1} $::data {
|
||||
.c create rectangle $y0 $z0 $y1 $z1
|
||||
}
|
||||
.c scale all 0 0 0.05 0.05
|
||||
resize_canvas_to_fit
|
||||
}
|
||||
refill-xy
|
||||
@@ -209,4 +209,42 @@ do_execsql_test skipscan1-4.1 {
|
||||
SELECT i FROM t4 WHERE h=8;
|
||||
} {9 9 9 9 9 9 9 9}
|
||||
|
||||
# Make sure skip-scan cost computation in the query planner takes into
|
||||
# account the fact that the seek must occur multiple times.
|
||||
#
|
||||
# Prior to 2014-03-10, the costs were computed incorrectly which would
|
||||
# cause index t5i2 to be used instead of t5i1 on the skipscan1-5.3.
|
||||
#
|
||||
do_execsql_test skipscan1-5.1 {
|
||||
CREATE TABLE t5(
|
||||
id INTEGER PRIMARY KEY,
|
||||
loc TEXT,
|
||||
lang INTEGER,
|
||||
utype INTEGER,
|
||||
xa INTEGER,
|
||||
xd INTEGER,
|
||||
xh INTEGER
|
||||
);
|
||||
CREATE INDEX t5i1 on t5(loc, xh, xa, utype, lang);
|
||||
CREATE INDEX t5i2 ON t5(xd,loc,utype,lang);
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N';
|
||||
} {/.*COVERING INDEX t5i1 .*/}
|
||||
do_execsql_test skipscan1-5.2 {
|
||||
ANALYZE;
|
||||
DELETE FROM sqlite_stat1;
|
||||
DROP TABLE IF EXISTS sqlite_stat4;
|
||||
DROP TABLE IF EXISTS sqlite_stat3;
|
||||
INSERT INTO sqlite_stat1 VALUES('t5','t5i1','2702931 3 2 2 2 2');
|
||||
INSERT INTO sqlite_stat1 VALUES('t5','t5i2','2702931 686 2 2 2');
|
||||
ANALYZE sqlite_master;
|
||||
} {}
|
||||
db cache flush
|
||||
do_execsql_test skipscan1-5.3 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N';
|
||||
} {/.*COVERING INDEX t5i1 .*/}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -74,6 +74,7 @@ do_execsql_test skipscan2-1.4 {
|
||||
-- of a skip-scan. So make a manual adjustment to the stat1 table
|
||||
-- to make it seem like there are many more.
|
||||
UPDATE sqlite_stat1 SET stat='10000 5000 20' WHERE idx='people_idx1';
|
||||
UPDATE sqlite_stat1 SET stat='10000 1' WHERE idx='sqlite_autoindex_people_1';
|
||||
ANALYZE sqlite_master;
|
||||
}
|
||||
db cache flush
|
||||
|
||||
+176
-3
@@ -8,10 +8,10 @@
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the CREATE TABLE statement.
|
||||
#
|
||||
# $Id: sort.test,v 1.25 2005/11/14 22:29:06 drh Exp $
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the sorter (code in vdbesort.c).
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -464,4 +464,177 @@ do_test sort-12.1 {
|
||||
}
|
||||
} {1 2 xxx 1 3 yyy 1 1 zzz}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that the sorter in vdbesort.c sorts in a stable fashion.
|
||||
#
|
||||
do_execsql_test sort-13.0 {
|
||||
CREATE TABLE t10(a, b);
|
||||
}
|
||||
do_test sort-13.1 {
|
||||
db transaction {
|
||||
for {set i 0} {$i < 100000} {incr i} {
|
||||
execsql { INSERT INTO t10 VALUES( $i/10, $i%10 ) }
|
||||
}
|
||||
}
|
||||
} {}
|
||||
do_execsql_test sort-13.2 {
|
||||
SELECT a, b FROM t10 ORDER BY a;
|
||||
} [db eval {SELECT a, b FROM t10 ORDER BY a, b}]
|
||||
do_execsql_test sort-13.3 {
|
||||
PRAGMA cache_size = 5;
|
||||
SELECT a, b FROM t10 ORDER BY a;
|
||||
} [db eval {SELECT a, b FROM t10 ORDER BY a, b}]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Sort some large ( > 4KiB) records.
|
||||
#
|
||||
proc cksum {x} {
|
||||
set i1 1
|
||||
set i2 2
|
||||
binary scan $x c* L
|
||||
foreach {a b} $L {
|
||||
set i1 [expr (($i2<<3) + $a) & 0x7FFFFFFF]
|
||||
set i2 [expr (($i1<<3) + $b) & 0x7FFFFFFF]
|
||||
}
|
||||
list $i1 $i2
|
||||
}
|
||||
db func cksum cksum
|
||||
|
||||
do_execsql_test sort-14.0 {
|
||||
PRAGMA cache_size = 5;
|
||||
CREATE TABLE t11(a, b);
|
||||
INSERT INTO t11 VALUES(randomblob(5000), NULL);
|
||||
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --2
|
||||
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --3
|
||||
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --4
|
||||
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --5
|
||||
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --6
|
||||
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --7
|
||||
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --8
|
||||
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --9
|
||||
UPDATE t11 SET b = cksum(a);
|
||||
}
|
||||
|
||||
foreach {tn mmap_limit} {
|
||||
1 0
|
||||
2 1000000
|
||||
} {
|
||||
do_test sort-14.$tn {
|
||||
sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $mmap_limit
|
||||
set prev ""
|
||||
db eval { SELECT * FROM t11 ORDER BY b } {
|
||||
if {$b != [cksum $a]} {error "checksum failed"}
|
||||
if {[string compare $b $prev] < 0} {error "sort failed"}
|
||||
set prev $b
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
foreach {tn mmap_limit nWorker tmpstore coremutex fakeheap softheaplimit} {
|
||||
1 0 3 file true false 0
|
||||
2 0 3 file true true 0
|
||||
3 0 0 file true false 0
|
||||
4 1000000 3 file true false 0
|
||||
5 0 0 memory false true 0
|
||||
6 0 0 file false true 1000000
|
||||
7 0 0 file false true 10000
|
||||
} {
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_worker_threads $nWorker
|
||||
if {$coremutex} {
|
||||
sqlite3_config multithread
|
||||
} else {
|
||||
sqlite3_config singlethread
|
||||
}
|
||||
sqlite3_initialize
|
||||
sorter_test_fakeheap $fakeheap
|
||||
sqlite3_soft_heap_limit $softheaplimit
|
||||
|
||||
reset_db
|
||||
sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $mmap_limit
|
||||
execsql "PRAGMA temp_store = $tmpstore"
|
||||
|
||||
set ten [string repeat X 10300]
|
||||
set one [string repeat y 200]
|
||||
|
||||
if {$softheaplimit} {
|
||||
execsql { PRAGMA cache_size = 20 };
|
||||
} else {
|
||||
execsql { PRAGMA cache_size = 5 };
|
||||
}
|
||||
|
||||
do_execsql_test 15.$tn.1 {
|
||||
WITH rr AS (
|
||||
SELECT 4, $ten UNION ALL
|
||||
SELECT 2, $one UNION ALL
|
||||
SELECT 1, $ten UNION ALL
|
||||
SELECT 3, $one
|
||||
)
|
||||
SELECT * FROM rr ORDER BY 1;
|
||||
} [list 1 $ten 2 $one 3 $one 4 $ten]
|
||||
|
||||
do_execsql_test 15.$tn.2 {
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES(4);
|
||||
INSERT INTO t1 VALUES(5);
|
||||
INSERT INTO t1 VALUES(3);
|
||||
INSERT INTO t1 VALUES(2);
|
||||
INSERT INTO t1 VALUES(6);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
} {1 2 3 4 5 6}
|
||||
|
||||
do_execsql_test 15.$tn.3 {
|
||||
WITH rr AS (
|
||||
SELECT 4, $ten UNION ALL
|
||||
SELECT 2, $one
|
||||
)
|
||||
SELECT * FROM rr ORDER BY 1;
|
||||
} [list 2 $one 4 $ten]
|
||||
|
||||
sorter_test_fakeheap 0
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_worker_threads 0
|
||||
set t(0) singlethread
|
||||
set t(1) multithread
|
||||
set t(2) serialized
|
||||
sqlite3_config $t($sqlite_options(threadsafe))
|
||||
sqlite3_initialize
|
||||
sqlite3_soft_heap_limit 0
|
||||
|
||||
reset_db
|
||||
do_catchsql_test 16.1 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(1, NULL, 3);
|
||||
INSERT INTO t1 VALUES(NULL, 2, 3);
|
||||
INSERT INTO t1 VALUES(1, 2, NULL);
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
CREATE UNIQUE INDEX i1 ON t1(b, a, c);
|
||||
} {0 {}}
|
||||
reset_db
|
||||
do_catchsql_test 16.2 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(1, NULL, 3);
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(1, 2, NULL);
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
CREATE UNIQUE INDEX i1 ON t1(b, a, c);
|
||||
} {1 {UNIQUE constraint failed: t1.b, t1.a, t1.c}}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 17.1 {
|
||||
SELECT * FROM sqlite_master ORDER BY sql;
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
# 2014 March 25.
|
||||
#
|
||||
# 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, the tests in this file attempt to verify that
|
||||
# multi-threaded sorting works.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix sort2
|
||||
|
||||
foreach {tn script} {
|
||||
1 { }
|
||||
2 {
|
||||
catch { db close }
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_worker_threads 7
|
||||
reset_db
|
||||
}
|
||||
} {
|
||||
|
||||
eval $script
|
||||
|
||||
do_execsql_test $tn.1 {
|
||||
PRAGMA cache_size = 5;
|
||||
WITH r(x,y) AS (
|
||||
SELECT 1, randomblob(100)
|
||||
UNION ALL
|
||||
SELECT x+1, randomblob(100) FROM r
|
||||
LIMIT 100000
|
||||
)
|
||||
SELECT count(x), length(y) FROM r GROUP BY (x%5)
|
||||
} {
|
||||
20000 100 20000 100 20000 100 20000 100 20000 100
|
||||
}
|
||||
|
||||
do_execsql_test $tn.2.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
WITH r(x,y) AS (
|
||||
SELECT 1, randomblob(100)
|
||||
UNION ALL
|
||||
SELECT x+1, randomblob(100) FROM r
|
||||
LIMIT 10000
|
||||
) INSERT INTO t1 SELECT * FROM r;
|
||||
}
|
||||
|
||||
do_execsql_test $tn.2.2 {
|
||||
CREATE UNIQUE INDEX i1 ON t1(b, a);
|
||||
}
|
||||
|
||||
do_execsql_test $tn.2.3 {
|
||||
CREATE UNIQUE INDEX i2 ON t1(a);
|
||||
}
|
||||
|
||||
do_execsql_test $tn.2.4 { PRAGMA integrity_check } {ok}
|
||||
|
||||
breakpoint
|
||||
do_execsql_test $tn.3 {
|
||||
PRAGMA cache_size = 5;
|
||||
WITH r(x,y) AS (
|
||||
SELECT 1, randomblob(100)
|
||||
UNION ALL
|
||||
SELECT x+1, randomblob(100) FROM r
|
||||
LIMIT 1000000
|
||||
)
|
||||
SELECT count(x), length(y) FROM r GROUP BY (x%5)
|
||||
} {
|
||||
200000 100 200000 100 200000 100 200000 100 200000 100
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_worker_threads 0
|
||||
sqlite3_initialize
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# 2014 March 25.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The tests in this file verify that sorting works when the library is
|
||||
# configured to use mmap(), but the temporary files generated by the
|
||||
# sorter are too large to be completely mapped.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix sort3
|
||||
|
||||
# Sort roughly 20MB of data. Once with a mmap limit of 5MB and once without.
|
||||
#
|
||||
foreach {itest limit} {
|
||||
1 5000000
|
||||
2 0x7FFFFFFF
|
||||
} {
|
||||
sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $limit
|
||||
do_execsql_test 1.$itest {
|
||||
WITH r(x,y) AS (
|
||||
SELECT 1, randomblob(1000)
|
||||
UNION ALL
|
||||
SELECT x+1, randomblob(1000) FROM r
|
||||
LIMIT 20000
|
||||
)
|
||||
SELECT count(*), sum(length(y)) FROM r GROUP BY (x%5);
|
||||
} {
|
||||
4000 4000000
|
||||
4000 4000000
|
||||
4000 4000000
|
||||
4000 4000000
|
||||
4000 4000000
|
||||
}
|
||||
}
|
||||
|
||||
# Sort more than 2GB of data. At one point this was causing a problem.
|
||||
# This test might take one minute or more to run.
|
||||
#
|
||||
do_execsql_test 2 {
|
||||
PRAGMA cache_size = 20000;
|
||||
WITH r(x,y) AS (
|
||||
SELECT 1, randomblob(1000)
|
||||
UNION ALL
|
||||
SELECT x+1, randomblob(1000) FROM r
|
||||
LIMIT 2200000
|
||||
)
|
||||
SELECT count(*), sum(length(y)) FROM r GROUP BY (x%5);
|
||||
} {
|
||||
440000 440000000
|
||||
440000 440000000
|
||||
440000 440000000
|
||||
440000 440000000
|
||||
440000 440000000
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user