Sync w/trunk, further streamline shell's resumable prescan.

FossilOrigin-Name: 9e00f9f7c03c192a3fb6b22851db0626515c59daac5ce6520229c42c838bf5b7
This commit is contained in:
larrybr 2021-09-18 21:35:22 +00:00
commit 7e00984a47
28 changed files with 2495 additions and 240 deletions

View File

@ -468,7 +468,8 @@ TESTSRC += \
$(TOP)/ext/misc/unionvtab.c \
$(TOP)/ext/misc/wholenumber.c \
$(TOP)/ext/misc/zipfile.c \
$(TOP)/ext/userauth/userauth.c
$(TOP)/ext/userauth/userauth.c \
$(TOP)/ext/rtree/test_rtreedoc.c
# Source code to the library files needed by the test fixture
#

View File

@ -1586,6 +1586,7 @@ TESTEXT = \
$(TOP)\ext\misc\totype.c \
$(TOP)\ext\misc\unionvtab.c \
$(TOP)\ext\misc\wholenumber.c \
$(TOP)\ext\rtree\test_rtreedoc.c \
fts5.c
# If use of zlib is enabled, add the "zipfile.c" source file.

View File

@ -64,7 +64,11 @@
#endif
int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */
#ifndef SQLITE_AMALGAMATION
/*
** If building separately, we will need some setup that is normally
** found in sqliteInt.h
*/
#if !defined(SQLITE_AMALGAMATION)
#include "sqlite3rtree.h"
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
@ -77,7 +81,17 @@ typedef unsigned int u32;
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
# undef NDEBUG
#endif
#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define ALWAYS(X) (1)
# define NEVER(X) (0)
#elif !defined(NDEBUG)
# define ALWAYS(X) ((X)?1:(assert(0),0))
# define NEVER(X) ((X)?(assert(0),1):0)
#else
# define ALWAYS(X) (X)
# define NEVER(X) (X)
#endif
#endif /* !defined(SQLITE_AMALGAMATION) */
#include <string.h>
#include <stdio.h>
@ -135,7 +149,9 @@ struct Rtree {
u8 nBytesPerCell; /* Bytes consumed per cell */
u8 inWrTrans; /* True if inside write transaction */
u8 nAux; /* # of auxiliary columns in %_rowid */
#ifdef SQLITE_ENABLE_GEOPOLY
u8 nAuxNotNull; /* Number of initial not-null aux columns */
#endif
#ifdef SQLITE_DEBUG
u8 bCorrupt; /* Shadow table corruption detected */
#endif
@ -666,18 +682,6 @@ static void nodeBlobReset(Rtree *pRtree){
}
}
/*
** Check to see if pNode is the same as pParent or any of the parents
** of pParent.
*/
static int nodeInParentChain(const RtreeNode *pNode, const RtreeNode *pParent){
do{
if( pNode==pParent ) return 1;
pParent = pParent->pParent;
}while( pParent );
return 0;
}
/*
** Obtain a reference to an r-tree node.
*/
@ -694,14 +698,7 @@ static int nodeAcquire(
** increase its reference count and return it.
*/
if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
if( pParent && !pNode->pParent ){
if( nodeInParentChain(pNode, pParent) ){
RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
pParent->nRef++;
pNode->pParent = pParent;
}else if( pParent && pNode->pParent && pParent!=pNode->pParent ){
if( pParent && pParent!=pNode->pParent ){
RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
@ -759,7 +756,7 @@ static int nodeAcquire(
** are the leaves, and so on. If the depth as specified on the root node
** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt.
*/
if( pNode && rc==SQLITE_OK && iNode==1 ){
if( rc==SQLITE_OK && pNode && iNode==1 ){
pRtree->iDepth = readInt16(pNode->zData);
if( pRtree->iDepth>RTREE_MAX_DEPTH ){
rc = SQLITE_CORRUPT_VTAB;
@ -1365,11 +1362,12 @@ static int nodeRowidIndex(
*/
static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){
RtreeNode *pParent = pNode->pParent;
if( pParent ){
if( ALWAYS(pParent) ){
return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex);
}else{
*piIndex = -1;
return SQLITE_OK;
}
*piIndex = -1;
return SQLITE_OK;
}
/*
@ -1492,7 +1490,8 @@ static RtreeSearchPoint *rtreeSearchPointNew(
pNew = rtreeEnqueue(pCur, rScore, iLevel);
if( pNew==0 ) return 0;
ii = (int)(pNew - pCur->aPoint) + 1;
if( ii<RTREE_CACHE_SZ ){
assert( ii==1 );
if( ALWAYS(ii<RTREE_CACHE_SZ) ){
assert( pCur->aNode[ii]==0 );
pCur->aNode[ii] = pCur->aNode[0];
}else{
@ -1553,7 +1552,7 @@ static void rtreeSearchPointPop(RtreeCursor *p){
if( p->bPoint ){
p->anQueue[p->sPoint.iLevel]--;
p->bPoint = 0;
}else if( p->nPoint ){
}else if( ALWAYS(p->nPoint) ){
p->anQueue[p->aPoint[0].iLevel]--;
n = --p->nPoint;
p->aPoint[0] = p->aPoint[n];
@ -1694,7 +1693,7 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
int rc = SQLITE_OK;
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
if( rc==SQLITE_OK && p ){
if( rc==SQLITE_OK && ALWAYS(p) ){
*pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
}
return rc;
@ -1712,7 +1711,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
if( rc ) return rc;
if( p==0 ) return SQLITE_OK;
if( NEVER(p==0) ) return SQLITE_OK;
if( i==0 ){
sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
}else if( i<=pRtree->nDim2 ){
@ -1911,8 +1910,11 @@ static int rtreeFilter(
}
if( rc==SQLITE_OK ){
RtreeSearchPoint *pNew;
assert( pCsr->bPoint==0 ); /* Due to the resetCursor() call above */
pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
if( pNew==0 ) return SQLITE_NOMEM;
if( NEVER(pNew==0) ){ /* Because pCsr->bPoint was FALSE */
return SQLITE_NOMEM;
}
pNew->id = 1;
pNew->iCell = 0;
pNew->eWithin = PARTLY_WITHIN;
@ -1989,7 +1991,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
if( bMatch==0 && p->usable
&& p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ
&& p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ
){
/* We have an equality constraint on the rowid. Use strategy 1. */
int jj;
@ -2242,12 +2244,19 @@ static int AdjustTree(
){
RtreeNode *p = pNode;
int cnt = 0;
int rc;
while( p->pParent ){
RtreeNode *pParent = p->pParent;
RtreeCell cell;
int iCell;
if( (++cnt)>1000 || nodeParentIndex(pRtree, p, &iCell) ){
cnt++;
if( NEVER(cnt>100) ){
RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
rc = nodeParentIndex(pRtree, p, &iCell);
if( NEVER(rc!=SQLITE_OK) ){
RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
@ -2631,11 +2640,12 @@ static int SplitNode(
RtreeNode *pParent = pLeft->pParent;
int iCell;
rc = nodeParentIndex(pRtree, pLeft, &iCell);
if( rc==SQLITE_OK ){
if( ALWAYS(rc==SQLITE_OK) ){
nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell);
rc = AdjustTree(pRtree, pParent, &leftbbox);
assert( rc==SQLITE_OK );
}
if( rc!=SQLITE_OK ){
if( NEVER(rc!=SQLITE_OK) ){
goto splitnode_out;
}
}
@ -2710,7 +2720,7 @@ static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){
*/
iNode = sqlite3_column_int64(pRtree->pReadParent, 0);
for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent);
if( !pTest ){
if( pTest==0 ){
rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent);
}
}
@ -2741,6 +2751,7 @@ static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
pParent = pNode->pParent;
pNode->pParent = 0;
rc = deleteCell(pRtree, pParent, iCell, iHeight+1);
assert( rc==SQLITE_OK );
}
rc2 = nodeRelease(pRtree, pParent);
if( rc==SQLITE_OK ){
@ -2963,7 +2974,7 @@ static int rtreeInsertCell(
}
}else{
rc = AdjustTree(pRtree, pNode, pCell);
if( rc==SQLITE_OK ){
if( ALWAYS(rc==SQLITE_OK) ){
if( iHeight==0 ){
rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
}else{
@ -3069,7 +3080,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
int rc2;
RtreeNode *pChild = 0;
i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); /* tag-20210916a */
if( rc==SQLITE_OK ){
rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
}
@ -3404,7 +3415,7 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
char *zSql;
sqlite3_stmt *p;
int rc;
i64 nRow = 0;
i64 nRow = RTREE_MIN_ROWEST;
rc = sqlite3_table_column_metadata(
db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0
@ -3421,20 +3432,10 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
if( rc==SQLITE_OK ){
if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
rc = sqlite3_finalize(p);
}else if( rc!=SQLITE_NOMEM ){
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
if( nRow==0 ){
pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
}else{
pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
}
}
sqlite3_free(zSql);
}
pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
return rc;
}
@ -3584,9 +3585,12 @@ static int rtreeSqlInit(
sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix);
for(ii=0; ii<pRtree->nAux; ii++){
if( ii ) sqlite3_str_append(p, ",", 1);
#ifdef SQLITE_ENABLE_GEOPOLY
if( ii<pRtree->nAuxNotNull ){
sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii);
}else{
}else
#endif
{
sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2);
}
}
@ -4525,7 +4529,10 @@ int sqlite3_rtree_query_callback(
/* Allocate and populate the context object. */
pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback));
if( !pGeomCtx ) return SQLITE_NOMEM;
if( !pGeomCtx ){
if( xDestructor ) xDestructor(pContext);
return SQLITE_NOMEM;
}
pGeomCtx->xGeom = 0;
pGeomCtx->xQueryFunc = xQueryFunc;
pGeomCtx->xDestructor = xDestructor;

View File

@ -145,7 +145,7 @@ populate_t1
do_test rtreeA-2.2.0 { truncate_node 1 200 } {}
do_corruption_tests rtreeA-2.2 {
1 "SELECT * FROM t1"
2 "SELECT * FROM t1 WHERE rowid=5"
2 "SELECT * FROM t1 WHERE +rowid=5"
3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
4 "SELECT * FROM t1 WHERE x1<10 AND x2>12"
}
@ -160,7 +160,7 @@ do_test rtreeA-3.1.0.1 { set_tree_depth t1 } {1}
do_test rtreeA-3.1.0.2 { set_tree_depth t1 3 } {3}
do_corruption_tests rtreeA-3.1 {
1 "SELECT * FROM t1"
2 "SELECT * FROM t1 WHERE rowid=5"
2 "SELECT * FROM t1 WHERE +rowid=5"
3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
}
@ -171,7 +171,7 @@ do_execsql_test rtreeA-3.1.0.3 {
do_test rtreeA-3.2.0 { set_tree_depth t1 1000 } {1000}
do_corruption_tests rtreeA-3.2 {
1 "SELECT * FROM t1"
2 "SELECT * FROM t1 WHERE rowid=5"
2 "SELECT * FROM t1 WHERE +rowid=5"
3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
}
@ -183,7 +183,7 @@ do_test rtreeA-3.3.0 {
} {65535}
do_corruption_tests rtreeA-3.3 {
1 "SELECT * FROM t1"
2 "SELECT * FROM t1 WHERE rowid=5"
2 "SELECT * FROM t1 WHERE +rowid=5"
3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
}
@ -203,7 +203,7 @@ do_test rtreeA-4.1.0 {
} {4000}
do_corruption_tests rtreeA-4.1 {
1 "SELECT * FROM t1"
2 "SELECT * FROM t1 WHERE rowid=5"
2 "SELECT * FROM t1 WHERE +rowid=5"
3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
4 "SELECT * FROM t1 WHERE x1<10 AND x2>12"
}
@ -216,7 +216,7 @@ create_t1
populate_t1
do_execsql_test rtreeA-5.1.0 { DELETE FROM t1_parent } {}
do_corruption_tests rtreeA-5.1 {
1 "DELETE FROM t1 WHERE rowid = 5"
1 "DELETE FROM t1 WHERE +rowid = 5"
2 "DELETE FROM t1"
}

1578
ext/rtree/rtreedoc.test Normal file

File diff suppressed because it is too large Load Diff

346
ext/rtree/rtreedoc2.test Normal file
View File

@ -0,0 +1,346 @@
# 2021 September 13
#
# 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.
#
#***********************************************************************
#
# The focus of this file is testing the r-tree extension.
#
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
set testprefix rtreedoc2
ifcapable !rtree {
finish_test
return
}
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
# Section 6 of documentation.
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
set testprefix rtreedoc2-1
# EVIDENCE-OF: R-35254-48865 A call to one of the above APIs creates a
# new SQL function named by the second parameter (zQueryFunc or zGeom).
#
# [register_circle_geom db] registers new geometry callback "Qcircle"
# and legacy implementation "circle". Test that these do actually appear.
#
do_execsql_test 1.1.0 {
SELECT * FROM pragma_function_list WHERE name IN('circle', 'qcircle');
} {
}
do_test 1.1 {
register_circle_geom db
} {SQLITE_OK}
do_execsql_test 1.1.2 {
SELECT * FROM pragma_function_list WHERE name = 'circle' AND enc='utf8';
} {
circle 0 s utf8 -1 0
}
do_execsql_test 1.1.3 {
SELECT * FROM pragma_function_list WHERE name = 'qcircle' AND enc='utf8';
} {
qcircle 0 s utf8 -1 0
}
do_execsql_test 1.2.0 { SELECT circle(1, 2, 3); } {{}}
do_execsql_test 1.2.1 { SELECT qcircle(1, 2, 3); } {{}}
# EVIDENCE-OF: R-61427-46983
do_execsql_test 1.3.0 {
CREATE VIRTUAL TABLE demo_index USING rtree(id, x1,x2, y1,y2);
INSERT INTO demo_index VALUES(10, 45,45, 24,24);
INSERT INTO demo_index VALUES(20, 50,50, 28,28);
INSERT INTO demo_index VALUES(30, 43,43, 22,22);
}
do_execsql_test 1.3.1 {
SELECT id FROM demo_index WHERE id MATCH circle(45.3, 22.9, 5.0)
} {10 30}
# EVIDENCE-OF: R-16907-50223 The SQL syntax for custom queries is the
# same regardless of which interface, sqlite3_rtree_geometry_callback()
# or sqlite3_rtree_query_callback(), is used to register the SQL
# function.
do_execsql_test 1.3.2 {
SELECT id FROM demo_index WHERE id MATCH qcircle(45.3, 22.9, 5.0, 1)
} {10 30}
# EVIDENCE-OF: R-59634-51678 When that SQL function appears on the
# right-hand side of the MATCH operator and the left-hand side of the
# MATCH operator is any column in the R*Tree virtual table, then the
# callback defined by the third argument (xQueryFunc or xGeom) is
# invoked to determine if a particular object or subtree overlaps the
# desired region.
proc box_geom {args} {
lappend ::box_geom [concat [lindex $args 0] [lrange $args 2 end-1]]
return ""
}
register_box_geom db box_geom
set box_geom [list]
do_execsql_test 1.3.2 {
SELECT id FROM demo_index WHERE id MATCH box(43,46, 21,25);
} {10 30}
do_test 1.3.3 {
set ::box_geom
} [list {*}{
{box {43.0 46.0 21.0 25.0} {45.0 45.0 24.0 24.0}}
{box {43.0 46.0 21.0 25.0} {50.0 50.0 28.0 28.0}}
{box {43.0 46.0 21.0 25.0} {43.0 43.0 22.0 22.0}}
}]
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
# Section 6 of documentation.
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
set testprefix rtreedoc2-2
# EVIDENCE-OF: R-02424-24769 The second argument is the number of
# coordinates in each r-tree entry, and is always the same for any given
# R*Tree.
#
# EVIDENCE-OF: R-40260-16838 The number of coordinates is 2 for a
# 1-dimensional R*Tree, 4 for a 2-dimensional R*Tree, 6 for a
# 3-dimensional R*Tree, and so forth.
#
# The second argument refered to above is the length of the list passed
# as the 3rd parameter to the Tcl script.
#
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE rt1 USING rtree(id, x1,x2);
CREATE VIRTUAL TABLE rt2 USING rtree(id, x1,x2, y1,y2);
CREATE VIRTUAL TABLE rt3 USING rtree(id, x1,x2, y1,y2, z1,z2);
INSERT INTO rt1 DEFAULT VALUES;
INSERT INTO rt2 DEFAULT VALUES;
INSERT INTO rt3 DEFAULT VALUES;
}
foreach {tn tbl nCoord} {
1 rt1 2
2 rt2 4
3 rt3 6
} {
set ::box_geom [list]
do_catchsql_test 1.$tn.1 "
SELECT id FROM $tbl WHERE id MATCH box();
" {1 {SQL logic error}}
do_test 1.$tn.2 {
llength [lindex $::box_geom 0 2]
} $nCoord
}
# EVIDENCE-OF: R-28051-48608 If xGeom returns anything other than
# SQLITE_OK, then the r-tree query will abort with an error.
proc box_geom {args} {
error "an error!"
}
do_catchsql_test 2.0 {
SELECT * FROM rt2 WHERE id MATCH box(22,23, 24,25);
} {1 {SQL logic error}}
do_execsql_test 3.0 {
INSERT INTO rt1 VALUES(10, 10, 10);
INSERT INTO rt1 VALUES(11, 11, 11);
INSERT INTO rt1 VALUES(12, 12, 12);
INSERT INTO rt1 VALUES(13, 13, 13);
INSERT INTO rt1 VALUES(14, 14, 14);
}
# EVIDENCE-OF: R-53759-57366 The exact same sqlite3_rtree_geometry
# structure is used for every callback for same MATCH operator in the
# same query.
proc box_geom {args} {
lappend ::ptr_list [lindex $args 4]
return 0
}
set ::ptr_list [list]
do_execsql_test 3.1 {
SELECT * FROM rt1 WHERE id MATCH box(1,1);
}
do_test 3.2 {
set val [lindex $::ptr_list 0]
foreach p $::ptr_list {
if {$p!=$val} {error "pointer mismatch"}
}
} {}
# EVIDENCE-OF: R-60247-35692 The contents of the sqlite3_rtree_geometry
# structure are initialized by SQLite but are not subsequently modified.
proc box_geom {args} {
lappend ::box_geom [concat [lindex $args 0] [lrange $args 2 end-1]]
if {[llength $::box_geom]==3} {
return "zero"
}
return ""
}
set ::box_geom [list]
do_catchsql_test 3.2 {
SELECT * FROM rt1 WHERE id MATCH box(1,1);
} {1 {SQL logic error}}
do_test 3.3 {
set ::box_geom
} [list {*}{
{box {1.0 1.0} {0.0 0.0}}
{box {1.0 1.0} {10.0 10.0}}
{box {1.0 1.0} {11.0 11.0}}
{box 0.0 {12.0 12.0}}
}]
# EVIDENCE-OF: R-31246-29731 The pContext member of the
# sqlite3_rtree_geometry structure is always set to a copy of the
# pContext argument passed to sqlite3_rtree_geometry_callback() when the
# callback is registered.
reset_db
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE r1 USING rtree(id, minX,maxX, minY,maxY);
WITH s(i) AS (
VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<120
)
INSERT INTO r1 SELECT i,i,i+1, 200,201 FROM s;
}
set ctx [register_box_geom db box_geom]
set ::box_geom [list]
proc box_geom {args} {
lappend ::box_geom [lindex $args 1]
return ""
}
do_execsql_test 4.1 {
SELECT count(*) FROM r1 WHERE id MATCH box(0,150,199,201)
} 120
do_test 4.2 {
foreach g $::box_geom {
if {$g!=$ctx} {error "pointer mismatch"}
}
} {}
# EVIDENCE-OF: R-09904-19077 The aParam[] array (size nParam) contains
# the parameter values passed to the SQL function on the right-hand side
# of the MATCH operator.
proc box_geom {args} {
set ::box_geom [lindex $args 2]
}
foreach {tn q vals} {
1 "SELECT count(*) FROM r1 WHERE id MATCH box(1,2,3)" {1.0 2.0 3.0}
2 "SELECT count(*) FROM r1 WHERE id MATCH box(10001)" {10001.0}
3 "SELECT count(*) FROM r1 WHERE id MATCH box(-10001)" {-10001.0}
} {
do_catchsql_test 5.$tn.1 $q {1 {SQL logic error}}
do_test 5.$tn.2 { set ::box_geom } $vals
}
do_execsql_test 5.0 {
CREATE VIRTUAL TABLE myrtree USING rtree(id, x1,x2);
INSERT INTO myrtree VALUES(1, 1, 1);
INSERT INTO myrtree VALUES(2, 2, 2);
INSERT INTO myrtree VALUES(3, 3, 3);
}
# EVIDENCE-OF: R-44448-00687 The pUser and xDelUser members of the
# sqlite3_rtree_geometry structure are initially set to NULL.
set ::box_geom_calls 0
proc box_geom {args} {
incr ::box_geom_calls
return user_is_zero
}
do_execsql_test 5.1.1 {
SELECT * FROM myrtree WHERE id MATCH box(4, 5);
}
do_test 5.1.2 { set ::box_geom_calls } 3
# EVIDENCE-OF: R-55837-00155 The pUser variable may be set by the
# callback implementation to any arbitrary value that may be useful to
# subsequent invocations of the callback within the same query (for
# example, a pointer to a complicated data structure used to test for
# region intersection).
#
# EVIDENCE-OF: R-34745-08839 If the xDelUser variable is set to a
# non-NULL value, then after the query has finished running SQLite
# automatically invokes it with the value of the pUser variable as the
# only argument.
#
set ::box_geom_calls 0
proc box_geom {args} {
incr ::box_geom_calls
switch -- $::box_geom_calls {
1 {
return user_is_zero
}
2 {
return [list user box_geom_finalizer]
}
}
return ""
}
proc box_geom_finalizer {} {
set ::box_geom_finalizer "::box_geom_calls is $::box_geom_calls"
}
do_execsql_test 5.1.1 {
SELECT * FROM myrtree WHERE id MATCH box(4, 5);
}
do_test 5.1.2 { set ::box_geom_calls } 3
do_test 5.1.3 {
set ::box_geom_finalizer
} {::box_geom_calls is 3}
# EVIDENCE-OF: R-28176-28813 The xGeom callback always does a
# depth-first search of the r-tree.
#
# For a breadth first search, final test case would return "B L" only.
#
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE xyz USING rtree(x, x1,x2, y1,y2);
WITH s(i) AS (
VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<15
)
INSERT INTO xyz SELECT NULL, one.i,one.i+1, two.i,two.i+1 FROM s one, s two;
}
do_execsql_test 6.1 {
SELECT count(*) FROM xyz_node
} {10}
proc box_geom {args} {
set coords [lindex $args 3]
set area [expr {
([lindex $coords 1]-[lindex $coords 0]) *
([lindex $coords 3]-[lindex $coords 2])
}]
if {$area==1} {
lappend ::box_geom_calls L
} else {
lappend ::box_geom_calls B
}
}
set ::box_geom_calls [list]
do_execsql_test 6.2 {
SELECT count(*) FROM xyz WHERE x MATCH box(0,20,0,20)
} 225
do_test 6.3 {
set prev ""
set box_calls [list]
foreach c $::box_geom_calls {
if {$c!=$prev} {
lappend ::box_calls $c
set prev $c
}
}
set ::box_calls
} {B L B L B L B L B L B L B L B L B L}
finish_test

228
ext/rtree/test_rtreedoc.c Normal file
View File

@ -0,0 +1,228 @@
/*
** 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.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library.
*/
#include "sqlite3.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"
#ifdef SQLITE_ENABLE_RTREE
typedef struct BoxGeomCtx BoxGeomCtx;
struct BoxGeomCtx {
Tcl_Interp *interp;
Tcl_Obj *pScript;
};
static void testDelUser(void *pCtx){
BoxGeomCtx *p = (BoxGeomCtx*)pCtx;
Tcl_EvalObjEx(p->interp, p->pScript, 0);
Tcl_DecrRefCount(p->pScript);
sqlite3_free(p);
}
static int invokeTclGeomCb(
const char *zName,
sqlite3_rtree_geometry *p,
int nCoord,
sqlite3_rtree_dbl *aCoord
){
int rc = SQLITE_OK;
if( p->pContext ){
char aPtr[64];
BoxGeomCtx *pCtx = (BoxGeomCtx*)p->pContext;
Tcl_Interp *interp = pCtx->interp;
Tcl_Obj *pScript = 0;
Tcl_Obj *pParam = 0;
Tcl_Obj *pCoord = 0;
int ii;
Tcl_Obj *pRes;
pScript = Tcl_DuplicateObj(pCtx->pScript);
Tcl_IncrRefCount(pScript);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(zName,-1));
sqlite3_snprintf(sizeof(aPtr)-1, aPtr, "%p", (void*)p->pContext);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(aPtr,-1));
pParam = Tcl_NewObj();
for(ii=0; ii<p->nParam; ii++){
Tcl_ListObjAppendElement(
interp, pParam, Tcl_NewDoubleObj(p->aParam[ii])
);
}
Tcl_ListObjAppendElement(interp, pScript, pParam);
pCoord = Tcl_NewObj();
for(ii=0; ii<nCoord; ii++){
Tcl_ListObjAppendElement(interp, pCoord, Tcl_NewDoubleObj(aCoord[ii]));
}
Tcl_ListObjAppendElement(interp, pScript, pCoord);
sqlite3_snprintf(sizeof(aPtr)-1, aPtr, "%p", (void*)p);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(aPtr,-1));
rc = Tcl_EvalObjEx(interp, pScript, 0);
if( rc!=TCL_OK ){
rc = SQLITE_ERROR;
}else{
int nObj = 0;
Tcl_Obj **aObj = 0;
pRes = Tcl_GetObjResult(interp);
if( Tcl_ListObjGetElements(interp, pRes, &nObj, &aObj) ) return TCL_ERROR;
if( nObj>0 ){
const char *zCmd = Tcl_GetString(aObj[0]);
if( 0==sqlite3_stricmp(zCmd, "zero") ){
p->aParam[0] = 0.0;
p->nParam = 1;
}
else if( 0==sqlite3_stricmp(zCmd, "user") ){
if( p->pUser || p->xDelUser ){
rc = SQLITE_ERROR;
}else{
BoxGeomCtx *pCtx = sqlite3_malloc(sizeof(BoxGeomCtx));
if( pCtx==0 ){
rc = SQLITE_NOMEM;
}else{
pCtx->interp = interp;
pCtx->pScript = Tcl_DuplicateObj(pRes);
Tcl_IncrRefCount(pCtx->pScript);
Tcl_ListObjReplace(interp, pCtx->pScript, 0, 1, 0, 0);
p->pUser = (void*)pCtx;
p->xDelUser = testDelUser;
}
}
}
else if( 0==sqlite3_stricmp(zCmd, "user_is_zero") ){
if( p->pUser || p->xDelUser ) rc = SQLITE_ERROR;
}
}
}
}
return rc;
}
/*
# EVIDENCE-OF: R-00693-36727 The legacy xGeom callback is invoked with
# four arguments.
# EVIDENCE-OF: R-50437-53270 The first argument is a pointer to an
# sqlite3_rtree_geometry structure which provides information about how
# the SQL function was invoked.
# EVIDENCE-OF: R-40260-16838 The number of coordinates is 2 for a
# 1-dimensional R*Tree, 4 for a 2-dimensional R*Tree, 6 for a
# 3-dimensional R*Tree, and so forth.
# EVIDENCE-OF: R-00090-24248 The third argument, aCoord[], is an array
# of nCoord coordinates that defines a bounding box to be tested.
# EVIDENCE-OF: R-28207-40885 The last argument is a pointer into which
# the callback result should be written.
*/
static int box_geom(
sqlite3_rtree_geometry *p, /* R-50437-53270 */
int nCoord, /* R-02424-24769 */
sqlite3_rtree_dbl *aCoord, /* R-00090-24248 */
int *pRes /* R-28207-40885 */
){
int ii;
if( p->nParam!=nCoord ){
invokeTclGeomCb("box", p, nCoord, aCoord);
return SQLITE_ERROR;
}
if( invokeTclGeomCb("box", p, nCoord, aCoord) ) return SQLITE_ERROR;
for(ii=0; ii<nCoord; ii+=2){
if( aCoord[ii]>p->aParam[ii+1] || aCoord[ii+1]<p->aParam[ii] ){
/* R-28207-40885 */
*pRes = 0;
return SQLITE_OK;
}
}
/* R-28207-40885 */
*pRes = 1;
return SQLITE_OK;
}
static int SQLITE_TCLAPI register_box_geom(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
extern const char *sqlite3ErrName(int);
sqlite3 *db;
BoxGeomCtx *pCtx;
char aPtr[64];
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB SCRIPT");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
pCtx = (BoxGeomCtx*)ckalloc(sizeof(BoxGeomCtx*));
pCtx->interp = interp;
pCtx->pScript = Tcl_DuplicateObj(objv[2]);
Tcl_IncrRefCount(pCtx->pScript);
sqlite3_rtree_geometry_callback(db, "box", box_geom, (void*)pCtx);
sqlite3_snprintf(64, aPtr, "%p", (void*)pCtx);
Tcl_SetObjResult(interp, Tcl_NewStringObj(aPtr, -1));
return TCL_OK;
}
static int SQLITE_TCLAPI register_box_query(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
extern const char *sqlite3ErrName(int);
sqlite3 *db;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB SCRIPT");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
return TCL_OK;
}
#endif /* SQLITE_ENABLE_RTREE */
int Sqlitetestrtreedoc_Init(Tcl_Interp *interp){
#ifdef SQLITE_ENABLE_RTREE
Tcl_CreateObjCommand(interp, "register_box_geom", register_box_geom, 0, 0);
Tcl_CreateObjCommand(interp, "register_box_query", register_box_query, 0, 0);
#endif /* SQLITE_ENABLE_RTREE */
return TCL_OK;
}

View File

@ -387,7 +387,8 @@ TESTSRC += \
$(TOP)/ext/misc/zipfile.c \
$(TOP)/ext/fts5/fts5_tcl.c \
$(TOP)/ext/fts5/fts5_test_mi.c \
$(TOP)/ext/fts5/fts5_test_tok.c
$(TOP)/ext/fts5/fts5_test_tok.c \
$(TOP)/ext/rtree/test_rtreedoc.c
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c

View File

@ -1,11 +1,11 @@
C CLI\sprescanner\smade\sto\smatch\sSQLite's\srules\sfor\sdelimited\sidentifiers.\sTests\sbegun.
D 2021-09-11T02:42:04.707
C Sync\sw/trunk,\sfurther\sstreamline\sshell's\sresumable\sprescan.
D 2021-09-18T21:35:22.366
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F Makefile.in 83c348515cb62f6f2a2ddf3fd014113ff20564b776e1a614079722c88c6ff43d
F Makefile.in 2a6e71e91f29e9eb0cb800b6500bbbfef31730d5c37eaadb6e8ea8a45e6ead21
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
F Makefile.msc 7dc32ba195639311ef4fa3d8f8ec218de37fde12d7ef5a33e9a7de921b0025ca
F Makefile.msc b18738be47ba9293dbea2048fe1d5a737456fdc630361cc98ef2c2f73bf3395c
F README.md 27fb76aa7eb57ed63a53bbba7292b6bf71f51125554f79f16b5d040edd1e6110
F VERSION c6595fef606851f2bc3ebed6a7386c73751835fc909feab7c093739fa4b3c1d1
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
@ -393,7 +393,7 @@ F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c3350
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/geopoly.c 98d45533989e908bf65b43f36ff6eaad95a9ffe6f3b6b8658fbd47d45c58b10b
F ext/rtree/rtree.c 0d1ef309e2bfbe469e3ee363ff9ea0420d5f7b9fcf15b5d9abb9d48a789c26f5
F ext/rtree/rtree.c fb930d5bee9deb9efbfbed72be56a0d4e4950ab216284fb5ec1c9863d32a32fa
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
F ext/rtree/rtree1.test 00792b030a4e188ff1b22e8530e8aa0452bb5dd81c2b18cb004afc7dc63e040e
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
@ -404,7 +404,7 @@ F ext/rtree/rtree6.test 9ce3691c1aac43070a9f194f0ebf54372db346c5a82241fd11b525ed
F ext/rtree/rtree7.test c8fb2e555b128dd0f0bdb520c61380014f497f8a23c40f2e820acc9f9e4fdce5
F ext/rtree/rtree8.test 2d99006a1386663978c9e1df167554671e4f711c419175b39f332719deb1ce0e
F ext/rtree/rtree9.test c646f12c8c1c68ef015c6c043d86a0c42488e2e68ed1bb1b0771a7ca246cbabf
F ext/rtree/rtreeA.test ed2f1be9c06dde0b1ab93a95dd9e87eeaa02db2d30bcb4b9179b69ee3dc3319b
F ext/rtree/rtreeA.test c0d8e91e25052d5f3fbda17632ca843b82ca13c4181fb6000a0d63bd2d7e70ce
F ext/rtree/rtreeB.test 4cec297f8e5c588654bbf3c6ed0903f10612be8a2878055dd25faf8c71758bc9
F ext/rtree/rtreeC.test c4bfa9a61c6788c03e4a9ce40ab2cfc6100982559effd9842d1b658e1d47aa5f
F ext/rtree/rtreeD.test fe46aa7f012e137bd58294409b16c0d43976c3bb92c8f710481e577c4a1100dc
@ -418,8 +418,11 @@ F ext/rtree/rtree_util.tcl db734b4c5e75fed6acc56d9701f2235345acfdec750b5fc7b5879
F ext/rtree/rtreecheck.test d67d5b3e9e45bfa8cd90734e8e9302144ac415b8e9176c6f02d4f92892ee8a35
F ext/rtree/rtreecirc.test aec664eb21ae943aeb344191407afff5d392d3ae9d12b9a112ced0d9c5de298e
F ext/rtree/rtreeconnect.test 225ad3fcb483d36cbee423a25052a6bbae762c9576ae9268332360c68c170d3d
F ext/rtree/rtreedoc.test 243cd3fdee1cb89e290e908ddde0cc0cfda0ccb85473c6d1b3c43e6260b14cac
F ext/rtree/rtreedoc2.test 194ebb7d561452dcdc10bf03f44e30c082c2f0c14efeb07f5e02c7daf8284d93
F ext/rtree/rtreefuzz001.test 0fc793f67897c250c5fde96cefee455a5e2fb92f4feeabde5b85ea02040790ee
F ext/rtree/sqlite3rtree.h 03c8db3261e435fbddcfc961471795cbf12b24e03001d0015b2636b0f3881373
F ext/rtree/test_rtreedoc.c 216f988e0b56474a3d42905653777772d3bdd413a7fe09a79e466b19296853b0
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
F ext/rtree/util/randomshape.tcl 54ee03d0d4a1c621806f7f44d5b78d2db8fac26e0e8687c36c4bd0203b27dbff
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
@ -466,7 +469,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
F main.mk 4e075c9618c06c55d1cc723087b0722f384247b6b8db1ac2cb161f864c953c97
F main.mk 002e77acdfeb08d1d8f4d360b01e130aa243fb5701728e81fac9085794f27155
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@ -478,14 +481,14 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 38975b971a4c36dbcc8004c74b492213a851ab368d29238c531a22636508a5d4
F src/alter.c a4e20094bb7e6ca5fa832779dc0b6aedfed4cab92144d3bc754fc6dfe6f26f34
F src/analyze.c abbaaf7dca79d1c31c713500324fc0b55bf3eeac5b7b07001452a3d0f210de4f
F src/attach.c a514e81758ba7b3a3a0501faf70af6cfc509de8810235db726cfc9f25165e929
F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c 742425ddcc06b2fef621b26edded28f77c7f9a9e96bdb3cb5217eb91444d99cf
F src/btree.c bed4239e31772ed5486e947d8eaf3d38fcc76136e19d0383bad15609198419c2
F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22
F src/btreeInt.h 7bc15a24a02662409ebcd6aeaa1065522d14b7fda71573a2b0568b458f514ae0
F src/build.c 8fa6deebf8726339a5aafb322e9d79c48950b994f33f17460c5393ef593d202e
@ -496,10 +499,10 @@ F src/date.c e0632f335952b32401482d099321bbf12716b29d6e72836b53ae49683ebae4bf
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c
F src/delete.c 3ce6af6b64c8b476de51ccc32da0cb3142d42e65754e1d8118addf65b8bcba15
F src/expr.c e98375fc63552cc8cdd36a41bdca3039cb603d9fe67abd9c9f40adae8405fbc5
F src/expr.c ce736caaf1cf6d69789511e9fc5ed31013d9570d5d773cce909d396112d83843
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 1905af1821b88321e1bb9d6a69e704495b6844a9b6c29398d40117cc251e893c
F src/func.c c224240cbc97fa5e9c4fe9acb128716cb835ca045532bca6951b7c45b020c56c
F src/func.c 812ac5383067bed7150d8597e83c47b714d73db0e62af55811d1a145243e58e1
F src/global.c 612ea60c9acbcb45754c2ed659b4a56936a06814718e969636fedc7e3b889808
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
@ -515,7 +518,7 @@ F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
F src/mem2.c b93b8762ab999a29ae7751532dadf0a1ac78040308a5fb1d17fcc365171d67eb
F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
F src/memdb.c 73622017aa03a3cabd1c4d6fca97eedada2155817dd0d74d6c1aeb42573b515d
F src/memdb.c cd8cf3ee965db4a4ab4b5423b49a4ef810490b8ba828911e523325f2cce3ed1a
F src/memjournal.c a85f0dc5c02a42453d0bc3819ecfb5666cb6433e5deefcd93ccbe05c9f088b83
F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8
F src/mutex.c 5e3409715552348732e97b9194abe92fdfcd934cfb681df4ba0ab87ac6c18d25
@ -531,7 +534,7 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c b11e4610769922253dec27d7af4a07ff84f65169d19bda5e9b12a152a706f7f5
F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 95c255256b13827caf038c8f963d334784073f38ab6ef9d70371d9d04f3c43e0
F src/pager.c 1ba6a843148282895d800aa69919553079946ef9a198a97e5d7c64442d10ed4c
F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f
F src/parse.y 86aa016b281f61d7664dd8cb7808cab8114d14cfaf362a9b9fc9ead8f33546b7
F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b
@ -544,16 +547,16 @@ F src/printf.c 78fabb49b9ac9a12dd1c89d744abdc9b67fd3205e62967e158f78b965a29ec4b
F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
F src/resolve.c 42b94d37a54200707a95566eff4f7e8a380e32d080016b699f23bd79a73a5028
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c b2c48dfc02b486fd2da2be1605503615958ba1997d40d994c2946975d0150a31
F src/shell.c.in be7cd92c042b5e16bfd727404c5b2ec72c8e177ee2e092da6fe3ea031bbf8ece
F src/select.c 030c3d07326708343208418c84da607752aebc13c92df929b7c68c7c08e7df54
F src/shell.c.in 639c01f9a743ed73beb1d4b1e982b07b731c3801811d8344063f43b11008582a
F src/sqlite.h.in 4e977a5e2ed1a9e8987ff65a2cab5f99a4298ebf040ea5ff636e1753339ff45a
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h e97f4e9b509408fea4c4e9bef5a41608dfac343b4d3c7a990dedde1e19af9510
F src/sqliteInt.h 4cb73cc4b9b7705ccfd5bdfb9c248a9772a90ba52f743dbab90d13123babe36b
F src/sqliteInt.h b62ee1fc9da3634616b969abe8b55fafcb540e4e7e5637ee2a2bb5fa477f4a38
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 05663f6b5010b044eac0ef22fc8fb5ea3406d2502700a898261683258042c88b
F src/tclsqlite.c 428e813dabf82804bc13196af35a0c3c6ef4347fe557fa6717c5c66bba6e8520
F src/test1.c 63761c2be2607f1b425fde991beda48aed384f8d67f2b4ee549174c88b433009
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
@ -597,7 +600,7 @@ F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F src/test_tclsh.c eeafce33ad2136d57e5dec10f1e9a4347447eb72ffd504a1c7b9c6bfe2e71578
F src/test_tclsh.c c4065ced25126e25c40122c5ff62dc89902ea617d72cdd27765151cdd7fcc477
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
F src/test_thread.c 269ea9e1fa5828dba550eb26f619aa18aedbc29fd92f8a5f6b93521fbb74a61c
F src/test_vdbecov.c f60c6f135ec42c0de013a1d5136777aa328a776d33277f92abac648930453d43
@ -616,7 +619,7 @@ F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
F src/util.c 3f27a1eae01c8bbbb8cdef2f26bd8e6a2a7db08106ef7c3dcc990787a5da6e86
F src/vacuum.c 454973a59fb20bb982efc2df568a098616db6328a0491b6e84e2e07f7333db45
F src/vdbe.c 39755f468a623af5e805c65a9ad7edb7c45fd78239fd58a319c7db8dfacc302b
F src/vdbe.c a4b6736b22ccb9e875dea4350ea1666276500b4d6a27eed9c7d000faa1fea163
F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
F src/vdbeInt.h 38206c8dd6b60ff03d9fd4f626b1b4fd0eef7cdc44f2fc2c1973b0f932a3f26b
F src/vdbeapi.c aa5aaf2c37676b83af5724c6cd8207a3064ed46a217fd180957f75ac84f7a2a5
@ -635,7 +638,7 @@ F src/where.c da3981a12e9eb5a71d32bab60ac1957fd4aa337aaea07ca8019b01f8788f442a
F src/whereInt.h 9248161dd004f625ce5d3841ca9b99fed3fc8d61522cf76340fc5217dbe1375b
F src/wherecode.c 0208553a0602146b5640747c0e3f7a8c785108c2d06a160b69f23491e9dc781e
F src/whereexpr.c e5fdac355deef93a821f03b90770f92f2be833e92bbdeff8ac1b6c2ae1f74356
F src/window.c 420167512050a0dfc0f0115b9f0c7d299da9759c9bb2ae83a61fb8d730a5707f
F src/window.c a5417de85a13e1f47bfb33c0bae5ae0ded5d68b146f4986c3d89d10a04f2c262
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7
@ -853,12 +856,12 @@ F test/e_blobbytes.test 439a945953b35cb6948a552edaec4dc31fd70a05
F test/e_blobclose.test 4b3c8c60c2171164d472059c73e9f3c1844bb66d
F test/e_blobopen.test e95e1d40f995056f6f322cd5e1a1b83a27e1a145
F test/e_blobwrite.test f87ff598b67af5b3ec002a8d83e804dc8d23808e88cf0080c176612fc9ffce14
F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579
F test/e_changes.test 6ba336a796db32f890e50197ab6a8fe5e6017e431fc9082702c246120cd58d55
F test/e_createtable.test 7997c0106c181243e0ac7db7ba8b9ae7233d0bfb0188605650322a7a02ea326e
F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
F test/e_droptrigger.test 235c610f8bf8ec44513e222b9085c7e49fad65ad0c1975ac2577109dd06fd8fa
F test/e_dropview.test 74e405df7fa0f762e0c9445b166fe03955856532e2bb234c372f7c51228d75e7
F test/e_expr.test 6ba7a51ece7b3e7fc145f14f924eed25ebb5a24e7b8596c78f3838d372cf0385
F test/e_expr.test e164550b9f8fd9c130283d1eae692dff9e2ba67f4dbd35f7325021f5d4b8851c
F test/e_fkey.test 351c7b989e5aefcc339ef5fc78dc4738442bd247a392cd67d81c2881000c369e
F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
@ -866,7 +869,7 @@ F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a42
F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8
F test/e_select.test c5425a423da06d0494119db8361ebfc6de302929f7546ca596d56224137e0360
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10
F test/e_totalchanges.test 1daded1db6867991c10b53a18436b2602f41ad82a2b8c2e1ed5eb7d1ad15edaf
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
F test/e_uri.test 47eeb2960e74613f0f8722b2f13aef08fde69daa16e5380ac93df84dac8b1f72
F test/e_vacuum.test 0d8832a2ce92350db0d0cff47b419465fd9772562e1f77ff7d9478c07a4980d2
@ -1057,7 +1060,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
F test/fuzzdata8.db 270cbd5fc46e1bf05e1d8a9ca8a6283df2b9a6d204c6135b51a11f39db21e0da
F test/fuzzdata8.db 81c9cfdd1c9dad84c1dbefb0a22cf31b685b8255031bc3827a6926412b0dc6f1
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc
@ -1448,7 +1451,7 @@ F test/tabfunc01.test d6821e7042e5653104dac0c63d75eff24a2415ab1889fc68b5db7fde59
F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132
F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
F test/tclsqlite.test 316c96f974f0e6d7480186e3f5bb53413e5ee5480596544a97484888912a365c
F test/tclsqlite.test 97cda6e4843e9f3e06c56f656d9b77ee0178fe1ee33fb09a6eeae8f125757ac1
F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08
F test/tempdb2.test 353864e96fd3ae2f70773d0ffbf8b1fe48589b02c2ec05013b540879410c3440
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
@ -1922,8 +1925,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 968aed690ba7240f8a256f5ba679cc971f432ff9af0ff99744824af79b952545
Q +2dd61dd97b0326b59b0bc3c83b4d4b9acf811c5acae4d1003e7525ba7a26daf5
R 646f691d304e0a026b7432ed79848447
P 15b105c520968855ad960d8929f80af9e9bedc155237af9af1956f7b546947f2 99d6bb22e8735681443bfe67287aa15ce2c57d0d63e304abf8aa01fde50dd021
R 49a56387d26f2bce27d3217e1e0550b1
U larrybr
Z d0aaf8bc6b08262fe824a57812c4fb12
Z f54f51b048cd8993f1718034d535befc

View File

@ -1 +1 @@
15b105c520968855ad960d8929f80af9e9bedc155237af9af1956f7b546947f2
9e00f9f7c03c192a3fb6b22851db0626515c59daac5ce6520229c42c838bf5b7

View File

@ -647,8 +647,7 @@ void sqlite3AlterRenameColumn(
"UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) "
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' "
" AND (type != 'index' OR tbl_name = %Q)"
" AND sql NOT LIKE 'create virtual%%'",
" AND (type != 'index' OR tbl_name = %Q)",
zDb,
zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1,
pTab->zName
@ -1498,7 +1497,7 @@ static void renameColumnFunc(
sqlite3WalkSelect(&sWalker, pSelect);
}
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
}else if( ALWAYS(IsOrdinaryTable(sParse.pNewTable)) ){
}else if( IsOrdinaryTable(sParse.pNewTable) ){
/* A regular table */
int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
FKey *pFKey;

View File

@ -7096,7 +7096,7 @@ static int rebuildPage(
assert( i<iEnd );
j = get2byte(&aData[hdr+5]);
if( j>(u32)usableSize ){ j = 0; }
if( NEVER(j>(u32)usableSize) ){ j = 0; }
memcpy(&pTmp[j], &aData[j], usableSize - j);
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
@ -7327,7 +7327,7 @@ static int editPage(
pData = &aData[get2byteNotZero(&aData[hdr+5])];
if( pData<pBegin ) goto editpage_fail;
if( pData>pPg->aDataEnd ) goto editpage_fail;
if( NEVER(pData>pPg->aDataEnd) ) goto editpage_fail;
/* Add cells to the start of the page */
if( iNew<iOld ){
@ -8733,7 +8733,7 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
do{
rc = btreeGetPage(pBt, ovflPgno, &pPage, 0);
if( rc ) return rc;
if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 ){
if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){
rc = SQLITE_CORRUPT_BKPT;
}else{
if( iOffset+ovflPageSize<(u32)nTotal ){

View File

@ -3866,6 +3866,7 @@ static int exprCodeInlineFunction(
** Test-only SQL functions that are only usable if enabled
** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS
*/
#if !defined(SQLITE_UNTESTABLE)
case INLINEFUNC_expr_compare: {
/* Compare two expressions using sqlite3ExprCompare() */
assert( nFarg==2 );
@ -3899,7 +3900,6 @@ static int exprCodeInlineFunction(
break;
}
#ifdef SQLITE_DEBUG
case INLINEFUNC_affinity: {
/* The AFFINITY() function evaluates to a string that describes
** the type affinity of the argument. This is used for testing of
@ -3913,7 +3913,7 @@ static int exprCodeInlineFunction(
(aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
break;
}
#endif
#endif /* !defined(SQLITE_UNTESTABLE) */
}
return target;
}

View File

@ -571,9 +571,9 @@ static void last_insert_rowid(
/*
** Implementation of the changes() SQL function.
**
** IMP: R-62073-11209 The changes() SQL function is a wrapper
** around the sqlite3_changes64() C/C++ function and hence follows the same
** rules for counting changes.
** IMP: R-32760-32347 The changes() SQL function is a wrapper
** around the sqlite3_changes64() C/C++ function and hence follows the
** same rules for counting changes.
*/
static void changes(
sqlite3_context *context,
@ -596,8 +596,8 @@ static void total_changes(
){
sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2);
/* IMP: R-52756-41993 This function was a wrapper around the
** sqlite3_total_changes() C/C++ interface. */
/* IMP: R-11217-42568 This function is a wrapper around the
** sqlite3_total_changes64() C/C++ interface. */
sqlite3_result_int64(context, sqlite3_total_changes64(db));
}
@ -2123,12 +2123,12 @@ void sqlite3RegisterBuiltinFunctions(void){
*/
static FuncDef aBuiltinFunc[] = {
/***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/
#if !defined(SQLITE_UNTESTABLE)
TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0),
TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0),
TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0),
#ifdef SQLITE_DEBUG
TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0),
#endif
TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0),
#endif /* !defined(SQLITE_UNTESTABLE) */
/***** Regular functions *****/
#ifdef SQLITE_SOUNDEX
FUNCTION(soundex, 1, 0, 0, soundexFunc ),

View File

@ -508,7 +508,7 @@ static int memdbOpen(
if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFd, flags, pOutFlags);
}
memset(pFile, 0, sizeof(*p));
memset(pFile, 0, sizeof(*pFile));
szName = sqlite3Strlen30(zName);
if( szName>1 && zName[0]=='/' ){
int i;

View File

@ -679,8 +679,8 @@ struct Pager {
i16 nReserve; /* Number of unused bytes at end of each page */
u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */
u32 sectorSize; /* Assumed sector size during rollback */
int pageSize; /* Number of bytes in a page */
Pgno mxPgno; /* Maximum allowed size of the database */
i64 pageSize; /* Number of bytes in a page */
i64 journalSizeLimit; /* Size limit for persistent journal files */
char *zFilename; /* Name of the database file */
char *zJournal; /* Name of the journal file */
@ -6737,8 +6737,8 @@ int sqlite3PagerRefcount(Pager *pPager){
** used by the pager and its associated cache.
*/
int sqlite3PagerMemUsed(Pager *pPager){
int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr)
+ 5*sizeof(void*);
int perPageSize = pPager->pageSize + pPager->nExtra
+ (int)(sizeof(PgHdr) + 5*sizeof(void*));
return perPageSize*sqlite3PcachePagecount(pPager->pPCache)
+ sqlite3MallocSize(pPager)
+ pPager->pageSize;
@ -6932,14 +6932,14 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
}
pPager->nSavepoint = nNew;
/* If this is a release of the outermost savepoint, truncate
** the sub-journal to zero bytes in size. */
/* Truncate the sub-journal so that it only includes the parts
** that are still in use. */
if( op==SAVEPOINT_RELEASE ){
PagerSavepoint *pRel = &pPager->aSavepoint[nNew];
if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){
/* Only truncate if it is an in-memory sub-journal. */
if( sqlite3JournalIsInMemory(pPager->sjfd) ){
i64 sz = (pPager->pageSize+4)*pRel->iSubRec;
i64 sz = (pPager->pageSize+4)*(i64)pRel->iSubRec;
rc = sqlite3OsTruncate(pPager->sjfd, sz);
assert( rc==SQLITE_OK );
}

View File

@ -347,6 +347,9 @@ static void addWhereTerm(
pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);
pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2);
assert( pE2!=0 || pEq==0 ); /* Due to db->mallocFailed test
** in sqlite3DbMallocRawNN() called from
** sqlite3PExpr(). */
if( pEq && isOuterJoin ){
ExprSetProperty(pEq, EP_FromJoin);
assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );

View File

@ -635,19 +635,38 @@ static int strlenChar(const char *z){
}
/*
** Return true if zFile does not exist or if it is not an ordinary file.
** Return open FILE * if zFile exists, can be opened for read
** and is an ordinary file or a character stream source.
** Otherwise return 0.
*/
static FILE * openChrSource(const char *zFile){
#ifdef _WIN32
# define notNormalFile(X) 0
struct _stat x = {0};
# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
/* On Windows, open first, then check the stream nature. This order
** is necessary because _stat() and sibs, when checking a named pipe,
** effectively break the pipe as its supplier sees it. */
FILE *rv = fopen(zFile, "rb");
if( rv==0 ) return 0;
if( _fstat(_fileno(rv), &x) != 0
|| !STAT_CHR_SRC(x.st_mode)){
fclose(rv);
rv = 0;
}
return rv;
#else
static int notNormalFile(const char *zFile){
struct stat x;
int rc;
memset(&x, 0, sizeof(x));
rc = stat(zFile, &x);
return rc || !S_ISREG(x.st_mode);
}
struct stat x = {0};
int rc = stat(zFile, &x);
# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
if( rc!=0 ) return 0;
if( STAT_CHR_SRC(x.st_mode) ){
return fopen(zFile, "rb");
}else{
return 0;
}
#endif
#undef STAT_CHR_SRC
}
/*
** This routine reads a line of text from FILE in, stores
@ -1203,7 +1222,7 @@ struct ShellState {
#define SHFLG_Newlines 0x00000010 /* .dump --newline flag */
#define SHFLG_CountChanges 0x00000020 /* .changes setting */
#define SHFLG_Echo 0x00000040 /* .echo or --echo setting */
#define SHFLG_HeaderSet 0x00000080 /* .header has been used */
#define SHFLG_HeaderSet 0x00000080 /* showHeader has been specified */
#define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */
#define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */
@ -9239,7 +9258,7 @@ static int do_meta_command(char *zLine, ShellState *p){
pclose(p->in);
}
#endif
}else if( notNormalFile(azArg[1]) || (p->in = fopen(azArg[1], "rb"))==0 ){
}else if( (p->in = openChrSource(azArg[1]))==0 ){
utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
@ -10601,18 +10620,15 @@ meta_command_exit:
/* Line scan result and intermediate states (supporting scan resumption)
*/
typedef enum {
QSS_InPlain = 0, QSS_InQuote = 1, QSS_InBlockComment = 2,
QSS_NoDark = 0, QSS_HasDark = 1<<2, QSS_EndingSemi = 1<<3,
QSS_ScanMask = 0x3, QSS_DarkMask = 1<<2,
QSS_CharShift = 4, QSS_StateMask = ((1<<QSS_CharShift)-1),
QSS_HasDark = 1<<CHAR_BIT, QSS_EndingSemi = 2<<CHAR_BIT,
QSS_CharMask = (1<<CHAR_BIT)-1, QSS_ScanMask = 3<<CHAR_BIT,
QSS_Start = 0
} QuickScanState;
#define QSS_STATE(qss) ((qss) & QSS_ScanMask)
#define QSS_SETV(qss, newst) (newst | ((qss) & (QSS_StateMask^QSS_ScanMask)))
#define QSS_PLAINWHITE(qss) (((qss)&~QSS_EndingSemi)==QSS_NoDark)
#define QSS_SETV(qss, newst) ((newst) | ((qss) & QSS_ScanMask))
#define QSS_INPLAIN(qss) (((qss)&QSS_CharMask)==QSS_Start)
#define QSS_PLAINWHITE(qss) (((qss)&~QSS_EndingSemi)==QSS_Start)
#define QSS_PLAINDARK(qss) (((qss)&~QSS_EndingSemi)==QSS_HasDark)
#define QSS_SEMITERM(qss) \
(((qss)&(QSS_ScanMask|QSS_EndingSemi))==QSS_EndingSemi)
#define QSS_SEMITERM(qss) (((qss)&~QSS_HasDark)==QSS_EndingSemi)
/*
** Scan line for classification to guide shell's handling.
@ -10621,69 +10637,69 @@ typedef enum {
*/
static QuickScanState quickscan(char *zLine, QuickScanState qss){
char cin;
switch( QSS_STATE(qss) ){
case QSS_InPlain:
InPlainSet:
qss = QSS_SETV(qss, QSS_InPlain);
char cWait = (char)qss; /* intentional narrowing loss */
if( cWait==0 ){
PlainScan:
while (cin = *zLine++){
if( IsSpace(cin) )
continue;
switch (cin){
case '-':
if( *zLine=='-' ){
while((cin = *++zLine)!=0 ){
if( cin=='\n')
continue;
}
return qss;
}
break;
if( *zLine!='-' )
break;
while((cin = *++zLine)!=0 )
if( cin=='\n')
goto PlainScan;
return qss;
case ';':
qss |= QSS_EndingSemi;
continue;
case '/':
if( *zLine=='*' ){
++zLine;
qss = QSS_SETV(qss, QSS_InBlockComment);
goto InBlockComment;
cWait = '*';
qss = QSS_SETV(qss, cWait);
goto TermScan;
}
break;
case '[':
cin = ']';
/* fall thru */
case '`': case '\'': case '"':
qss = qss & ~QSS_EndingSemi | QSS_HasDark;
qss = QSS_SETV(qss, QSS_InQuote) | (cin<<QSS_CharShift);
goto InQuote;
cWait = cin;
qss = QSS_HasDark | cWait;
goto TermScan;
default:
break;
}
qss = qss & ~QSS_EndingSemi | QSS_HasDark;
qss = (qss & ~QSS_EndingSemi) | QSS_HasDark;
}
break;
case QSS_InQuote:
InQuote: {
char cLeave = qss >> QSS_CharShift;
while (cin = *zLine++){
if( cin==cLeave ){
if(*zLine==cLeave && cLeave!=']')
}else{
TermScan:
while (cin = *zLine++){
if( cin==cWait ){
switch( cWait ){
case '*':
if( *zLine != '/' )
continue;
++zLine;
cWait = 0;
qss = QSS_SETV(qss, 0);
goto PlainScan;
case '`': case '\'': case '"':
if(*zLine==cWait){
++zLine;
else
goto InPlainSet;
continue;
}
/* fall thru */
case ']':
cWait = 0;
qss = QSS_SETV(qss, 0);
goto PlainScan;
default: assert(0);
}
}
}
break;
case QSS_InBlockComment:
InBlockComment:
while (cin = *zLine++){
if( cin=='*' && *zLine=='/' ){
++zLine;
goto InPlainSet;
}
}
break;
default:;
}
return qss;
}
@ -10784,7 +10800,7 @@ static int process_input(ShellState *p){
int rc; /* Error code */
int errCnt = 0; /* Number of errors seen */
int startline = 0; /* Line number for start of current input */
QuickScanState qss = QSS_InPlain; /* Accumulated line status (so far) */
QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
p->lineno = 0;
while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
@ -10800,7 +10816,7 @@ static int process_input(ShellState *p){
seenInterrupt = 0;
}
p->lineno++;
if( QSS_STATE(qss)==QSS_InPlain
if( QSS_INPLAIN(qss)
&& line_is_command_terminator(zLine)
&& line_is_complete(zSql, nSql) ){
memcpy(zLine,";",2);
@ -11502,8 +11518,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
"%s",cmdline_option_value(argc,argv,++i));
}else if( strcmp(z,"-header")==0 ){
data.showHeader = 1;
}else if( strcmp(z,"-noheader")==0 ){
ShellSetFlag(&data, SHFLG_HeaderSet);
}else if( strcmp(z,"-noheader")==0 ){
data.showHeader = 0;
ShellSetFlag(&data, SHFLG_HeaderSet);
}else if( strcmp(z,"-echo")==0 ){
ShellSetFlag(&data, SHFLG_Echo);
}else if( strcmp(z,"-eqp")==0 ){

View File

@ -4985,7 +4985,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
#endif
#ifdef SQLITE_OMIT_VIRTUALTABLE
# define sqlite3VtabClear(Y)
# define sqlite3VtabClear(D,T)
# define sqlite3VtabSync(X,Y) SQLITE_OK
# define sqlite3VtabRollback(X)
# define sqlite3VtabCommit(X)

View File

@ -181,6 +181,7 @@ struct SqliteDb {
int nVMStep; /* Another statistic for most recent operation */
int nTransaction; /* Number of nested [transaction] methods */
int openFlags; /* Flags used to open. (SQLITE_OPEN_URI) */
int nRef; /* Delete object when this reaches 0 */
#ifdef SQLITE_TEST
int bLegacyPrepare; /* True to use sqlite3_prepare() */
#endif
@ -517,64 +518,84 @@ static void flushStmtCache(SqliteDb *pDb){
pDb->stmtList = 0;
}
/*
** Increment the reference counter on the SqliteDb object. The reference
** should be released by calling delDatabaseRef().
*/
static void addDatabaseRef(SqliteDb *pDb){
pDb->nRef++;
}
/*
** Decrement the reference counter associated with the SqliteDb object.
** If it reaches zero, delete the object.
*/
static void delDatabaseRef(SqliteDb *pDb){
assert( pDb->nRef>0 );
pDb->nRef--;
if( pDb->nRef==0 ){
flushStmtCache(pDb);
closeIncrblobChannels(pDb);
sqlite3_close(pDb->db);
while( pDb->pFunc ){
SqlFunc *pFunc = pDb->pFunc;
pDb->pFunc = pFunc->pNext;
assert( pFunc->pDb==pDb );
Tcl_DecrRefCount(pFunc->pScript);
Tcl_Free((char*)pFunc);
}
while( pDb->pCollate ){
SqlCollate *pCollate = pDb->pCollate;
pDb->pCollate = pCollate->pNext;
Tcl_Free((char*)pCollate);
}
if( pDb->zBusy ){
Tcl_Free(pDb->zBusy);
}
if( pDb->zTrace ){
Tcl_Free(pDb->zTrace);
}
if( pDb->zTraceV2 ){
Tcl_Free(pDb->zTraceV2);
}
if( pDb->zProfile ){
Tcl_Free(pDb->zProfile);
}
if( pDb->zBindFallback ){
Tcl_Free(pDb->zBindFallback);
}
if( pDb->zAuth ){
Tcl_Free(pDb->zAuth);
}
if( pDb->zNull ){
Tcl_Free(pDb->zNull);
}
if( pDb->pUpdateHook ){
Tcl_DecrRefCount(pDb->pUpdateHook);
}
if( pDb->pPreUpdateHook ){
Tcl_DecrRefCount(pDb->pPreUpdateHook);
}
if( pDb->pRollbackHook ){
Tcl_DecrRefCount(pDb->pRollbackHook);
}
if( pDb->pWalHook ){
Tcl_DecrRefCount(pDb->pWalHook);
}
if( pDb->pCollateNeeded ){
Tcl_DecrRefCount(pDb->pCollateNeeded);
}
Tcl_Free((char*)pDb);
}
}
/*
** TCL calls this procedure when an sqlite3 database command is
** deleted.
*/
static void SQLITE_TCLAPI DbDeleteCmd(void *db){
SqliteDb *pDb = (SqliteDb*)db;
flushStmtCache(pDb);
closeIncrblobChannels(pDb);
sqlite3_close(pDb->db);
while( pDb->pFunc ){
SqlFunc *pFunc = pDb->pFunc;
pDb->pFunc = pFunc->pNext;
assert( pFunc->pDb==pDb );
Tcl_DecrRefCount(pFunc->pScript);
Tcl_Free((char*)pFunc);
}
while( pDb->pCollate ){
SqlCollate *pCollate = pDb->pCollate;
pDb->pCollate = pCollate->pNext;
Tcl_Free((char*)pCollate);
}
if( pDb->zBusy ){
Tcl_Free(pDb->zBusy);
}
if( pDb->zTrace ){
Tcl_Free(pDb->zTrace);
}
if( pDb->zTraceV2 ){
Tcl_Free(pDb->zTraceV2);
}
if( pDb->zProfile ){
Tcl_Free(pDb->zProfile);
}
if( pDb->zBindFallback ){
Tcl_Free(pDb->zBindFallback);
}
if( pDb->zAuth ){
Tcl_Free(pDb->zAuth);
}
if( pDb->zNull ){
Tcl_Free(pDb->zNull);
}
if( pDb->pUpdateHook ){
Tcl_DecrRefCount(pDb->pUpdateHook);
}
if( pDb->pPreUpdateHook ){
Tcl_DecrRefCount(pDb->pPreUpdateHook);
}
if( pDb->pRollbackHook ){
Tcl_DecrRefCount(pDb->pRollbackHook);
}
if( pDb->pWalHook ){
Tcl_DecrRefCount(pDb->pWalHook);
}
if( pDb->pCollateNeeded ){
Tcl_DecrRefCount(pDb->pCollateNeeded);
}
Tcl_Free((char*)pDb);
delDatabaseRef(pDb);
}
/*
@ -1246,6 +1267,7 @@ static int SQLITE_TCLAPI DbTransPostCmd(
}
pDb->disableAuth--;
delDatabaseRef(pDb);
return rc;
}
@ -1579,6 +1601,7 @@ static void dbEvalInit(
Tcl_IncrRefCount(pArray);
}
p->evalFlags = evalFlags;
addDatabaseRef(p->pDb);
}
/*
@ -1719,6 +1742,7 @@ static void dbEvalFinalize(DbEvalContext *p){
}
Tcl_DecrRefCount(p->pSql);
dbReleaseColumnNames(p);
delDatabaseRef(p->pDb);
}
/*
@ -3435,6 +3459,7 @@ deserialize_error:
** opened above. If not using NRE, evaluate the script directly, then
** call function DbTransPostCmd() to commit (or rollback) the transaction
** or savepoint. */
addDatabaseRef(pDb); /* DbTransPostCmd() calls delDatabaseRef() */
if( DbUseNre() ){
Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0);
(void)Tcl_NREvalObj(interp, pScript, 0);
@ -3842,6 +3867,7 @@ static int SQLITE_TCLAPI DbMain(
}else{
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
}
p->nRef = 1;
return TCL_OK;
}

View File

@ -87,6 +87,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
extern int Sqlitetestintarray_Init(Tcl_Interp*);
extern int Sqlitetestvfs_Init(Tcl_Interp *);
extern int Sqlitetestrtree_Init(Tcl_Interp*);
extern int Sqlitetestrtreedoc_Init(Tcl_Interp*);
extern int Sqlitequota_Init(Tcl_Interp*);
extern int Sqlitemultiplex_Init(Tcl_Interp*);
extern int SqliteSuperlock_Init(Tcl_Interp*);
@ -156,6 +157,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
Sqlitetestintarray_Init(interp);
Sqlitetestvfs_Init(interp);
Sqlitetestrtree_Init(interp);
Sqlitetestrtreedoc_Init(interp);
Sqlitequota_Init(interp);
Sqlitemultiplex_Init(interp);
SqliteSuperlock_Init(interp);

View File

@ -8367,6 +8367,11 @@ abort_due_to_error:
rc = SQLITE_CORRUPT_BKPT;
}
assert( rc );
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeTrace ){
printf("ABORT-due-to-error. rc=%d\n", rc);
}
#endif
if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
}

View File

@ -1066,6 +1066,9 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
("New window-function subquery in FROM clause of (%u/%p)\n",
p->selId, p));
p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside
** of sqlite3DbMallocRawNN() called from
** sqlite3SrcListAppend() */
if( p->pSrc ){
Table *pTab2;
p->pSrc->a[0].pSelect = pSub;

View File

@ -25,10 +25,10 @@ proc do_changes_test {tn sql res} {
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-15996-49369 This function returns the number of rows
# modified, inserted or deleted by the most recently completed INSERT,
# UPDATE or DELETE statement on the database connection specified by the
# only parameter.
# EVIDENCE-OF: R-58361-29089 The changes() function returns the number
# of database rows that were changed or inserted or deleted by the most
# recently completed INSERT, DELETE, or UPDATE statement, exclusive of
# statements in lower-level triggers.
#
do_execsql_test 1.0 {
CREATE TABLE t1(a, b);
@ -108,7 +108,7 @@ foreach {tn schema} {
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-44877-05564 Executing any other type of SQL statement
# X-EVIDENCE-OF: R-44877-05564 Executing any other type of SQL statement
# does not modify the value returned by this function.
#
reset_db

View File

@ -84,12 +84,12 @@ db func regexp -argcount 2 regexfunc
# in the documentation exist and that the relative precedences of the
# operators are also as the documentation suggests.
#
# EVIDENCE-OF: R-15514-65163 SQLite understands the following binary
# X-EVIDENCE-OF: R-15514-65163 SQLite understands the following binary
# operators, in order from highest to lowest precedence: || * / % + -
# << >> & | < <= > >= = == != <> IS IS
# NOT IN LIKE GLOB MATCH REGEXP AND OR
#
# EVIDENCE-OF: R-38759-38789 Operators IS and IS NOT have the same
# X-EVIDENCE-OF: R-38759-38789 Operators IS and IS NOT have the same
# precedence as =.
#
@ -180,7 +180,7 @@ do_execsql_test e_expr-1.6 {
# Check that the four unary prefix operators mentioned in the
# documentation exist.
#
# EVIDENCE-OF: R-13958-53419 Supported unary prefix operators are these:
# X-EVIDENCE-OF: R-13958-53419 Supported unary prefix operators are these:
# - + ~ NOT
#
do_execsql_test e_expr-2.1 { SELECT - 10 } {-10}
@ -368,7 +368,7 @@ db collate reverse reverse_collate
# EVIDENCE-OF: R-59577-33471 The COLLATE operator is a unary postfix
# operator that assigns a collating sequence to an expression.
#
# EVIDENCE-OF: R-36231-30731 The COLLATE operator has a higher
# X-EVIDENCE-OF: R-36231-30731 The COLLATE operator has a higher
# precedence (binds more tightly) than any binary operator and any unary
# prefix operator except "~".
#
@ -860,7 +860,7 @@ foreach {tn x expr res nEval} {
} [list $nEval $res]
}
# EVIDENCE-OF: R-05155-34454 The precedence of the BETWEEN operator is
# X-EVIDENCE-OF: R-05155-34454 The precedence of the BETWEEN operator is
# the same as the precedence as operators == and != and LIKE and groups
# left to right.
#

View File

@ -32,10 +32,9 @@ do_execsql_test 1.0 {
#--------------------------------------------------------------------------
# EVIDENCE-OF: R-65438-26258 This function returns the total number of
# rows inserted, modified or deleted by all INSERT, UPDATE or DELETE
# statements completed since the database connection was opened,
# including those executed as part of trigger programs.
# EVIDENCE-OF: R-38914-26427 The total_changes() function returns the
# number of row changes caused by INSERT, UPDATE or DELETE statements
# since the current database connection was opened.
#
# 1.1.*: different types of I/U/D statements,
# 1.2.*: trigger programs.

Binary file not shown.

View File

@ -848,4 +848,40 @@ do_catchsql_test 19.911 {
} {1 {invalid command name "bind_fallback_does_not_exist"}}
db bind_fallback {}
#-------------------------------------------------------------------------
do_test 20.0 {
db transaction {
db close
}
} {}
do_test 20.1 {
sqlite3 db test.db
set rc [catch {
db eval {SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3} { db close }
} msg]
list $rc $msg
} {1 {invalid command name "db"}}
proc closedb {} {
db close
return 10
}
proc func1 {} { return 1 }
sqlite3 db test.db
db func closedb closedb
db func func1 func1
do_test 20.2 {
set rc [catch {
db eval {
SELECT closedb(),func1() UNION ALL SELECT 20,30 UNION ALL SELECT 30,40
}
} msg]
list $rc $msg
} {0 {10 1 20 30 30 40}}
finish_test