1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Import all the latest trunk changes into the sessions branch.

FossilOrigin-Name: 87a0eab5d98fff93aa2147c04c4af27be42fb365
This commit is contained in:
drh
2012-04-18 01:41:37 +00:00
48 changed files with 1562 additions and 476 deletions

18
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.62 for sqlite 3.7.11. # Generated by GNU Autoconf 2.62 for sqlite 3.7.12.
# #
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package. # Identity of this package.
PACKAGE_NAME='sqlite' PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite' PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.7.11' PACKAGE_VERSION='3.7.12'
PACKAGE_STRING='sqlite 3.7.11' PACKAGE_STRING='sqlite 3.7.12'
PACKAGE_BUGREPORT='' PACKAGE_BUGREPORT=''
# Factoring default headers for most tests. # Factoring default headers for most tests.
@@ -1485,7 +1485,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures sqlite 3.7.11 to adapt to many kinds of systems. \`configure' configures sqlite 3.7.12 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1550,7 +1550,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.7.11:";; short | recursive ) echo "Configuration of sqlite 3.7.12:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@@ -1666,7 +1666,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
sqlite configure 3.7.11 sqlite configure 3.7.12
generated by GNU Autoconf 2.62 generated by GNU Autoconf 2.62
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1680,7 +1680,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.7.11, which was It was created by sqlite $as_me 3.7.12, which was
generated by GNU Autoconf 2.62. Invocation command line was generated by GNU Autoconf 2.62. Invocation command line was
$ $0 $@ $ $0 $@
@@ -14032,7 +14032,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by sqlite $as_me 3.7.11, which was This file was extended by sqlite $as_me 3.7.12, which was
generated by GNU Autoconf 2.62. Invocation command line was generated by GNU Autoconf 2.62. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -14085,7 +14085,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\ ac_cs_version="\\
sqlite config.status 3.7.11 sqlite config.status 3.7.12
configured by $0, generated by GNU Autoconf 2.62, configured by $0, generated by GNU Autoconf 2.62,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"

View File

@@ -110,7 +110,10 @@ static int icuOpen(
*ppCursor = 0; *ppCursor = 0;
if( nInput<0 ){ if( zInput==0 ){
nInput = 0;
zInput = "";
}else if( nInput<0 ){
nInput = strlen(zInput); nInput = strlen(zInput);
} }
nChar = nInput+1; nChar = nInput+1;

View File

@@ -22,7 +22,8 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#ifdef SQLITE_TEST #if defined(SQLITE_TEST)
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
/* Required so that the "ifdef SQLITE_ENABLE_FTS3" below works */ /* Required so that the "ifdef SQLITE_ENABLE_FTS3" below works */
#include "fts3Int.h" #include "fts3Int.h"
@@ -530,4 +531,5 @@ int Sqlitetestfts3_Init(Tcl_Interp *interp){
); );
return TCL_OK; return TCL_OK;
} }
#endif /* SQLITE_ENABLE_FTS3 || SQLITE_ENABLE_FTS4 */
#endif /* ifdef SQLITE_TEST */ #endif /* ifdef SQLITE_TEST */

View File

@@ -3739,7 +3739,6 @@ static int fts3IncrmergeAppend(
pLeaf->key.n = 0; pLeaf->key.n = 0;
pLeaf->block.n = 0; pLeaf->block.n = 0;
nPrefix = 0;
nSuffix = nTerm; nSuffix = nTerm;
nSpace = 1; nSpace = 1;
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;

View File

@@ -182,6 +182,19 @@ struct Rtree {
#define RTREE_COORD_REAL32 0 #define RTREE_COORD_REAL32 0
#define RTREE_COORD_INT32 1 #define RTREE_COORD_INT32 1
/*
** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will
** only deal with integer coordinates. No floating point operations
** will be done.
*/
#ifdef SQLITE_RTREE_INT_ONLY
typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */
typedef int RtreeValue; /* Low accuracy coordinate */
#else
typedef double RtreeDValue; /* High accuracy coordinate */
typedef float RtreeValue; /* Low accuracy coordinate */
#endif
/* /*
** The minimum number of cells allowed for a node is a third of the ** The minimum number of cells allowed for a node is a third of the
** maximum. In Gutman's notation: ** maximum. In Gutman's notation:
@@ -217,20 +230,25 @@ struct RtreeCursor {
}; };
union RtreeCoord { union RtreeCoord {
float f; RtreeValue f;
int i; int i;
}; };
/* /*
** The argument is an RtreeCoord. Return the value stored within the RtreeCoord ** The argument is an RtreeCoord. Return the value stored within the RtreeCoord
** formatted as a double. This macro assumes that local variable pRtree points ** formatted as a RtreeDValue (double or int64). This macro assumes that local
** to the Rtree structure associated with the RtreeCoord. ** variable pRtree points to the Rtree structure associated with the
** RtreeCoord.
*/ */
#define DCOORD(coord) ( \ #ifdef SQLITE_RTREE_INT_ONLY
(pRtree->eCoordType==RTREE_COORD_REAL32) ? \ # define DCOORD(coord) ((RtreeDValue)coord.i)
((double)coord.f) : \ #else
((double)coord.i) \ # define DCOORD(coord) ( \
) (pRtree->eCoordType==RTREE_COORD_REAL32) ? \
((double)coord.f) : \
((double)coord.i) \
)
#endif
/* /*
** A search constraint. ** A search constraint.
@@ -238,8 +256,8 @@ union RtreeCoord {
struct RtreeConstraint { struct RtreeConstraint {
int iCoord; /* Index of constrained coordinate */ int iCoord; /* Index of constrained coordinate */
int op; /* Constraining operation */ int op; /* Constraining operation */
double rValue; /* Constraint value. */ RtreeDValue rValue; /* Constraint value. */
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *); int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */ sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */
}; };
@@ -287,10 +305,10 @@ struct RtreeCell {
*/ */
struct RtreeMatchArg { struct RtreeMatchArg {
u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ u32 magic; /* Always RTREE_GEOMETRY_MAGIC */
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *); int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue*, int *);
void *pContext; void *pContext;
int nParam; int nParam;
double aParam[1]; RtreeDValue aParam[1];
}; };
/* /*
@@ -302,7 +320,7 @@ struct RtreeMatchArg {
** the geometry callback function). ** the geometry callback function).
*/ */
struct RtreeGeomCallback { struct RtreeGeomCallback {
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *); int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
void *pContext; void *pContext;
}; };
@@ -868,7 +886,7 @@ static int testRtreeGeom(
int *pbRes /* OUT: Test result */ int *pbRes /* OUT: Test result */
){ ){
int i; int i;
double aCoord[RTREE_MAX_DIMENSIONS*2]; RtreeDValue aCoord[RTREE_MAX_DIMENSIONS*2];
int nCoord = pRtree->nDim*2; int nCoord = pRtree->nDim*2;
assert( pConstraint->op==RTREE_MATCH ); assert( pConstraint->op==RTREE_MATCH );
@@ -898,8 +916,8 @@ static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){ for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){
RtreeConstraint *p = &pCursor->aConstraint[ii]; RtreeConstraint *p = &pCursor->aConstraint[ii];
double cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]); RtreeDValue cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]); RtreeDValue cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
@@ -951,7 +969,7 @@ static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
for(ii=0; ii<pCursor->nConstraint; ii++){ for(ii=0; ii<pCursor->nConstraint; ii++){
RtreeConstraint *p = &pCursor->aConstraint[ii]; RtreeConstraint *p = &pCursor->aConstraint[ii];
double coord = DCOORD(cell.aCoord[p->iCoord]); RtreeDValue coord = DCOORD(cell.aCoord[p->iCoord]);
int res; int res;
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
@@ -1149,9 +1167,12 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
}else{ }else{
RtreeCoord c; RtreeCoord c;
nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c); nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c);
#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
sqlite3_result_double(ctx, c.f); sqlite3_result_double(ctx, c.f);
}else{ }else
#endif
{
assert( pRtree->eCoordType==RTREE_COORD_INT32 ); assert( pRtree->eCoordType==RTREE_COORD_INT32 );
sqlite3_result_int(ctx, c.i); sqlite3_result_int(ctx, c.i);
} }
@@ -1198,7 +1219,7 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
/* Check that the blob is roughly the right size. */ /* Check that the blob is roughly the right size. */
nBlob = sqlite3_value_bytes(pValue); nBlob = sqlite3_value_bytes(pValue);
if( nBlob<(int)sizeof(RtreeMatchArg) if( nBlob<(int)sizeof(RtreeMatchArg)
|| ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0 || ((nBlob-sizeof(RtreeMatchArg))%sizeof(RtreeDValue))!=0
){ ){
return SQLITE_ERROR; return SQLITE_ERROR;
} }
@@ -1212,7 +1233,7 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
memcpy(p, sqlite3_value_blob(pValue), nBlob); memcpy(p, sqlite3_value_blob(pValue), nBlob);
if( p->magic!=RTREE_GEOMETRY_MAGIC if( p->magic!=RTREE_GEOMETRY_MAGIC
|| nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double)) || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(RtreeDValue))
){ ){
sqlite3_free(pGeom); sqlite3_free(pGeom);
return SQLITE_ERROR; return SQLITE_ERROR;
@@ -1284,7 +1305,11 @@ static int rtreeFilter(
break; break;
} }
}else{ }else{
#ifdef SQLITE_RTREE_INT_ONLY
p->rValue = sqlite3_value_int64(argv[ii]);
#else
p->rValue = sqlite3_value_double(argv[ii]); p->rValue = sqlite3_value_double(argv[ii]);
#endif
} }
} }
} }
@@ -1418,11 +1443,11 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
/* /*
** Return the N-dimensional volumn of the cell stored in *p. ** Return the N-dimensional volumn of the cell stored in *p.
*/ */
static float cellArea(Rtree *pRtree, RtreeCell *p){ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
float area = 1.0; RtreeDValue area = (RtreeDValue)1;
int ii; int ii;
for(ii=0; ii<(pRtree->nDim*2); ii+=2){ for(ii=0; ii<(pRtree->nDim*2); ii+=2){
area = (float)(area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]))); area = (area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
} }
return area; return area;
} }
@@ -1431,11 +1456,11 @@ static float cellArea(Rtree *pRtree, RtreeCell *p){
** Return the margin length of cell p. The margin length is the sum ** Return the margin length of cell p. The margin length is the sum
** of the objects size in each dimension. ** of the objects size in each dimension.
*/ */
static float cellMargin(Rtree *pRtree, RtreeCell *p){ static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
float margin = 0.0; RtreeDValue margin = (RtreeDValue)0;
int ii; int ii;
for(ii=0; ii<(pRtree->nDim*2); ii+=2){ for(ii=0; ii<(pRtree->nDim*2); ii+=2){
margin += (float)(DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
} }
return margin; return margin;
} }
@@ -1480,8 +1505,8 @@ static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
/* /*
** Return the amount cell p would grow by if it were unioned with pCell. ** Return the amount cell p would grow by if it were unioned with pCell.
*/ */
static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
float area; RtreeDValue area;
RtreeCell cell; RtreeCell cell;
memcpy(&cell, p, sizeof(RtreeCell)); memcpy(&cell, p, sizeof(RtreeCell));
area = cellArea(pRtree, &cell); area = cellArea(pRtree, &cell);
@@ -1490,7 +1515,7 @@ static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
} }
#if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT #if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT
static float cellOverlap( static RtreeDValue cellOverlap(
Rtree *pRtree, Rtree *pRtree,
RtreeCell *p, RtreeCell *p,
RtreeCell *aCell, RtreeCell *aCell,
@@ -1498,7 +1523,7 @@ static float cellOverlap(
int iExclude int iExclude
){ ){
int ii; int ii;
float overlap = 0.0; RtreeDValue overlap = 0.0;
for(ii=0; ii<nCell; ii++){ for(ii=0; ii<nCell; ii++){
#if VARIANT_RSTARTREE_CHOOSESUBTREE #if VARIANT_RSTARTREE_CHOOSESUBTREE
if( ii!=iExclude ) if( ii!=iExclude )
@@ -1508,10 +1533,9 @@ static float cellOverlap(
#endif #endif
{ {
int jj; int jj;
float o = 1.0; RtreeDValue o = (RtreeDValue)1;
for(jj=0; jj<(pRtree->nDim*2); jj+=2){ for(jj=0; jj<(pRtree->nDim*2); jj+=2){
double x1; RtreeDValue x1, x2;
double x2;
x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj]));
x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1]));
@@ -1520,7 +1544,7 @@ static float cellOverlap(
o = 0.0; o = 0.0;
break; break;
}else{ }else{
o = o * (float)(x2-x1); o = o * (x2-x1);
} }
} }
overlap += o; overlap += o;
@@ -1531,7 +1555,7 @@ static float cellOverlap(
#endif #endif
#if VARIANT_RSTARTREE_CHOOSESUBTREE #if VARIANT_RSTARTREE_CHOOSESUBTREE
static float cellOverlapEnlargement( static RtreeDValue cellOverlapEnlargement(
Rtree *pRtree, Rtree *pRtree,
RtreeCell *p, RtreeCell *p,
RtreeCell *pInsert, RtreeCell *pInsert,
@@ -1539,12 +1563,11 @@ static float cellOverlapEnlargement(
int nCell, int nCell,
int iExclude int iExclude
){ ){
double before; RtreeDValue before, after;
double after;
before = cellOverlap(pRtree, p, aCell, nCell, iExclude); before = cellOverlap(pRtree, p, aCell, nCell, iExclude);
cellUnion(pRtree, p, pInsert); cellUnion(pRtree, p, pInsert);
after = cellOverlap(pRtree, p, aCell, nCell, iExclude); after = cellOverlap(pRtree, p, aCell, nCell, iExclude);
return (float)(after-before); return (after-before);
} }
#endif #endif
@@ -1568,11 +1591,11 @@ static int ChooseLeaf(
int iCell; int iCell;
sqlite3_int64 iBest = 0; sqlite3_int64 iBest = 0;
float fMinGrowth = 0.0; RtreeDValue fMinGrowth = 0.0;
float fMinArea = 0.0; RtreeDValue fMinArea = 0.0;
#if VARIANT_RSTARTREE_CHOOSESUBTREE #if VARIANT_RSTARTREE_CHOOSESUBTREE
float fMinOverlap = 0.0; RtreeDValue fMinOverlap = 0.0;
float overlap; RtreeDValue overlap;
#endif #endif
int nCell = NCELL(pNode); int nCell = NCELL(pNode);
@@ -1603,8 +1626,8 @@ static int ChooseLeaf(
*/ */
for(iCell=0; iCell<nCell; iCell++){ for(iCell=0; iCell<nCell; iCell++){
int bBest = 0; int bBest = 0;
float growth; RtreeDValue growth;
float area; RtreeDValue area;
nodeGetCell(pRtree, pNode, iCell, &cell); nodeGetCell(pRtree, pNode, iCell, &cell);
growth = cellGrowth(pRtree, &cell, pCell); growth = cellGrowth(pRtree, &cell, pCell);
area = cellArea(pRtree, &cell); area = cellArea(pRtree, &cell);
@@ -1731,7 +1754,7 @@ static void LinearPickSeeds(
int i; int i;
int iLeftSeed = 0; int iLeftSeed = 0;
int iRightSeed = 1; int iRightSeed = 1;
float maxNormalInnerWidth = 0.0; RtreeDValue maxNormalInnerWidth = (RtreeDValue)0;
/* Pick two "seed" cells from the array of cells. The algorithm used /* Pick two "seed" cells from the array of cells. The algorithm used
** here is the LinearPickSeeds algorithm from Gutman[1984]. The ** here is the LinearPickSeeds algorithm from Gutman[1984]. The
@@ -1739,18 +1762,18 @@ static void LinearPickSeeds(
** variables iLeftSeek and iRightSeed. ** variables iLeftSeek and iRightSeed.
*/ */
for(i=0; i<pRtree->nDim; i++){ for(i=0; i<pRtree->nDim; i++){
float x1 = DCOORD(aCell[0].aCoord[i*2]); RtreeDValue x1 = DCOORD(aCell[0].aCoord[i*2]);
float x2 = DCOORD(aCell[0].aCoord[i*2+1]); RtreeDValue x2 = DCOORD(aCell[0].aCoord[i*2+1]);
float x3 = x1; RtreeDValue x3 = x1;
float x4 = x2; RtreeDValue x4 = x2;
int jj; int jj;
int iCellLeft = 0; int iCellLeft = 0;
int iCellRight = 0; int iCellRight = 0;
for(jj=1; jj<nCell; jj++){ for(jj=1; jj<nCell; jj++){
float left = DCOORD(aCell[jj].aCoord[i*2]); RtreeDValue left = DCOORD(aCell[jj].aCoord[i*2]);
float right = DCOORD(aCell[jj].aCoord[i*2+1]); RtreeDValue right = DCOORD(aCell[jj].aCoord[i*2+1]);
if( left<x1 ) x1 = left; if( left<x1 ) x1 = left;
if( right>x4 ) x4 = right; if( right>x4 ) x4 = right;
@@ -1765,7 +1788,7 @@ static void LinearPickSeeds(
} }
if( x4!=x1 ){ if( x4!=x1 ){
float normalwidth = (x3 - x2) / (x4 - x1); RtreeDValue normalwidth = (x3 - x2) / (x4 - x1);
if( normalwidth>maxNormalInnerWidth ){ if( normalwidth>maxNormalInnerWidth ){
iLeftSeed = iCellLeft; iLeftSeed = iCellLeft;
iRightSeed = iCellRight; iRightSeed = iCellRight;
@@ -1794,13 +1817,13 @@ static RtreeCell *QuadraticPickNext(
#define FABS(a) ((a)<0.0?-1.0*(a):(a)) #define FABS(a) ((a)<0.0?-1.0*(a):(a))
int iSelect = -1; int iSelect = -1;
float fDiff; RtreeDValue fDiff;
int ii; int ii;
for(ii=0; ii<nCell; ii++){ for(ii=0; ii<nCell; ii++){
if( aiUsed[ii]==0 ){ if( aiUsed[ii]==0 ){
float left = cellGrowth(pRtree, pLeftBox, &aCell[ii]); RtreeDValue left = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
float right = cellGrowth(pRtree, pLeftBox, &aCell[ii]); RtreeDValue right = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
float diff = FABS(right-left); RtreeDValue diff = FABS(right-left);
if( iSelect<0 || diff>fDiff ){ if( iSelect<0 || diff>fDiff ){
fDiff = diff; fDiff = diff;
iSelect = ii; iSelect = ii;
@@ -1827,13 +1850,13 @@ static void QuadraticPickSeeds(
int iLeftSeed = 0; int iLeftSeed = 0;
int iRightSeed = 1; int iRightSeed = 1;
float fWaste = 0.0; RtreeDValue fWaste = 0.0;
for(ii=0; ii<nCell; ii++){ for(ii=0; ii<nCell; ii++){
for(jj=ii+1; jj<nCell; jj++){ for(jj=ii+1; jj<nCell; jj++){
float right = cellArea(pRtree, &aCell[jj]); RtreeDValue right = cellArea(pRtree, &aCell[jj]);
float growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]); RtreeDValue growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]);
float waste = growth - right; RtreeDValue waste = growth - right;
if( waste>fWaste ){ if( waste>fWaste ){
iLeftSeed = ii; iLeftSeed = ii;
@@ -1868,7 +1891,7 @@ static void QuadraticPickSeeds(
static void SortByDistance( static void SortByDistance(
int *aIdx, int *aIdx,
int nIdx, int nIdx,
float *aDistance, RtreeDValue *aDistance,
int *aSpare int *aSpare
){ ){
if( nIdx>1 ){ if( nIdx>1 ){
@@ -1894,8 +1917,8 @@ static void SortByDistance(
aIdx[iLeft+iRight] = aLeft[iLeft]; aIdx[iLeft+iRight] = aLeft[iLeft];
iLeft++; iLeft++;
}else{ }else{
float fLeft = aDistance[aLeft[iLeft]]; RtreeDValue fLeft = aDistance[aLeft[iLeft]];
float fRight = aDistance[aRight[iRight]]; RtreeDValue fRight = aDistance[aRight[iRight]];
if( fLeft<fRight ){ if( fLeft<fRight ){
aIdx[iLeft+iRight] = aLeft[iLeft]; aIdx[iLeft+iRight] = aLeft[iLeft];
iLeft++; iLeft++;
@@ -1911,8 +1934,8 @@ static void SortByDistance(
{ {
int jj; int jj;
for(jj=1; jj<nIdx; jj++){ for(jj=1; jj<nIdx; jj++){
float left = aDistance[aIdx[jj-1]]; RtreeDValue left = aDistance[aIdx[jj-1]];
float right = aDistance[aIdx[jj]]; RtreeDValue right = aDistance[aIdx[jj]];
assert( left<=right ); assert( left<=right );
} }
} }
@@ -1955,10 +1978,10 @@ static void SortByDimension(
memcpy(aSpare, aLeft, sizeof(int)*nLeft); memcpy(aSpare, aLeft, sizeof(int)*nLeft);
aLeft = aSpare; aLeft = aSpare;
while( iLeft<nLeft || iRight<nRight ){ while( iLeft<nLeft || iRight<nRight ){
double xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]); RtreeDValue xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]);
double xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]); RtreeDValue xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]);
double xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]); RtreeDValue xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]);
double xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]); RtreeDValue xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]);
if( (iLeft!=nLeft) && ((iRight==nRight) if( (iLeft!=nLeft) && ((iRight==nRight)
|| (xleft1<xright1) || (xleft1<xright1)
|| (xleft1==xright1 && xleft2<xright2) || (xleft1==xright1 && xleft2<xright2)
@@ -1976,10 +1999,10 @@ static void SortByDimension(
{ {
int jj; int jj;
for(jj=1; jj<nIdx; jj++){ for(jj=1; jj<nIdx; jj++){
float xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2]; RtreeDValue xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2];
float xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1]; RtreeDValue xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1];
float xright1 = aCell[aIdx[jj]].aCoord[iDim*2]; RtreeDValue xright1 = aCell[aIdx[jj]].aCoord[iDim*2];
float xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1]; RtreeDValue xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1];
assert( xleft1<=xright1 && (xleft1<xright1 || xleft2<=xright2) ); assert( xleft1<=xright1 && (xleft1<xright1 || xleft2<=xright2) );
} }
} }
@@ -2006,7 +2029,7 @@ static int splitNodeStartree(
int iBestDim = 0; int iBestDim = 0;
int iBestSplit = 0; int iBestSplit = 0;
float fBestMargin = 0.0; RtreeDValue fBestMargin = 0.0;
int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
@@ -2027,9 +2050,9 @@ static int splitNodeStartree(
} }
for(ii=0; ii<pRtree->nDim; ii++){ for(ii=0; ii<pRtree->nDim; ii++){
float margin = 0.0; RtreeDValue margin = 0.0;
float fBestOverlap = 0.0; RtreeDValue fBestOverlap = 0.0;
float fBestArea = 0.0; RtreeDValue fBestArea = 0.0;
int iBestLeft = 0; int iBestLeft = 0;
int nLeft; int nLeft;
@@ -2041,8 +2064,8 @@ static int splitNodeStartree(
RtreeCell left; RtreeCell left;
RtreeCell right; RtreeCell right;
int kk; int kk;
float overlap; RtreeDValue overlap;
float area; RtreeDValue area;
memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell)); memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell));
memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell)); memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell));
@@ -2125,7 +2148,7 @@ static int splitNodeGuttman(
for(i=nCell-2; i>0; i--){ for(i=nCell-2; i>0; i--){
RtreeCell *pNext; RtreeCell *pNext;
pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed); pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed);
float diff = RtreeDValue diff =
cellGrowth(pRtree, pBboxLeft, pNext) - cellGrowth(pRtree, pBboxLeft, pNext) -
cellGrowth(pRtree, pBboxRight, pNext) cellGrowth(pRtree, pBboxRight, pNext)
; ;
@@ -2458,32 +2481,34 @@ static int Reinsert(
int *aOrder; int *aOrder;
int *aSpare; int *aSpare;
RtreeCell *aCell; RtreeCell *aCell;
float *aDistance; RtreeDValue *aDistance;
int nCell; int nCell;
float aCenterCoord[RTREE_MAX_DIMENSIONS]; RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS];
int iDim; int iDim;
int ii; int ii;
int rc = SQLITE_OK; int rc = SQLITE_OK;
int n;
memset(aCenterCoord, 0, sizeof(float)*RTREE_MAX_DIMENSIONS); memset(aCenterCoord, 0, sizeof(RtreeDValue)*RTREE_MAX_DIMENSIONS);
nCell = NCELL(pNode)+1; nCell = NCELL(pNode)+1;
n = (nCell+1)&(~1);
/* Allocate the buffers used by this operation. The allocation is /* Allocate the buffers used by this operation. The allocation is
** relinquished before this function returns. ** relinquished before this function returns.
*/ */
aCell = (RtreeCell *)sqlite3_malloc(nCell * ( aCell = (RtreeCell *)sqlite3_malloc(n * (
sizeof(RtreeCell) + /* aCell array */ sizeof(RtreeCell) + /* aCell array */
sizeof(int) + /* aOrder array */ sizeof(int) + /* aOrder array */
sizeof(int) + /* aSpare array */ sizeof(int) + /* aSpare array */
sizeof(float) /* aDistance array */ sizeof(RtreeDValue) /* aDistance array */
)); ));
if( !aCell ){ if( !aCell ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
aOrder = (int *)&aCell[nCell]; aOrder = (int *)&aCell[n];
aSpare = (int *)&aOrder[nCell]; aSpare = (int *)&aOrder[n];
aDistance = (float *)&aSpare[nCell]; aDistance = (RtreeDValue *)&aSpare[n];
for(ii=0; ii<nCell; ii++){ for(ii=0; ii<nCell; ii++){
if( ii==(nCell-1) ){ if( ii==(nCell-1) ){
@@ -2493,19 +2518,19 @@ static int Reinsert(
} }
aOrder[ii] = ii; aOrder[ii] = ii;
for(iDim=0; iDim<pRtree->nDim; iDim++){ for(iDim=0; iDim<pRtree->nDim; iDim++){
aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2]); aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]);
aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2+1]); aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]);
} }
} }
for(iDim=0; iDim<pRtree->nDim; iDim++){ for(iDim=0; iDim<pRtree->nDim; iDim++){
aCenterCoord[iDim] = (float)(aCenterCoord[iDim]/((float)nCell*2.0)); aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2));
} }
for(ii=0; ii<nCell; ii++){ for(ii=0; ii<nCell; ii++){
aDistance[ii] = 0.0; aDistance[ii] = 0.0;
for(iDim=0; iDim<pRtree->nDim; iDim++){ for(iDim=0; iDim<pRtree->nDim; iDim++){
float coord = (float)(DCOORD(aCell[ii].aCoord[iDim*2+1]) - RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
DCOORD(aCell[ii].aCoord[iDim*2])); DCOORD(aCell[ii].aCoord[iDim*2]));
aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]); aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
} }
} }
@@ -2747,16 +2772,19 @@ static int rtreeUpdate(
/* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */ /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */
assert( nData==(pRtree->nDim*2 + 3) ); assert( nData==(pRtree->nDim*2 + 3) );
#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
for(ii=0; ii<(pRtree->nDim*2); ii+=2){ for(ii=0; ii<(pRtree->nDim*2); ii+=2){
cell.aCoord[ii].f = (float)sqlite3_value_double(azData[ii+3]); cell.aCoord[ii].f = (RtreeValue)sqlite3_value_double(azData[ii+3]);
cell.aCoord[ii+1].f = (float)sqlite3_value_double(azData[ii+4]); cell.aCoord[ii+1].f = (RtreeValue)sqlite3_value_double(azData[ii+4]);
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){ if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
rc = SQLITE_CONSTRAINT; rc = SQLITE_CONSTRAINT;
goto constraint; goto constraint;
} }
} }
}else{ }else
#endif
{
for(ii=0; ii<(pRtree->nDim*2); ii+=2){ for(ii=0; ii<(pRtree->nDim*2); ii+=2){
cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]); cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]); cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
@@ -3154,7 +3182,13 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid); sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
nCell = (int)strlen(zCell); nCell = (int)strlen(zCell);
for(jj=0; jj<tree.nDim*2; jj++){ for(jj=0; jj<tree.nDim*2; jj++){
sqlite3_snprintf(512-nCell,&zCell[nCell]," %f",(double)cell.aCoord[jj].f); #ifndef SQLITE_RTREE_INT_ONLY
sqlite3_snprintf(512-nCell,&zCell[nCell], " %f",
(double)cell.aCoord[jj].f);
#else
sqlite3_snprintf(512-nCell,&zCell[nCell], " %d",
cell.aCoord[jj].i);
#endif
nCell = (int)strlen(zCell); nCell = (int)strlen(zCell);
} }
@@ -3196,7 +3230,11 @@ int sqlite3RtreeInit(sqlite3 *db){
rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0); rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
#ifdef SQLITE_RTREE_INT_ONLY
void *c = (void *)RTREE_COORD_INT32;
#else
void *c = (void *)RTREE_COORD_REAL32; void *c = (void *)RTREE_COORD_REAL32;
#endif
rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0); rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0);
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@@ -3230,7 +3268,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
RtreeMatchArg *pBlob; RtreeMatchArg *pBlob;
int nBlob; int nBlob;
nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(double); nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue);
pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob); pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
if( !pBlob ){ if( !pBlob ){
sqlite3_result_error_nomem(ctx); sqlite3_result_error_nomem(ctx);
@@ -3241,7 +3279,11 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
pBlob->pContext = pGeomCtx->pContext; pBlob->pContext = pGeomCtx->pContext;
pBlob->nParam = nArg; pBlob->nParam = nArg;
for(i=0; i<nArg; i++){ for(i=0; i<nArg; i++){
#ifdef SQLITE_RTREE_INT_ONLY
pBlob->aParam[i] = sqlite3_value_int64(aArg[i]);
#else
pBlob->aParam[i] = sqlite3_value_double(aArg[i]); pBlob->aParam[i] = sqlite3_value_double(aArg[i]);
#endif
} }
sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free); sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free);
} }
@@ -3253,7 +3295,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
int sqlite3_rtree_geometry_callback( int sqlite3_rtree_geometry_callback(
sqlite3 *db, sqlite3 *db,
const char *zGeom, const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *), int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue *, int *),
void *pContext void *pContext
){ ){
RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */

View File

@@ -104,6 +104,18 @@ for {set nCol 1} {$nCol<[llength $cols]} {incr nCol} {
catchsql { DROP TABLE t1 } catchsql { DROP TABLE t1 }
} }
# Like execsql except display output as integer where that can be
# done without loss of information.
#
proc execsql_intout {sql} {
set out {}
foreach term [execsql $sql] {
regsub {\.0$} $term {} term
lappend out $term
}
return $out
}
# Test that it is possible to open an existing database that contains # Test that it is possible to open an existing database that contains
# r-tree tables. # r-tree tables.
# #
@@ -117,8 +129,8 @@ do_test rtree-1.4.1 {
do_test rtree-1.4.2 { do_test rtree-1.4.2 {
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql { SELECT * FROM t1 ORDER BY ii } execsql_intout { SELECT * FROM t1 ORDER BY ii }
} {1 5.0 10.0 2 15.0 20.0} } {1 5 10 2 15 20}
do_test rtree-1.4.3 { do_test rtree-1.4.3 {
execsql { DROP TABLE t1 } execsql { DROP TABLE t1 }
} {} } {}
@@ -127,12 +139,12 @@ do_test rtree-1.4.3 {
# column names. # column names.
# #
do_test rtree-1.5.1 { do_test rtree-1.5.1 {
execsql { execsql_intout {
CREATE VIRTUAL TABLE t1 USING rtree("the key", "x dim.", "x2'dim"); CREATE VIRTUAL TABLE t1 USING rtree("the key", "x dim.", "x2'dim");
INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(1, 2, 3);
SELECT "the key", "x dim.", "x2'dim" FROM t1; SELECT "the key", "x dim.", "x2'dim" FROM t1;
} }
} {1 2.0 3.0} } {1 2 3}
do_test rtree-1.5.1 { do_test rtree-1.5.1 {
execsql { DROP TABLE t1 } execsql { DROP TABLE t1 }
} {} } {}
@@ -161,8 +173,8 @@ do_test rtree-2.1.1 {
do_test rtree-2.1.2 { do_test rtree-2.1.2 {
execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) } execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
execsql { SELECT * FROM t1 } execsql_intout { SELECT * FROM t1 }
} {1 1.0 3.0 2.0 4.0} } {1 1 3 2 4}
do_test rtree-2.1.3 { do_test rtree-2.1.3 {
execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) } execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
execsql { SELECT rowid FROM t1 ORDER BY rowid } execsql { SELECT rowid FROM t1 ORDER BY rowid }
@@ -201,17 +213,17 @@ do_test rtree-3.1.1 {
} }
} {} } {}
do_test rtree-3.1.2 { do_test rtree-3.1.2 {
execsql { execsql_intout {
INSERT INTO t1 VALUES(5, 1, 3, 2, 4); INSERT INTO t1 VALUES(5, 1, 3, 2, 4);
SELECT * FROM t1; SELECT * FROM t1;
} }
} {5 1.0 3.0 2.0 4.0} } {5 1 3 2 4}
do_test rtree-3.1.3 { do_test rtree-3.1.3 {
execsql { execsql_intout {
INSERT INTO t1 VALUES(6, 2, 6, 4, 8); INSERT INTO t1 VALUES(6, 2, 6, 4, 8);
SELECT * FROM t1; SELECT * FROM t1;
} }
} {5 1.0 3.0 2.0 4.0 6 2.0 6.0 4.0 8.0} } {5 1 3 2 4 6 2 6 4 8}
# Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)): # Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)):
do_test rtree-3.2.1 { do_test rtree-3.2.1 {
@@ -228,25 +240,25 @@ do_test rtree-5.1.1 {
execsql { CREATE VIRTUAL TABLE t2 USING rtree(ii, x1, x2) } execsql { CREATE VIRTUAL TABLE t2 USING rtree(ii, x1, x2) }
} {} } {}
do_test rtree-5.1.2 { do_test rtree-5.1.2 {
execsql { execsql_intout {
INSERT INTO t2 VALUES(1, 10, 20); INSERT INTO t2 VALUES(1, 10, 20);
INSERT INTO t2 VALUES(2, 30, 40); INSERT INTO t2 VALUES(2, 30, 40);
INSERT INTO t2 VALUES(3, 50, 60); INSERT INTO t2 VALUES(3, 50, 60);
SELECT * FROM t2 ORDER BY ii; SELECT * FROM t2 ORDER BY ii;
} }
} {1 10.0 20.0 2 30.0 40.0 3 50.0 60.0} } {1 10 20 2 30 40 3 50 60}
do_test rtree-5.1.3 { do_test rtree-5.1.3 {
execsql { execsql_intout {
DELETE FROM t2 WHERE ii=2; DELETE FROM t2 WHERE ii=2;
SELECT * FROM t2 ORDER BY ii; SELECT * FROM t2 ORDER BY ii;
} }
} {1 10.0 20.0 3 50.0 60.0} } {1 10 20 3 50 60}
do_test rtree-5.1.4 { do_test rtree-5.1.4 {
execsql { execsql_intout {
DELETE FROM t2 WHERE ii=1; DELETE FROM t2 WHERE ii=1;
SELECT * FROM t2 ORDER BY ii; SELECT * FROM t2 ORDER BY ii;
} }
} {3 50.0 60.0} } {3 50 60}
do_test rtree-5.1.5 { do_test rtree-5.1.5 {
execsql { execsql {
DELETE FROM t2 WHERE ii=3; DELETE FROM t2 WHERE ii=3;
@@ -264,16 +276,16 @@ do_test rtree-6.1.1 {
execsql { CREATE VIRTUAL TABLE t3 USING rtree(ii, x1, x2, y1, y2) } execsql { CREATE VIRTUAL TABLE t3 USING rtree(ii, x1, x2, y1, y2) }
} {} } {}
do_test rtree-6.1.2 { do_test rtree-6.1.2 {
execsql { execsql_intout {
INSERT INTO t3 VALUES(1, 2, 3, 4, 5); INSERT INTO t3 VALUES(1, 2, 3, 4, 5);
UPDATE t3 SET x2=5; UPDATE t3 SET x2=5;
SELECT * FROM t3; SELECT * FROM t3;
} }
} {1 2.0 5.0 4.0 5.0} } {1 2 5 4 5}
do_test rtree-6.1.3 { do_test rtree-6.1.3 {
execsql { UPDATE t3 SET ii = 2 } execsql { UPDATE t3 SET ii = 2 }
execsql { SELECT * FROM t3 } execsql_intout { SELECT * FROM t3 }
} {2 2.0 5.0 4.0 5.0} } {2 2 5 4 5}
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
# Test cases rtree-7.* test rename operations. # Test cases rtree-7.* test rename operations.
@@ -286,29 +298,29 @@ do_test rtree-7.1.1 {
} {} } {}
do_test rtree-7.1.2 { do_test rtree-7.1.2 {
execsql { ALTER TABLE t4 RENAME TO t5 } execsql { ALTER TABLE t4 RENAME TO t5 }
execsql { SELECT * FROM t5 } execsql_intout { SELECT * FROM t5 }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.1.3 { do_test rtree-7.1.3 {
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql { SELECT * FROM t5 } execsql_intout { SELECT * FROM t5 }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.1.4 { do_test rtree-7.1.4 {
execsql { ALTER TABLE t5 RENAME TO 'raisara "one"'''} execsql { ALTER TABLE t5 RENAME TO 'raisara "one"'''}
execsql { SELECT * FROM "raisara ""one""'" } execsql_intout { SELECT * FROM "raisara ""one""'" }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.1.5 { do_test rtree-7.1.5 {
execsql { SELECT * FROM 'raisara "one"''' } execsql_intout { SELECT * FROM 'raisara "one"''' }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.1.6 { do_test rtree-7.1.6 {
execsql { ALTER TABLE "raisara ""one""'" RENAME TO "abc 123" } execsql { ALTER TABLE "raisara ""one""'" RENAME TO "abc 123" }
execsql { SELECT * FROM "abc 123" } execsql_intout { SELECT * FROM "abc 123" }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.1.7 { do_test rtree-7.1.7 {
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql { SELECT * FROM "abc 123" } execsql_intout { SELECT * FROM "abc 123" }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
# An error midway through a rename operation. # An error midway through a rename operation.
do_test rtree-7.2.1 { do_test rtree-7.2.1 {
@@ -318,8 +330,8 @@ do_test rtree-7.2.1 {
catchsql { ALTER TABLE "abc 123" RENAME TO t4 } catchsql { ALTER TABLE "abc 123" RENAME TO t4 }
} {1 {SQL logic error or missing database}} } {1 {SQL logic error or missing database}}
do_test rtree-7.2.2 { do_test rtree-7.2.2 {
execsql { SELECT * FROM "abc 123" } execsql_intout { SELECT * FROM "abc 123" }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.2.3 { do_test rtree-7.2.3 {
execsql { execsql {
DROP TABLE t4_node; DROP TABLE t4_node;
@@ -330,13 +342,13 @@ do_test rtree-7.2.3 {
do_test rtree-7.2.4 { do_test rtree-7.2.4 {
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql { SELECT * FROM "abc 123" } execsql_intout { SELECT * FROM "abc 123" }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.2.5 { do_test rtree-7.2.5 {
execsql { DROP TABLE t4_rowid } execsql { DROP TABLE t4_rowid }
execsql { ALTER TABLE "abc 123" RENAME TO t4 } execsql { ALTER TABLE "abc 123" RENAME TO t4 }
execsql { SELECT * FROM t4 } execsql_intout { SELECT * FROM t4 }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------

View File

@@ -27,21 +27,38 @@ if {[info exists G(isquick)] && $G(isquick)} {
set ::NROW 250 set ::NROW 250
} }
# Return a floating point number between -X and X. ifcapable !rtree_int_only {
# # Return a floating point number between -X and X.
proc rand {X} { #
return [expr {int((rand()-0.5)*1024.0*$X)/512.0}] proc rand {X} {
} return [expr {int((rand()-0.5)*1024.0*$X)/512.0}]
}
# Return a positive floating point number less than or equal to X
# # Return a positive floating point number less than or equal to X
proc randincr {X} { #
while 1 { proc randincr {X} {
set r [expr {int(rand()*$X*32.0)/32.0}] while 1 {
if {$r>0.0} {return $r} set r [expr {int(rand()*$X*32.0)/32.0}]
if {$r>0.0} {return $r}
}
}
} else {
# For rtree_int_only, return an number between -X and X.
#
proc rand {X} {
return [expr {int((rand()-0.5)*2*$X)}]
}
# Return a positive integer less than or equal to X
#
proc randincr {X} {
while 1 {
set r [expr {int(rand()*$X)+1}]
if {$r>0} {return $r}
}
} }
} }
# Scramble the $inlist into a random order. # Scramble the $inlist into a random order.
# #
proc scramble {inlist} { proc scramble {inlist} {

View File

@@ -49,9 +49,11 @@ do_test rtree5-1.6 {
do_test rtree5-1.7 { do_test rtree5-1.7 {
execsql { SELECT count(*) FROM t1 WHERE x1==5 } execsql { SELECT count(*) FROM t1 WHERE x1==5 }
} {1} } {1}
do_test rtree5-1.8 { ifcapable !rtree_int_only {
execsql { SELECT count(*) FROM t1 WHERE x1==5.2 } do_test rtree5-1.8 {
} {0} execsql { SELECT count(*) FROM t1 WHERE x1==5.2 }
} {0}
}
do_test rtree5-1.9 { do_test rtree5-1.9 {
execsql { SELECT count(*) FROM t1 WHERE x1==5.0 } execsql { SELECT count(*) FROM t1 WHERE x1==5.0 }
} {1} } {1}

View File

@@ -16,7 +16,7 @@ if {![info exists testdir]} {
} }
source $testdir/tester.tcl source $testdir/tester.tcl
ifcapable !rtree { ifcapable {!rtree || rtree_int_only} {
finish_test finish_test
return return
} }

View File

@@ -24,6 +24,18 @@ ifcapable !rtree||!vacuum {
return return
} }
# Like execsql except display output as integer where that can be
# done without loss of information.
#
proc execsql_intout {sql} {
set out {}
foreach term [execsql $sql] {
regsub {\.0$} $term {} term
lappend out $term
}
return $out
}
do_test rtree7-1.1 { do_test rtree7-1.1 {
execsql { execsql {
PRAGMA page_size = 1024; PRAGMA page_size = 1024;
@@ -32,27 +44,27 @@ do_test rtree7-1.1 {
} }
} {} } {}
do_test rtree7-1.2 { do_test rtree7-1.2 {
execsql { SELECT * FROM rt } execsql_intout { SELECT * FROM rt }
} {1 1.0 2.0 3.0 4.0} } {1 1 2 3 4}
do_test rtree7-1.3 { do_test rtree7-1.3 {
execsql { execsql_intout {
PRAGMA page_size = 2048; PRAGMA page_size = 2048;
VACUUM; VACUUM;
SELECT * FROM rt; SELECT * FROM rt;
} }
} {1 1.0 2.0 3.0 4.0} } {1 1 2 3 4}
do_test rtree7-1.4 { do_test rtree7-1.4 {
for {set i 2} {$i <= 51} {incr i} { for {set i 2} {$i <= 51} {incr i} {
execsql { INSERT INTO rt VALUES($i, 1, 2, 3, 4) } execsql { INSERT INTO rt VALUES($i, 1, 2, 3, 4) }
} }
execsql { SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt } execsql_intout { SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt }
} {51.0 102.0 153.0 204.0} } {51 102 153 204}
do_test rtree7-1.5 { do_test rtree7-1.5 {
execsql { execsql_intout {
PRAGMA page_size = 512; PRAGMA page_size = 512;
VACUUM; VACUUM;
SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt
} }
} {51.0 102.0 153.0 204.0} } {51 102 153 204}
finish_test finish_test

View File

@@ -17,6 +17,7 @@ if {![info exists testdir]} {
} }
source $testdir/tester.tcl source $testdir/tester.tcl
ifcapable !rtree { finish_test ; return } ifcapable !rtree { finish_test ; return }
ifcapable rtree_int_only { finish_test; return }
register_cube_geom db register_cube_geom db

View File

@@ -18,17 +18,30 @@ if {![info exists testdir]} {
source $testdir/tester.tcl source $testdir/tester.tcl
ifcapable !rtree { finish_test ; return } ifcapable !rtree { finish_test ; return }
do_test rtreeB-1.1 { ifcapable rtree_int_only {
db eval { do_test rtreeB-1.1-intonly {
CREATE VIRTUAL TABLE t1 USING rtree(ii, x0, y0, x1, y1); db eval {
INSERT INTO t1 VALUES(1073741824, 0.0, 0.0, 100.0, 100.0); CREATE VIRTUAL TABLE t1 USING rtree(ii, x0, y0, x1, y1);
INSERT INTO t1 VALUES(2147483646, 0.0, 0.0, 200.0, 200.0); INSERT INTO t1 VALUES(1073741824, 0.0, 0.0, 100.0, 100.0);
INSERT INTO t1 VALUES(4294967296, 0.0, 0.0, 300.0, 300.0); INSERT INTO t1 VALUES(2147483646, 0.0, 0.0, 200.0, 200.0);
INSERT INTO t1 VALUES(8589934592, 20.0, 20.0, 150.0, 150.0); INSERT INTO t1 VALUES(4294967296, 0.0, 0.0, 300.0, 300.0);
INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400); INSERT INTO t1 VALUES(8589934592, 20.0, 20.0, 150.0, 150.0);
SELECT rtreenode(2, data) FROM t1_node; 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}}}
} else {
do_test rtreeB-1.1 {
db eval {
CREATE VIRTUAL TABLE t1 USING rtree(ii, x0, y0, x1, y1);
INSERT INTO t1 VALUES(1073741824, 0.0, 0.0, 100.0, 100.0);
INSERT INTO t1 VALUES(2147483646, 0.0, 0.0, 200.0, 200.0);
INSERT INTO t1 VALUES(4294967296, 0.0, 0.0, 300.0, 300.0);
INSERT INTO t1 VALUES(8589934592, 20.0, 20.0, 150.0, 150.0);
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}}}
}
finish_test finish_test

View File

@@ -31,7 +31,11 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
int sqlite3_rtree_geometry_callback( int sqlite3_rtree_geometry_callback(
sqlite3 *db, sqlite3 *db,
const char *zGeom, const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes), #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
void *pContext void *pContext
); );

101
manifest
View File

@@ -1,5 +1,5 @@
C Merge\sall\srecent\strunk\schanges\sinto\sthe\ssessions\sbranch. C Import\sall\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch.
D 2012-03-30T17:30:33.409 D 2012-04-18T01:41:37.755
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -23,7 +23,7 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
F configure 4ee31677412c454d0978a64872faf3ec36ff94ca x F configure eb9e5e7f4c1601b5acf674a724e1a778481d2835 x
F configure.ac 9ee886c21c095b3272137b1553ae416c8b8c8557 F configure.ac 9ee886c21c095b3272137b1553ae416c8b8c8557
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html 3091574143dd3415669b6745843ff8d011d33549 F doc/lemon.html 3091574143dd3415669b6745843ff8d011d33549
@@ -70,15 +70,15 @@ F ext/fts3/fts3_aux.c 5205182bd8f372782597888156404766edf5781e
F ext/fts3/fts3_expr.c dbc7ba4c3a6061adde0f38ed8e9b349568299551 F ext/fts3/fts3_expr.c dbc7ba4c3a6061adde0f38ed8e9b349568299551
F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914 F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
F ext/fts3/fts3_icu.c 6c8f395cdf9e1e3afa7fadb7e523dbbf381c6dfa F ext/fts3/fts3_icu.c 62ec177c55f6a5c6e994dd3e5fd3194b4045c347
F ext/fts3/fts3_porter.c a465b49fcb8249a755792f87516eff182efa42b3 F ext/fts3/fts3_porter.c a465b49fcb8249a755792f87516eff182efa42b3
F ext/fts3/fts3_snippet.c 51a3a34c217e24678a133782c1dfb6f2f70fe559 F ext/fts3/fts3_snippet.c 51a3a34c217e24678a133782c1dfb6f2f70fe559
F ext/fts3/fts3_term.c 41e82ad335213d1c24356cf310dca1d3c13e7366 F ext/fts3/fts3_term.c 41e82ad335213d1c24356cf310dca1d3c13e7366
F ext/fts3/fts3_test.c f3ef8ae1b802383c4d24fd70774cb87d52841d5f F ext/fts3/fts3_test.c f153a121c763993e3d94cc99c012ee68d13231ae
F ext/fts3/fts3_tokenizer.c 3da7254a9881f7e270ab28e2004e0d22b3212bce F ext/fts3/fts3_tokenizer.c 3da7254a9881f7e270ab28e2004e0d22b3212bce
F ext/fts3/fts3_tokenizer.h 66dec98e365854b6cd2d54f1a96bb6d428fc5a68 F ext/fts3/fts3_tokenizer.h 66dec98e365854b6cd2d54f1a96bb6d428fc5a68
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004 F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
F ext/fts3/fts3_write.c 545c3e2add64c27b2b03f9c79619ac5e47043252 F ext/fts3/fts3_write.c cd4af00b3b0512b4d76177a267fcaafab44cbce4
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197 F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197
@@ -86,22 +86,22 @@ F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 4c1878818fc50efe5c2c7b8809d5cd0d88c7d396 F ext/rtree/rtree.c 73502e5336162fdc8f5d1c4bdd4ec6b1299c2f2a
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test 28e1b8da4da98093ce3210187434dd760a8d89d8 F ext/rtree/rtree1.test e474a2b5eff231496dbd073fe67e5fbaf7f444c9
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
F ext/rtree/rtree4.test 0061e6f464fd3dc6a79f82454c5a1c3dadbe42af F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
F ext/rtree/rtree5.test ce3d7ccae2cfd9d2e1052b462424964c9bdcda12 F ext/rtree/rtree5.test 9a229678a00f40e6aedb40cb3a07ec5444af892c
F ext/rtree/rtree6.test 0b380bd9af93f3bc496eef42502a336f58949c1b F ext/rtree/rtree6.test 3ff9113b4a872fa935309e3511cd9b7cdb4d2472
F ext/rtree/rtree7.test bcb647b42920b3b5d025846689147778485cc318 F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
F ext/rtree/rtree8.test 9772e16da71e17e02bdebf0a5188590f289ab37d F ext/rtree/rtree8.test 9772e16da71e17e02bdebf0a5188590f289ab37d
F ext/rtree/rtree9.test df9843d1a9195249c8d3b4ea6aedda2d5c73e9c2 F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
F ext/rtree/rtreeB.test b1916a9cecb86b02529c4cc5a546e8d6e7ff10da F ext/rtree/rtreeB.test 983e567b49b5dca165940f66b87e161aa30e82b2
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195 F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0 F ext/rtree/sqlite3rtree.h c34c1e41d1ab80bb8ad09aae402c9c956871a765
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
F ext/session/session1.test 502086908e4144dfaccb1baa77bc29d75a9daace F ext/session/session1.test 502086908e4144dfaccb1baa77bc29d75a9daace
@@ -138,16 +138,16 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 6be23a344d3301ae38e92fddb3a33b91c309fce4 F src/backup.c 6be23a344d3301ae38e92fddb3a33b91c309fce4
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 02aeee1f6d425e11f7b9b2d9d461ac501645ed6f F src/btree.c df800f10896bc2ddaa1125c532d6e7a7b9efc532
F src/btree.h 48a013f8964f12d944d90e4700df47b72dd6d923 F src/btree.h 48a013f8964f12d944d90e4700df47b72dd6d923
F src/btreeInt.h 26d8ca625b141927fe6620c1d2cf58eaf494ca0c F src/btreeInt.h 38a639c0542c29fe8331a221c4aed0cb8686249e
F src/build.c 987c6933ea170e443dc6a79d52f8d2506206b12b F src/build.c 987c6933ea170e443dc6a79d52f8d2506206b12b
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a F src/callback.c 0cb4228cdcd827dcc5def98fb099edcc9142dbcd
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33 F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c 32041c65dc05a94914cf979fad7b82bc8a963fe9 F src/delete.c 32041c65dc05a94914cf979fad7b82bc8a963fe9
F src/expr.c 7e40ea9f6899e31134be3c1b88b8347cf9ec40d7 F src/expr.c 1b2383adc4391ddae38abb71fd4690a3af8efb01
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5 F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
F src/func.c c6b3c94320253a35bda43fb69cc292618e3285d6 F src/func.c c6b3c94320253a35bda43fb69cc292618e3285d6
@@ -155,7 +155,7 @@ F src/global.c 4cfdca5cb0edd33c4d021baec4ede958cb2c793b
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c 56f11d8c1de32e90fd76f92e998267557f1ec5ce F src/insert.c e32d8d0b761ae5e57d804948bb4e01029a9653b0
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416 F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
@@ -179,7 +179,7 @@ F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c
F src/os.h 59beba555b65a450bd1d804220532971d4299f60 F src/os.h 59beba555b65a450bd1d804220532971d4299f60
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
F src/os_unix.c 0e3d2942d228d0366fb80a3640f35caf413b66d1 F src/os_unix.c 424d46e0edab969293c2223f09923b2178171f47
F src/os_win.c 5e9e933a412ab35de2a6506b3c6a8295b31b309e F src/os_win.c 5e9e933a412ab35de2a6506b3c6a8295b31b309e
F src/pager.c 85988507fa20acc60defb834722eddf4633e4aeb F src/pager.c 85988507fa20acc60defb834722eddf4633e4aeb
F src/pager.h ef1eaf8593e78f73885c1dfac27ad83bee23bdc5 F src/pager.h ef1eaf8593e78f73885c1dfac27ad83bee23bdc5
@@ -191,13 +191,13 @@ F src/pragma.c e708b3bb5704605816f617e0b1d63a5488060715
F src/prepare.c ec4989f7f480544bdc4192fe663470d2a2d7d61e F src/prepare.c ec4989f7f480544bdc4192fe663470d2a2d7d61e
F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699 F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 3d3e80a98f203ac6b9329e9621e29eda85ddfd40 F src/resolve.c 969ec2bc52db1b068054ecf5ddc74f244102a71d
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1
F src/select.c f6f141cb1ea13f1e6564d3e162700e4937baa2a1 F src/select.c d7b9018b7dd2e821183d69477ab55c39b8272335
F src/shell.c abf18d6ee54f2631860a98fdd7ab1327f470db67 F src/shell.c 11185a9a4574f363bd4268a2780d37480ae00040
F src/sqlite.h.in 984b1a39bc5f977aaf7ae1a7895ba2fdd5c4302a F src/sqlite.h.in ad55acc42422c461719f3adaee434836ab00677b
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
F src/sqliteInt.h 0ad8c0d6978532be268b2cf33ba713773ee4183a F src/sqliteInt.h 572c5e6aca50256bdbc34919ece5f660dabf25cc
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208 F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -215,11 +215,11 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2 F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
F src/test_config.c 576d3d9450fb009ccd8be581eaab7c7e3458cc40 F src/test_config.c 52aa8cab6e20e9de078a0fb4a6f45a0466fbae2a
F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094 F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_func.c 6232d722a4ddb193035aa13a03796bf57d6c12fd F src/test_func.c 6232d722a4ddb193035aa13a03796bf57d6c12fd
F src/test_fuzzer.c 3703a190bd79a43e5f097d59c73ab38961d14872 F src/test_fuzzer.c 7e431cb04f4457b676a2764839d2857fdd91ec4e
F src/test_hexio.c c4773049603151704a6ab25ac5e936b5109caf5a F src/test_hexio.c c4773049603151704a6ab25ac5e936b5109caf5a
F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a
F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99 F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
@@ -227,15 +227,15 @@ F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
F src/test_journal.c b964473ff1b7a65626763f068fa6a810385d1fbf F src/test_journal.c b964473ff1b7a65626763f068fa6a810385d1fbf
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
F src/test_malloc.c 3f5903a1528fd32fe4c472a3bd0259128d8faaef F src/test_malloc.c 3f5903a1528fd32fe4c472a3bd0259128d8faaef
F src/test_multiplex.c 30ca0348953abd3add46fe4ee19e3f9e669b7e56 F src/test_multiplex.c 3dffd0fe6c96ac7c5150485b55244e73faab5380
F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d
F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
F src/test_onefile.c 5e1382e7844c703c77c4c2aee82f8359555b5a8e F src/test_onefile.c 5e1382e7844c703c77c4c2aee82f8359555b5a8e
F src/test_osinst.c 7f790ac89c5a585d51b341274d9691c3391e0923 F src/test_osinst.c 7f790ac89c5a585d51b341274d9691c3391e0923
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
F src/test_quota.c a545115f837da4ef32f6b5578f147b44cfb13fd7 F src/test_quota.c 2ab468f5817b84f7105f78b77c300649ea5af8d1
F src/test_quota.h 9ffa1d3ad6d0a6a24e8670ea64b909c717ec3358 F src/test_quota.h ee5da2ae7f84d1c8e0e0e2ab33f01d69f10259b5
F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
F src/test_stat.c d7035cfcc0ff1f93c000b621f36524318e004e11 F src/test_stat.c d7035cfcc0ff1f93c000b621f36524318e004e11
@@ -253,13 +253,13 @@ F src/update.c 89de085a0bf4da448472029d0420a2b1cf1824ee
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84 F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
F src/util.c 4f6cfad661b2e3454b0cdd5b1b9d39a54942d0e3 F src/util.c 4f6cfad661b2e3454b0cdd5b1b9d39a54942d0e3
F src/vacuum.c bfd53f9bd20a8fdb70b0fa8e77182b866875c0d8 F src/vacuum.c bfd53f9bd20a8fdb70b0fa8e77182b866875c0d8
F src/vdbe.c 9c6251931bc32ca8824dd7b89e06eba358a4a536 F src/vdbe.c b79d6de881aeec7d22e944238fa0d9bd5a3ef5ae
F src/vdbe.h 87b8ff40de3f55dbcdc33029416862f517c37a2f F src/vdbe.h 87b8ff40de3f55dbcdc33029416862f517c37a2f
F src/vdbeInt.h f1956902b06b4f05ce965aafab6fe220a5477f9c F src/vdbeInt.h f1956902b06b4f05ce965aafab6fe220a5477f9c
F src/vdbeapi.c 2fc381f651738feb2495cb001cf2114dea596cc3 F src/vdbeapi.c 2fc381f651738feb2495cb001cf2114dea596cc3
F src/vdbeaux.c 2803275ce14795549fd86a03474cac80f549a569 F src/vdbeaux.c dcff925ee54f73a6a729ea56e4197c91b38645c4
F src/vdbeblob.c 11248c6362389569764682eb0f59ce910f3cc381 F src/vdbeblob.c 11248c6362389569764682eb0f59ce910f3cc381
F src/vdbemem.c fb0ac964ccbcd94f595eb993c05bfd9c52468a4a F src/vdbemem.c cb55e84b8e2c15704968ee05f0fae25883299b74
F src/vdbesort.c b25814d385895544ebc8118245c8311ded7f81c9 F src/vdbesort.c b25814d385895544ebc8118245c8311ded7f81c9
F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843 F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843
F src/vtab.c ab90fb600a3f5e4b7c48d22a4cdb2d6b23239847 F src/vtab.c ab90fb600a3f5e4b7c48d22a4cdb2d6b23239847
@@ -328,9 +328,9 @@ F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0 F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
F test/cache.test f64136b0893c293d0b910ed057b3b711249099a7 F test/cache.test f64136b0893c293d0b910ed057b3b711249099a7
F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360 F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360
F test/capi3.test 9c8b58b6a6aeb14e69bd8c8c7721b47d640464d1 F test/capi3.test 8dedb0050610e9ff95cd9d487beb0ce5f33a31ee
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
F test/capi3c.test 1b5424d2ac57b7b443b5de5b9a287642c02279b6 F test/capi3c.test 01f197d73f4d4d66316483662f475cab7ab5bd60
F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1 F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1
F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
@@ -489,7 +489,7 @@ F test/fts3corrupt.test 7b0f91780ca36118d73324ec803187208ad33b32
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
F test/fts3d.test bf640d79722b720fa1c81834c48cdaa45d531b1a F test/fts3d.test bf640d79722b720fa1c81834c48cdaa45d531b1a
F test/fts3defer.test 2ea3fa028f8d9523f9c33dd8acc4555d567ea4ac F test/fts3defer.test 6c2707be1b05b9790ba8ff91d3391d5fb425269e
F test/fts3defer2.test 35867d33ba6db03f6c73bd6f5fc333ae14f68c81 F test/fts3defer2.test 35867d33ba6db03f6c73bd6f5fc333ae14f68c81
F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297 F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851 F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
@@ -514,7 +514,7 @@ F test/fts4content.test 17b2360f7d1a9a7e5aa8022783f5c5731b6dfd4f
F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7 F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7
F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
F test/fts4merge3.test 640611c05f01e9e018ac10afd188b018d8fcd4e5 F test/fts4merge3.test 125c3334f49bc171b3310efc99358cd05475c1d6
F test/func.test 9809b7622d721904a8cc33c1ffb87f46d506ed01 F test/func.test 9809b7622d721904a8cc33c1ffb87f46d506ed01
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
@@ -527,7 +527,7 @@ F test/fuzzer1.test 69cf1036b92fd3b8e1fd65bef4d7ee3f085c28fb
F test/fuzzerfault.test ff2282c81797b6a355f0748d8b54c7287c5d2b25 F test/fuzzerfault.test ff2282c81797b6a355f0748d8b54c7287c5d2b25
F test/hook.test 94b927b15883f5c1477ab09eecd16275addb08f4 F test/hook.test 94b927b15883f5c1477ab09eecd16275addb08f4
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
F test/in.test a7b8a0f43da81cd08645b7a710099ffe9ad1126b F test/in.test 5941096407d8c133b9eff15bd3e666624b6cbde3
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617 F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
@@ -663,7 +663,7 @@ F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26 F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26
F test/quota.test c2f778dab4c7fb07bcfa962cc5c762f36d8061dc F test/quota.test c2f778dab4c7fb07bcfa962cc5c762f36d8061dc
F test/quota2.test 7e1c84f71f59388963fa8181a1292c87ae814d2d F test/quota2.test bc9fdb2e46aace691c1a01a9cc8d097bd4d7c1ab
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
@@ -681,6 +681,7 @@ F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
@@ -725,7 +726,7 @@ F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298 F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
F test/stat.test 08e8185b3fd5b010c90d7ad82b9dd4ea1cbf14b0 F test/stat.test 08e8185b3fd5b010c90d7ad82b9dd4ea1cbf14b0
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9 F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796 F test/subquery.test c5e0d183f1ae6251453338a465b32ae11326e0fa
F test/subquery2.test edcad5c118f0531c2e21bf16a09bbb105252d4cd F test/subquery2.test edcad5c118f0531c2e21bf16a09bbb105252d4cd
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4 F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
@@ -968,7 +969,7 @@ F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9 F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
F test/zerodamage.test 0de750389990b1078bab203c712dc3fefd1d8b82 F test/zerodamage.test 0de750389990b1078bab203c712dc3fefd1d8b82
F tool/build-shell.sh 12aa4391073a777fcb6dcc490b219a018ae98bac F tool/build-shell.sh b64a481901fc9ffe5ca8812a2a9255b6cfb77381
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2 F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439 F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
@@ -994,12 +995,12 @@ F tool/shell2.test 5dc76b8005b465f420fed8241621da7513060ff3
F tool/shell3.test 4fad469e8003938426355afdf34155f08c587836 F tool/shell3.test 4fad469e8003938426355afdf34155f08c587836
F tool/shell4.test 35f9c3d452b4e76d5013c63e1fd07478a62f14ce F tool/shell4.test 35f9c3d452b4e76d5013c63e1fd07478a62f14ce
F tool/shell5.test 0e987fb8d40638bb5c90163cb58cbe3e07dbed56 F tool/shell5.test 0e987fb8d40638bb5c90163cb58cbe3e07dbed56
F tool/showdb.c 43e913d954684c2f5007dcab46d1a1308852a0ad F tool/showdb.c 2e28d8e499b016485672e9a7ac65dacc0d28ff69
F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02 F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02
F tool/showwal.c f09e5a80a293919290ec85a6a37c85a5ddcf37d9 F tool/showwal.c f09e5a80a293919290ec85a6a37c85a5ddcf37d9
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
F tool/spaceanal.tcl 15f6cd939b4ecc14d061de7e8ace89e26c30c40b F tool/spaceanal.tcl e42273000686a4afbf6a5e5d7fb12be65e92afb1
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355 F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
@@ -1010,9 +1011,9 @@ F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
F tool/symbols.sh fec58532668296d7c7dc48be9c87f75ccdb5814f F tool/symbols.sh fec58532668296d7c7dc48be9c87f75ccdb5814f
F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
P 2277c70b6f14e2f8043112a5c49a8bc18b7504f3 196ca3a8b007b9f792e969893d981f6c5aa2fccc P fb9b9987de965e194fef56bca563ee65c49f0950 430bb59d798286a86c351de92c429345f016b3f0
R 93da740959437ea907cbb7c5ae8abd7e R 1079dce486da15e32db2d612434f8ab1
U drh U drh
Z fef535844e3896614cb995edc2eb862f Z f39a0ebbcb374338bf5b614e6c1f4af3

View File

@@ -1 +1 @@
fb9b9987de965e194fef56bca563ee65c49f0950 87a0eab5d98fff93aa2147c04c4af27be42fb365

View File

@@ -7554,6 +7554,25 @@ static void checkAppendMsg(
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
#ifndef SQLITE_OMIT_INTEGRITY_CHECK #ifndef SQLITE_OMIT_INTEGRITY_CHECK
/*
** Return non-zero if the bit in the IntegrityCk.aPgRef[] array that
** corresponds to page iPg is already set.
*/
static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){
assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 );
return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07)));
}
/*
** Set the bit in the IntegrityCk.aPgRef[] array that corresponds to page iPg.
*/
static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 );
pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07));
}
/* /*
** Add 1 to the reference count for page iPage. If this is the second ** Add 1 to the reference count for page iPage. If this is the second
** reference to the page, add an error message to pCheck->zErrMsg. ** reference to the page, add an error message to pCheck->zErrMsg.
@@ -7568,11 +7587,12 @@ static int checkRef(IntegrityCk *pCheck, Pgno iPage, char *zContext){
checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage); checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage);
return 1; return 1;
} }
if( pCheck->anRef[iPage]==1 ){ if( getPageReferenced(pCheck, iPage) ){
checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage); checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage);
return 1; return 1;
} }
return (pCheck->anRef[iPage]++)>1; setPageReferenced(pCheck, iPage);
return 0;
} }
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
@@ -7948,17 +7968,15 @@ char *sqlite3BtreeIntegrityCheck(
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
return 0; return 0;
} }
sCheck.anRef = sqlite3Malloc( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
if( !sCheck.anRef ){ sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
if( !sCheck.aPgRef ){
*pnErr = 1; *pnErr = 1;
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
return 0; return 0;
} }
for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; }
i = PENDING_BYTE_PAGE(pBt); i = PENDING_BYTE_PAGE(pBt);
if( i<=sCheck.nPage ){ if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
sCheck.anRef[i] = 1;
}
sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), 20000); sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), 20000);
sCheck.errMsg.useMalloc = 2; sCheck.errMsg.useMalloc = 2;
@@ -7983,18 +8001,18 @@ char *sqlite3BtreeIntegrityCheck(
*/ */
for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM #ifdef SQLITE_OMIT_AUTOVACUUM
if( sCheck.anRef[i]==0 ){ if( getPageReferenced(&sCheck, i)==0 ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i); checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
} }
#else #else
/* If the database supports auto-vacuum, make sure no tables contain /* If the database supports auto-vacuum, make sure no tables contain
** references to pointer-map pages. ** references to pointer-map pages.
*/ */
if( sCheck.anRef[i]==0 && if( getPageReferenced(&sCheck, i)==0 &&
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i); checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
} }
if( sCheck.anRef[i]!=0 && if( getPageReferenced(&sCheck, i)!=0 &&
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i); checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
} }
@@ -8015,7 +8033,7 @@ char *sqlite3BtreeIntegrityCheck(
/* Clean up and report errors. /* Clean up and report errors.
*/ */
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
sqlite3_free(sCheck.anRef); sqlite3_free(sCheck.aPgRef);
if( sCheck.mallocFailed ){ if( sCheck.mallocFailed ){
sqlite3StrAccumReset(&sCheck.errMsg); sqlite3StrAccumReset(&sCheck.errMsg);
*pnErr = sCheck.nErr+1; *pnErr = sCheck.nErr+1;

View File

@@ -631,12 +631,18 @@ struct BtCursor {
/* /*
** This structure is passed around through all the sanity checking routines ** This structure is passed around through all the sanity checking routines
** in order to keep track of some global state information. ** in order to keep track of some global state information.
**
** The aRef[] array is allocated so that there is 1 bit for each page in
** the database. As the integrity-check proceeds, for each page used in
** the database the corresponding bit is set. This allows integrity-check to
** detect pages that are used twice and orphaned pages (both of which
** indicate corruption).
*/ */
typedef struct IntegrityCk IntegrityCk; typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk { struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */ BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
int *anRef; /* Number of times each page is referenced */ u8 *aPgRef; /* 1 bit per page in the db (see above) */
Pgno nPage; /* Number of pages in the database */ Pgno nPage; /* Number of pages in the database */
int mxErr; /* Stop accumulating errors when this reaches zero */ int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */ int nErr; /* Number of messages written to zErrMsg so far */

View File

@@ -223,38 +223,57 @@ CollSeq *sqlite3FindCollSeq(
** that uses encoding enc. The value returned indicates how well the ** that uses encoding enc. The value returned indicates how well the
** request is matched. A higher value indicates a better match. ** request is matched. A higher value indicates a better match.
** **
** If nArg is -1 that means to only return a match (non-zero) if p->nArg
** is also -1. In other words, we are searching for a function that
** takes a variable number of arguments.
**
** If nArg is -2 that means that we are searching for any function
** regardless of the number of arguments it uses, so return a positive
** match score for any
**
** The returned value is always between 0 and 6, as follows: ** The returned value is always between 0 and 6, as follows:
** **
** 0: Not a match, or if nArg<0 and the function is has no implementation. ** 0: Not a match.
** 1: A variable arguments function that prefers UTF-8 when a UTF-16 ** 1: UTF8/16 conversion required and function takes any number of arguments.
** encoding is requested, or vice versa. ** 2: UTF16 byte order change required and function takes any number of args.
** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is ** 3: encoding matches and function takes any number of arguments
** requested, or vice versa. ** 4: UTF8/16 conversion required - argument count matches exactly
** 3: A variable arguments function using the same text encoding. ** 5: UTF16 byte order conversion required - argument count matches exactly
** 4: A function with the exact number of arguments requested that ** 6: Perfect match: encoding and argument count match exactly.
** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa.
** 5: A function with the exact number of arguments requested that
** prefers UTF-16LE when UTF-16BE is requested, or vice versa.
** 6: An exact match.
** **
** If nArg==(-2) then any function with a non-null xStep or xFunc is
** a perfect match and any function with both xStep and xFunc NULL is
** a non-match.
*/ */
static int matchQuality(FuncDef *p, int nArg, u8 enc){ #define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */
int match = 0; static int matchQuality(
if( p->nArg==-1 || p->nArg==nArg FuncDef *p, /* The function we are evaluating for match quality */
|| (nArg==-1 && (p->xFunc!=0 || p->xStep!=0)) int nArg, /* Desired number of arguments. (-1)==any */
){ u8 enc /* Desired text encoding */
){
int match;
/* nArg of -2 is a special case */
if( nArg==(-2) ) return (p->xFunc==0 && p->xStep==0) ? 0 : FUNC_PERFECT_MATCH;
/* Wrong number of arguments means "no match" */
if( p->nArg!=nArg && p->nArg>=0 ) return 0;
/* Give a better score to a function with a specific number of arguments
** than to function that accepts any number of arguments. */
if( p->nArg==nArg ){
match = 4;
}else{
match = 1; match = 1;
if( p->nArg==nArg || nArg==-1 ){
match = 4;
}
if( enc==p->iPrefEnc ){
match += 2;
}
else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) ||
(enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){
match += 1;
}
} }
/* Bonus points if the text encoding matches */
if( enc==p->iPrefEnc ){
match += 2; /* Exact encoding match */
}else if( (enc & p->iPrefEnc & 2)!=0 ){
match += 1; /* Both are UTF16, but with different byte orders */
}
return match; return match;
} }
@@ -310,13 +329,12 @@ void sqlite3FuncDefInsert(
** **
** If the createFlag argument is true, then a new (blank) FuncDef ** If the createFlag argument is true, then a new (blank) FuncDef
** structure is created and liked into the "db" structure if a ** structure is created and liked into the "db" structure if a
** no matching function previously existed. When createFlag is true ** no matching function previously existed.
** and the nArg parameter is -1, then only a function that accepts
** any number of arguments will be returned.
** **
** If createFlag is false and nArg is -1, then the first valid ** If nArg is -2, then the first valid function found is returned. A
** function found is returned. A function is valid if either xFunc ** function is valid if either xFunc or xStep is non-zero. The nArg==(-2)
** or xStep is non-zero. ** case is used to see if zName is a valid function name for some number
** of arguments. If nArg is -2, then createFlag must be 0.
** **
** If createFlag is false, then a function with the required name and ** If createFlag is false, then a function with the required name and
** number of arguments may be returned even if the eTextRep flag does not ** number of arguments may be returned even if the eTextRep flag does not
@@ -328,14 +346,15 @@ FuncDef *sqlite3FindFunction(
int nName, /* Number of characters in the name */ int nName, /* Number of characters in the name */
int nArg, /* Number of arguments. -1 means any number */ int nArg, /* Number of arguments. -1 means any number */
u8 enc, /* Preferred text encoding */ u8 enc, /* Preferred text encoding */
int createFlag /* Create new entry if true and does not otherwise exist */ u8 createFlag /* Create new entry if true and does not otherwise exist */
){ ){
FuncDef *p; /* Iterator variable */ FuncDef *p; /* Iterator variable */
FuncDef *pBest = 0; /* Best match found so far */ FuncDef *pBest = 0; /* Best match found so far */
int bestScore = 0; /* Score of best match */ int bestScore = 0; /* Score of best match */
int h; /* Hash value */ int h; /* Hash value */
assert( nArg>=(-2) );
assert( nArg>=(-1) || createFlag==0 );
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a); h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
@@ -381,7 +400,7 @@ FuncDef *sqlite3FindFunction(
** exact match for the name, number of arguments and encoding, then add a ** exact match for the name, number of arguments and encoding, then add a
** new entry to the hash table and return it. ** new entry to the hash table and return it.
*/ */
if( createFlag && (bestScore<6 || pBest->nArg!=nArg) && if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){ (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
pBest->zName = (char *)&pBest[1]; pBest->zName = (char *)&pBest[1];
pBest->nArg = (u16)nArg; pBest->nArg = (u16)nArg;

View File

@@ -484,23 +484,55 @@ Expr *sqlite3PExpr(
Expr *pRight, /* Right operand */ Expr *pRight, /* Right operand */
const Token *pToken /* Argument token */ const Token *pToken /* Argument token */
){ ){
Expr *p = sqlite3ExprAlloc(pParse->db, op, pToken, 1); Expr *p;
sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight); if( op==TK_AND && pLeft && pRight ){
/* Take advantage of short-circuit false optimization for AND */
p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
}else{
p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
}
if( p ) { if( p ) {
sqlite3ExprCheckHeight(pParse, p->nHeight); sqlite3ExprCheckHeight(pParse, p->nHeight);
} }
return p; return p;
} }
/*
** Return 1 if an expression must be FALSE in all cases and 0 if the
** expression might be true. This is an optimization. If is OK to
** return 0 here even if the expression really is always false (a
** false negative). But it is a bug to return 1 if the expression
** might be true in some rare circumstances (a false positive.)
**
** Note that if the expression is part of conditional for a
** LEFT JOIN, then we cannot determine at compile-time whether or not
** is it true or false, so always return 0.
*/
static int exprAlwaysFalse(Expr *p){
int v = 0;
if( ExprHasProperty(p, EP_FromJoin) ) return 0;
if( !sqlite3ExprIsInteger(p, &v) ) return 0;
return v==0;
}
/* /*
** Join two expressions using an AND operator. If either expression is ** Join two expressions using an AND operator. If either expression is
** NULL, then just return the other expression. ** NULL, then just return the other expression.
**
** If one side or the other of the AND is known to be false, then instead
** of returning an AND expression, just return a constant expression with
** a value of false.
*/ */
Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){ Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){
if( pLeft==0 ){ if( pLeft==0 ){
return pRight; return pRight;
}else if( pRight==0 ){ }else if( pRight==0 ){
return pLeft; return pLeft;
}else if( exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight) ){
sqlite3ExprDelete(db, pLeft);
sqlite3ExprDelete(db, pRight);
return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0);
}else{ }else{
Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0); Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0);
sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight); sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight);
@@ -3746,7 +3778,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){ if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
return 2; return 2;
} }
}else if( pA->op!=TK_COLUMN && pA->u.zToken ){ }else if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2; if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
return 2; return 2;
@@ -3783,6 +3815,41 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
return 0; return 0;
} }
/*
** This is the expression callback for sqlite3FunctionUsesOtherSrc().
**
** Determine if an expression references any table other than one of the
** tables in pWalker->u.pSrcList and abort if it does.
*/
static int exprUsesOtherSrc(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
int i;
SrcList *pSrc = pWalker->u.pSrcList;
for(i=0; i<pSrc->nSrc; i++){
if( pExpr->iTable==pSrc->a[i].iCursor ) return WRC_Continue;
}
return WRC_Abort;
}else{
return WRC_Continue;
}
}
/*
** Determine if any of the arguments to the pExpr Function references
** any SrcList other than pSrcList. Return true if they do. Return
** false if pExpr has no argument or has only constant arguments or
** only references tables named in pSrcList.
*/
static int sqlite3FunctionUsesOtherSrc(Expr *pExpr, SrcList *pSrcList){
Walker w;
assert( pExpr->op==TK_AGG_FUNCTION );
memset(&w, 0, sizeof(w));
w.xExprCallback = exprUsesOtherSrc;
w.u.pSrcList = pSrcList;
if( sqlite3WalkExprList(&w, pExpr->x.pList)!=WRC_Continue ) return 1;
return 0;
}
/* /*
** Add a new element to the pAggInfo->aCol[] array. Return the index of ** Add a new element to the pAggInfo->aCol[] array. Return the index of
** the new element. Return a negative number if malloc fails. ** the new element. Return a negative number if malloc fails.
@@ -3898,9 +3965,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
return WRC_Prune; return WRC_Prune;
} }
case TK_AGG_FUNCTION: { case TK_AGG_FUNCTION: {
/* The pNC->nDepth==0 test causes aggregate functions in subqueries if( !sqlite3FunctionUsesOtherSrc(pExpr, pSrcList) ){
** to be ignored */
if( pNC->nDepth==0 ){
/* Check to see if pExpr is a duplicate of another aggregate /* Check to see if pExpr is a duplicate of another aggregate
** function that is already in the pAggInfo structure ** function that is already in the pAggInfo structure
*/ */
@@ -3944,15 +4009,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
return WRC_Continue; return WRC_Continue;
} }
static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
NameContext *pNC = pWalker->u.pNC; return WRC_Continue;
if( pNC->nDepth==0 ){
pNC->nDepth++;
sqlite3WalkSelect(pWalker, pSelect);
pNC->nDepth--;
return WRC_Prune;
}else{
return WRC_Continue;
}
} }
/* /*
@@ -3965,6 +4022,7 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
*/ */
void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
Walker w; Walker w;
memset(&w, 0, sizeof(w));
w.xExprCallback = analyzeAggregate; w.xExprCallback = analyzeAggregate;
w.xSelectCallback = analyzeAggregatesInSelect; w.xSelectCallback = analyzeAggregatesInSelect;
w.u.pNC = pNC; w.u.pNC = pNC;

View File

@@ -1218,7 +1218,6 @@ void sqlite3GenerateConstraintChecks(
#ifndef SQLITE_OMIT_CHECK #ifndef SQLITE_OMIT_CHECK
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
ExprList *pCheck = pTab->pCheck; ExprList *pCheck = pTab->pCheck;
int i;
pParse->ckBase = regData; pParse->ckBase = regData;
onError = overrideError!=OE_Default ? overrideError : OE_Abort; onError = overrideError!=OE_Default ? overrideError : OE_Abort;
for(i=0; i<pCheck->nExpr; i++){ for(i=0; i<pCheck->nExpr; i++){

View File

@@ -165,8 +165,8 @@
#endif #endif
/* /*
** Default permissions when creating auto proxy dir ** Default permissions when creating auto proxy dir
*/ */
#ifndef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS #ifndef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
# define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755 # define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755
#endif #endif
@@ -512,7 +512,7 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
/* /*
** Invoke open(). Do so multiple times, until it either succeeds or ** Invoke open(). Do so multiple times, until it either succeeds or
** files for some reason other than EINTR. ** fails for some reason other than EINTR.
** **
** If the file creation mode "m" is 0 then set it to the default for ** If the file creation mode "m" is 0 then set it to the default for
** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally ** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
@@ -528,7 +528,7 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
** recover the hot journals. ** recover the hot journals.
*/ */
static int robust_open(const char *z, int f, mode_t m){ static int robust_open(const char *z, int f, mode_t m){
int rc; int fd;
mode_t m2; mode_t m2;
mode_t origM = 0; mode_t origM = 0;
if( m==0 ){ if( m==0 ){
@@ -537,11 +537,20 @@ static int robust_open(const char *z, int f, mode_t m){
m2 = m; m2 = m;
origM = osUmask(0); origM = osUmask(0);
} }
do{ rc = osOpen(z,f,m2); }while( rc<0 && errno==EINTR ); do{
#if defined(O_CLOEXEC)
fd = osOpen(z,f|O_CLOEXEC,m2);
#else
fd = osOpen(z,f,m2);
#endif
}while( fd<0 && errno==EINTR );
if( m ){ if( m ){
osUmask(origM); osUmask(origM);
} }
return rc; #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
if( fd>=0 ) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
#endif
return fd;
} }
/* /*
@@ -3336,9 +3345,6 @@ static int openDirectory(const char *zFilename, int *pFd){
zDirname[ii] = '\0'; zDirname[ii] = '\0';
fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
if( fd>=0 ){ if( fd>=0 ){
#ifdef FD_CLOEXEC
osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
#endif
OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
} }
} }
@@ -3421,7 +3427,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
** actual file size after the operation may be larger than the requested ** actual file size after the operation may be larger than the requested
** size). ** size).
*/ */
if( pFile->szChunk ){ if( pFile->szChunk>0 ){
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
} }
@@ -5183,10 +5189,6 @@ static int unixOpen(
} }
#endif #endif
#ifdef FD_CLOEXEC
osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
#endif
noLock = eType!=SQLITE_OPEN_MAIN_DB; noLock = eType!=SQLITE_OPEN_MAIN_DB;

View File

@@ -533,7 +533,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
nId = sqlite3Strlen30(zId); nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
if( pDef==0 ){ if( pDef==0 ){
pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0); pDef = sqlite3FindFunction(pParse->db, zId, nId, -2, enc, 0);
if( pDef==0 ){ if( pDef==0 ){
no_such_func = 1; no_such_func = 1;
}else{ }else{

View File

@@ -76,6 +76,11 @@
/* /*
** Each entry in a RowSet is an instance of the following object. ** Each entry in a RowSet is an instance of the following object.
**
** This same object is reused to store a linked list of trees of RowSetEntry
** objects. In that alternative use, pRight points to the next entry
** in the list, pLeft points to the tree, and v is unused. The
** RowSet.pForest value points to the head of this forest list.
*/ */
struct RowSetEntry { struct RowSetEntry {
i64 v; /* ROWID value for this entry */ i64 v; /* ROWID value for this entry */
@@ -105,12 +110,18 @@ struct RowSet {
struct RowSetEntry *pEntry; /* List of entries using pRight */ struct RowSetEntry *pEntry; /* List of entries using pRight */
struct RowSetEntry *pLast; /* Last entry on the pEntry list */ struct RowSetEntry *pLast; /* Last entry on the pEntry list */
struct RowSetEntry *pFresh; /* Source of new entry objects */ struct RowSetEntry *pFresh; /* Source of new entry objects */
struct RowSetEntry *pTree; /* Binary tree of entries */ struct RowSetEntry *pForest; /* List of binary trees of entries */
u16 nFresh; /* Number of objects on pFresh */ u16 nFresh; /* Number of objects on pFresh */
u8 isSorted; /* True if pEntry is sorted */ u8 rsFlags; /* Various flags */
u8 iBatch; /* Current insert batch */ u8 iBatch; /* Current insert batch */
}; };
/*
** Allowed values for RowSet.rsFlags
*/
#define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */
#define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */
/* /*
** Turn bulk memory into a RowSet object. N bytes of memory ** Turn bulk memory into a RowSet object. N bytes of memory
** are available at pSpace. The db pointer is used as a memory context ** are available at pSpace. The db pointer is used as a memory context
@@ -131,10 +142,10 @@ RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){
p->db = db; p->db = db;
p->pEntry = 0; p->pEntry = 0;
p->pLast = 0; p->pLast = 0;
p->pTree = 0; p->pForest = 0;
p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
p->isSorted = 1; p->rsFlags = ROWSET_SORTED;
p->iBatch = 0; p->iBatch = 0;
return p; return p;
} }
@@ -154,8 +165,33 @@ void sqlite3RowSetClear(RowSet *p){
p->nFresh = 0; p->nFresh = 0;
p->pEntry = 0; p->pEntry = 0;
p->pLast = 0; p->pLast = 0;
p->pTree = 0; p->pForest = 0;
p->isSorted = 1; p->rsFlags = ROWSET_SORTED;
}
/*
** Allocate a new RowSetEntry object that is associated with the
** given RowSet. Return a pointer to the new and completely uninitialized
** objected.
**
** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
** routine returns NULL.
*/
static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
assert( p!=0 );
if( p->nFresh==0 ){
struct RowSetChunk *pNew;
pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));
if( pNew==0 ){
return 0;
}
pNew->pNextChunk = p->pChunk;
p->pChunk = pNew;
p->pFresh = pNew->aEntry;
p->nFresh = ROWSET_ENTRY_PER_CHUNK;
}
p->nFresh--;
return p->pFresh++;
} }
/* /*
@@ -167,30 +203,21 @@ void sqlite3RowSetClear(RowSet *p){
void sqlite3RowSetInsert(RowSet *p, i64 rowid){ void sqlite3RowSetInsert(RowSet *p, i64 rowid){
struct RowSetEntry *pEntry; /* The new entry */ struct RowSetEntry *pEntry; /* The new entry */
struct RowSetEntry *pLast; /* The last prior entry */ struct RowSetEntry *pLast; /* The last prior entry */
assert( p!=0 );
if( p->nFresh==0 ){ /* This routine is never called after sqlite3RowSetNext() */
struct RowSetChunk *pNew; assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));
if( pNew==0 ){ pEntry = rowSetEntryAlloc(p);
return; if( pEntry==0 ) return;
}
pNew->pNextChunk = p->pChunk;
p->pChunk = pNew;
p->pFresh = pNew->aEntry;
p->nFresh = ROWSET_ENTRY_PER_CHUNK;
}
pEntry = p->pFresh++;
p->nFresh--;
pEntry->v = rowid; pEntry->v = rowid;
pEntry->pRight = 0; pEntry->pRight = 0;
pLast = p->pLast; pLast = p->pLast;
if( pLast ){ if( pLast ){
if( p->isSorted && rowid<=pLast->v ){ if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){
p->isSorted = 0; p->rsFlags &= ~ROWSET_SORTED;
} }
pLast->pRight = pEntry; pLast->pRight = pEntry;
}else{ }else{
assert( p->pEntry==0 ); /* Fires if INSERT after SMALLEST */
p->pEntry = pEntry; p->pEntry = pEntry;
} }
p->pLast = pEntry; p->pLast = pEntry;
@@ -202,7 +229,7 @@ void sqlite3RowSetInsert(RowSet *p, i64 rowid){
** The input lists are connected via pRight pointers and are ** The input lists are connected via pRight pointers and are
** assumed to each already be in sorted order. ** assumed to each already be in sorted order.
*/ */
static struct RowSetEntry *rowSetMerge( static struct RowSetEntry *rowSetEntryMerge(
struct RowSetEntry *pA, /* First sorted list to be merged */ struct RowSetEntry *pA, /* First sorted list to be merged */
struct RowSetEntry *pB /* Second sorted list to be merged */ struct RowSetEntry *pB /* Second sorted list to be merged */
){ ){
@@ -236,32 +263,29 @@ static struct RowSetEntry *rowSetMerge(
} }
/* /*
** Sort all elements on the pEntry list of the RowSet into ascending order. ** Sort all elements on the list of RowSetEntry objects into order of
** increasing v.
*/ */
static void rowSetSort(RowSet *p){ static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
unsigned int i; unsigned int i;
struct RowSetEntry *pEntry; struct RowSetEntry *pNext, *aBucket[40];
struct RowSetEntry *aBucket[40];
assert( p->isSorted==0 );
memset(aBucket, 0, sizeof(aBucket)); memset(aBucket, 0, sizeof(aBucket));
while( p->pEntry ){ while( pIn ){
pEntry = p->pEntry; pNext = pIn->pRight;
p->pEntry = pEntry->pRight; pIn->pRight = 0;
pEntry->pRight = 0;
for(i=0; aBucket[i]; i++){ for(i=0; aBucket[i]; i++){
pEntry = rowSetMerge(aBucket[i], pEntry); pIn = rowSetEntryMerge(aBucket[i], pIn);
aBucket[i] = 0; aBucket[i] = 0;
} }
aBucket[i] = pEntry; aBucket[i] = pIn;
pIn = pNext;
} }
pEntry = 0; pIn = 0;
for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){ for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
pEntry = rowSetMerge(pEntry, aBucket[i]); pIn = rowSetEntryMerge(pIn, aBucket[i]);
} }
p->pEntry = pEntry; return pIn;
p->pLast = 0;
p->isSorted = 1;
} }
@@ -355,20 +379,37 @@ static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){
} }
/* /*
** Convert the list in p->pEntry into a sorted list if it is not ** Take all the entries on p->pEntry and on the trees in p->pForest and
** sorted already. If there is a binary tree on p->pTree, then ** sort them all together into one big ordered list on p->pEntry.
** convert it into a list too and merge it into the p->pEntry list. **
** This routine should only be called once in the life of a RowSet.
*/ */
static void rowSetToList(RowSet *p){ static void rowSetToList(RowSet *p){
if( !p->isSorted ){
rowSetSort(p); /* This routine is called only once */
assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
if( (p->rsFlags & ROWSET_SORTED)==0 ){
p->pEntry = rowSetEntrySort(p->pEntry);
} }
if( p->pTree ){
struct RowSetEntry *pHead, *pTail; /* While this module could theoretically support it, sqlite3RowSetNext()
rowSetTreeToList(p->pTree, &pHead, &pTail); ** is never called after sqlite3RowSetText() for the same RowSet. So
p->pTree = 0; ** there is never a forest to deal with. Should this change, simply
p->pEntry = rowSetMerge(p->pEntry, pHead); ** remove the assert() and the #if 0. */
assert( p->pForest==0 );
#if 0
while( p->pForest ){
struct RowSetEntry *pTree = p->pForest->pLeft;
if( pTree ){
struct RowSetEntry *pHead, *pTail;
rowSetTreeToList(pTree, &pHead, &pTail);
p->pEntry = rowSetEntryMerge(p->pEntry, pHead);
}
p->pForest = p->pForest->pRight;
} }
#endif
p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */
} }
/* /*
@@ -380,7 +421,12 @@ static void rowSetToList(RowSet *p){
** routine may not be called again. ** routine may not be called again.
*/ */
int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
rowSetToList(p); assert( p!=0 );
/* Merge the forest into a single sorted list on first call */
if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p);
/* Return the next entry on the list */
if( p->pEntry ){ if( p->pEntry ){
*pRowid = p->pEntry->v; *pRowid = p->pEntry->v;
p->pEntry = p->pEntry->pRight; p->pEntry = p->pEntry->pRight;
@@ -396,26 +442,66 @@ int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
/* /*
** Check to see if element iRowid was inserted into the the rowset as ** Check to see if element iRowid was inserted into the the rowset as
** part of any insert batch prior to iBatch. Return 1 or 0. ** part of any insert batch prior to iBatch. Return 1 or 0.
**
** If this is the first test of a new batch and if there exist entires
** 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, u8 iBatch, sqlite3_int64 iRowid){
struct RowSetEntry *p; struct RowSetEntry *p, *pTree;
/* This routine is never called after sqlite3RowSetNext() */
assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
/* Sort entries into the forest on the first test of a new batch
*/
if( iBatch!=pRowSet->iBatch ){ if( iBatch!=pRowSet->iBatch ){
if( pRowSet->pEntry ){ p = pRowSet->pEntry;
rowSetToList(pRowSet); if( p ){
pRowSet->pTree = rowSetListToTree(pRowSet->pEntry); struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){
p = rowSetEntrySort(p);
}
for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
ppPrevTree = &pTree->pRight;
if( pTree->pLeft==0 ){
pTree->pLeft = rowSetListToTree(p);
break;
}else{
struct RowSetEntry *pAux, *pTail;
rowSetTreeToList(pTree->pLeft, &pAux, &pTail);
pTree->pLeft = 0;
p = rowSetEntryMerge(pAux, p);
}
}
if( pTree==0 ){
*ppPrevTree = pTree = rowSetEntryAlloc(pRowSet);
if( pTree ){
pTree->v = 0;
pTree->pRight = 0;
pTree->pLeft = rowSetListToTree(p);
}
}
pRowSet->pEntry = 0; pRowSet->pEntry = 0;
pRowSet->pLast = 0; pRowSet->pLast = 0;
pRowSet->rsFlags |= ROWSET_SORTED;
} }
pRowSet->iBatch = iBatch; pRowSet->iBatch = iBatch;
} }
p = pRowSet->pTree;
while( p ){ /* Test to see if the iRowid value appears anywhere in the forest.
if( p->v<iRowid ){ ** Return 1 if it does and 0 if not.
p = p->pRight; */
}else if( p->v>iRowid ){ for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
p = p->pLeft; p = pTree->pLeft;
}else{ while( p ){
return 1; if( p->v<iRowid ){
p = p->pRight;
}else if( p->v>iRowid ){
p = p->pLeft;
}else{
return 1;
}
} }
} }
return 0; return 0;

View File

@@ -1258,9 +1258,17 @@ static int selectColumnsFromExprList(
char *zName; /* Column name */ char *zName; /* Column name */
int nName; /* Size of name in zName[] */ int nName; /* Size of name in zName[] */
*pnCol = nCol = pEList ? pEList->nExpr : 0; if( pEList ){
aCol = *paCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol); nCol = pEList->nExpr;
if( aCol==0 ) return SQLITE_NOMEM; aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
testcase( aCol==0 );
}else{
nCol = 0;
aCol = 0;
}
*pnCol = nCol;
*paCol = aCol;
for(i=0, pCol=aCol; i<nCol; i++, pCol++){ for(i=0, pCol=aCol; i<nCol; i++, pCol++){
/* Get an appropriate name for the column /* Get an appropriate name for the column
*/ */
@@ -2843,7 +2851,8 @@ static int flattenSubquery(
/* Authorize the subquery */ /* Authorize the subquery */
pParse->zAuthContext = pSubitem->zName; pParse->zAuthContext = pSubitem->zName;
sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0); TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0);
testcase( i==SQLITE_DENY );
pParse->zAuthContext = zSavedAuthContext; pParse->zAuthContext = zSavedAuthContext;
/* If the sub-query is a compound SELECT statement, then (by restrictions /* If the sub-query is a compound SELECT statement, then (by restrictions

View File

@@ -421,6 +421,7 @@ struct callback_data {
int statsOn; /* True to display memory stats before each finalize */ int statsOn; /* True to display memory stats before each finalize */
int cnt; /* Number of records displayed so far */ int cnt; /* Number of records displayed so far */
FILE *out; /* Write results here */ FILE *out; /* Write results here */
FILE *traceOut; /* Output for sqlite3_trace() */
int nErr; /* Number of errors seen */ int nErr; /* Number of errors seen */
int mode; /* An output mode setting */ int mode; /* An output mode setting */
int writableSchema; /* True if PRAGMA writable_schema=ON */ int writableSchema; /* True if PRAGMA writable_schema=ON */
@@ -1309,6 +1310,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
zTmp = appendText(zTmp, zTable, '"'); zTmp = appendText(zTmp, zTable, '"');
if( zTmp ){ if( zTmp ){
zSelect = appendText(zSelect, zTmp, '\''); zSelect = appendText(zSelect, zTmp, '\'');
free(zTmp);
} }
zSelect = appendText(zSelect, " || ' VALUES(' || ", 0); zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
rc = sqlite3_step(pTableInfo); rc = sqlite3_step(pTableInfo);
@@ -1337,7 +1339,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0); zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
run_table_dump_query(p, zSelect, 0); run_table_dump_query(p, zSelect, 0);
} }
if( zSelect ) free(zSelect); free(zSelect);
} }
return 0; return 0;
} }
@@ -1367,7 +1369,7 @@ static int run_schema_dump_query(
} }
zQ2 = malloc( len+100 ); zQ2 = malloc( len+100 );
if( zQ2==0 ) return rc; if( zQ2==0 ) return rc;
sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery); sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr); rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
if( rc ){ if( rc ){
fprintf(p->out, "/****** ERROR: %s ******/\n", zErr); fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
@@ -1433,6 +1435,7 @@ static char zHelp[] =
" If TABLE specified, only list tables matching\n" " If TABLE specified, only list tables matching\n"
" LIKE pattern TABLE.\n" " LIKE pattern TABLE.\n"
".timeout MS Try opening locked tables for MS milliseconds\n" ".timeout MS Try opening locked tables for MS milliseconds\n"
".trace FILE|off Output each SQL statement as it is run\n"
".vfsname ?AUX? Print the name of the VFS stack\n" ".vfsname ?AUX? Print the name of the VFS stack\n"
".width NUM1 NUM2 ... Set column widths for \"column\" mode\n" ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
; ;
@@ -1522,6 +1525,52 @@ static int booleanValue(char *zArg){
return val; return val;
} }
/*
** Close an output file, assuming it is not stderr or stdout
*/
static void output_file_close(FILE *f){
if( f && f!=stdout && f!=stderr ) fclose(f);
}
/*
** Try to open an output file. The names "stdout" and "stderr" are
** recognized and do the right thing. NULL is returned if the output
** filename is "off".
*/
static FILE *output_file_open(const char *zFile){
FILE *f;
if( strcmp(zFile,"stdout")==0 ){
f = stdout;
}else if( strcmp(zFile, "stderr")==0 ){
f = stderr;
}else if( strcmp(zFile, "off")==0 ){
f = 0;
}else{
f = fopen(zFile, "wb");
if( f==0 ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
}
}
return f;
}
/*
** A routine for handling output from sqlite3_trace().
*/
static void sql_trace_callback(void *pArg, const char *z){
FILE *f = (FILE*)pArg;
if( f ) fprintf(f, "%s\n", z);
}
/*
** A no-op routine that runs with the ".breakpoint" doc-command. This is
** a useful spot to set a debugger breakpoint.
*/
static void test_breakpoint(void){
static int nCall = 0;
nCall++;
}
/* /*
** If an input line begins with "." then invoke this routine to ** If an input line begins with "." then invoke this routine to
** process that line. ** process that line.
@@ -1601,6 +1650,13 @@ static int do_meta_command(char *zLine, struct callback_data *p){
bail_on_error = booleanValue(azArg[1]); bail_on_error = booleanValue(azArg[1]);
}else }else
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
test_breakpoint();
}else
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){ if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
struct callback_data data; struct callback_data data;
char *zErrMsg = 0; char *zErrMsg = 0;
@@ -1932,22 +1988,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){ if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){
const char *zFile = azArg[1]; const char *zFile = azArg[1];
if( p->pLog && p->pLog!=stdout && p->pLog!=stderr ){ output_file_close(p->pLog);
fclose(p->pLog); p->pLog = output_file_open(zFile);
p->pLog = 0;
}
if( strcmp(zFile,"stdout")==0 ){
p->pLog = stdout;
}else if( strcmp(zFile, "stderr")==0 ){
p->pLog = stderr;
}else if( strcmp(zFile, "off")==0 ){
p->pLog = 0;
}else{
p->pLog = fopen(zFile, "w");
if( p->pLog==0 ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
}
}
}else }else
if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){ if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
@@ -2000,17 +2042,13 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}else }else
if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){ if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
if( p->out!=stdout ){ if( p->outfile[0]=='|' ){
if( p->outfile[0]=='|' ){ pclose(p->out);
pclose(p->out); }else{
}else{ output_file_close(p->out);
fclose(p->out);
}
} }
if( strcmp(azArg[1],"stdout")==0 ){ p->outfile[0] = 0;
p->out = stdout; if( azArg[1][0]=='|' ){
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout");
}else if( azArg[1][0]=='|' ){
p->out = popen(&azArg[1][1], "w"); p->out = popen(&azArg[1][1], "w");
if( p->out==0 ){ if( p->out==0 ){
fprintf(stderr,"Error: cannot open pipe \"%s\"\n", &azArg[1][1]); fprintf(stderr,"Error: cannot open pipe \"%s\"\n", &azArg[1][1]);
@@ -2020,13 +2058,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
} }
}else{ }else{
p->out = fopen(azArg[1], "wb"); p->out = output_file_open(azArg[1]);
if( p->out==0 ){ if( p->out==0 ){
fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]); if( strcmp(azArg[1],"off")!=0 ){
fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]);
}
p->out = stdout; p->out = stdout;
rc = 1; rc = 1;
} else { } else {
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
} }
} }
}else }else
@@ -2396,6 +2436,18 @@ static int do_meta_command(char *zLine, struct callback_data *p){
enableTimer = booleanValue(azArg[1]); enableTimer = booleanValue(azArg[1]);
}else }else
if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){
output_file_close(p->traceOut);
p->traceOut = output_file_open(azArg[1]);
#ifndef SQLITE_OMIT_TRACE
if( p->traceOut==0 ){
sqlite3_trace(p->db, 0, 0);
}else{
sqlite3_trace(p->db, sql_trace_callback, p->traceOut);
}
#endif
}else
if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
printf("SQLite %s %s\n" /*extra-version-info*/, printf("SQLite %s %s\n" /*extra-version-info*/,
sqlite3_libversion(), sqlite3_sourceid()); sqlite3_libversion(), sqlite3_sourceid());
@@ -2607,12 +2659,11 @@ static int process_input(struct callback_data *p, FILE *in){
/* /*
** Return a pathname which is the user's home directory. A ** Return a pathname which is the user's home directory. A
** 0 return indicates an error of some kind. Space to hold the ** 0 return indicates an error of some kind.
** resulting string is obtained from malloc(). The calling
** function should free the result.
*/ */
static char *find_home_dir(void){ static char *find_home_dir(void){
char *home_dir = NULL; static char *home_dir = NULL;
if( home_dir ) return home_dir;
#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL) #if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL)
struct passwd *pwent; struct passwd *pwent;
@@ -2625,7 +2676,7 @@ static char *find_home_dir(void){
#if defined(_WIN32_WCE) #if defined(_WIN32_WCE)
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv() /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
*/ */
home_dir = strdup("/"); home_dir = "/";
#else #else
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__) #if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
@@ -2681,7 +2732,6 @@ static int process_sqliterc(
const char *sqliterc = sqliterc_override; const char *sqliterc = sqliterc_override;
char *zBuf = 0; char *zBuf = 0;
FILE *in = NULL; FILE *in = NULL;
int nBuf;
int rc = 0; int rc = 0;
if (sqliterc == NULL) { if (sqliterc == NULL) {
@@ -2692,15 +2742,8 @@ static int process_sqliterc(
#endif #endif
return 1; return 1;
} }
nBuf = strlen30(home_dir) + 16; zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
zBuf = malloc( nBuf ); sqliterc = zBuf;
if( zBuf==0 ){
fprintf(stderr,"%s: Error: out of memory\n",Argv0);
return 1;
}
sqlite3_snprintf(nBuf, zBuf,"%s/.sqliterc",home_dir);
free(home_dir);
sqliterc = (const char*)zBuf;
} }
in = fopen(sqliterc,"rb"); in = fopen(sqliterc,"rb");
if( in ){ if( in ){
@@ -2710,7 +2753,7 @@ static int process_sqliterc(
rc = process_input(p,in); rc = process_input(p,in);
fclose(in); fclose(in);
} }
free(zBuf); sqlite3_free(zBuf);
return rc; return rc;
} }
@@ -3051,7 +3094,6 @@ int main(int argc, char **argv){
write_history(zHistory); write_history(zHistory);
free(zHistory); free(zHistory);
} }
free(zHome);
}else{ }else{
rc = process_input(&data, stdin); rc = process_input(&data, stdin);
} }

View File

@@ -1542,7 +1542,7 @@ struct sqlite3_mem_methods {
** [SQLITE_USE_URI] symbol defined. ** [SQLITE_USE_URI] symbol defined.
** **
** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]]
** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFNIG_GETPCACHE ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
** <dd> These options are obsolete and should not be used by new code. ** <dd> These options are obsolete and should not be used by new code.
** They are retained for backwards compatibility but are now no-ops. ** They are retained for backwards compatibility but are now no-ops.
** </dl> ** </dl>

View File

@@ -2019,7 +2019,6 @@ struct NameContext {
u8 allowAgg; /* Aggregate functions allowed here */ u8 allowAgg; /* Aggregate functions allowed here */
u8 hasAgg; /* True if aggregates are seen */ u8 hasAgg; /* True if aggregates are seen */
u8 isCheck; /* True if resolving names in a CHECK constraint */ u8 isCheck; /* True if resolving names in a CHECK constraint */
int nDepth; /* Depth of subquery recursion. 1 for no recursion */
AggInfo *pAggInfo; /* Information about aggregates at this level */ AggInfo *pAggInfo; /* Information about aggregates at this level */
NameContext *pNext; /* Next outer name context. NULL for outermost */ NameContext *pNext; /* Next outer name context. NULL for outermost */
}; };
@@ -2489,6 +2488,7 @@ struct Walker {
union { /* Extra data for callback */ union { /* Extra data for callback */
NameContext *pNC; /* Naming context */ NameContext *pNC; /* Naming context */
int i; /* Integer value */ int i; /* Integer value */
SrcList *pSrcList; /* FROM clause */
} u; } u;
}; };
@@ -2857,7 +2857,7 @@ SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
IdList *sqlite3IdListDup(sqlite3*,IdList*); IdList *sqlite3IdListDup(sqlite3*,IdList*);
Select *sqlite3SelectDup(sqlite3*,Select*,int); Select *sqlite3SelectDup(sqlite3*,Select*,int);
void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*); void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int); FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8);
void sqlite3RegisterBuiltinFunctions(sqlite3*); void sqlite3RegisterBuiltinFunctions(sqlite3*);
void sqlite3RegisterDateTimeFunctions(void); void sqlite3RegisterDateTimeFunctions(void);
void sqlite3RegisterGlobalFunctions(void); void sqlite3RegisterGlobalFunctions(void);

View File

@@ -426,6 +426,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
Tcl_SetVar2(interp, "sqlite_options", "rtree", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "rtree", "0", TCL_GLOBAL_ONLY);
#endif #endif
#ifdef SQLITE_RTREE_INT_ONLY
Tcl_SetVar2(interp, "sqlite_options", "rtree_int_only", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "rtree_int_only", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS #ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY);
#else #else

View File

@@ -1127,8 +1127,7 @@ static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
} }
/* /*
** A virtual table module that provides read-only access to a ** A virtual table module that implements the "fuzzer".
** Tcl global variable namespace.
*/ */
static sqlite3_module fuzzerModule = { static sqlite3_module fuzzerModule = {
0, /* iVersion */ 0, /* iVersion */

View File

@@ -329,6 +329,7 @@ static sqlite3_file *multiplexSubOpen(
** database may therefore not grow to larger than 400 chunks. Attempting ** database may therefore not grow to larger than 400 chunks. Attempting
** to open chunk 401 indicates the database is full. */ ** to open chunk 401 indicates the database is full. */
if( iChunk>=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){ if( iChunk>=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){
sqlite3_log(SQLITE_FULL, "multiplexed chunk overflow: %s", pGroup->zName);
*rc = SQLITE_FULL; *rc = SQLITE_FULL;
return 0; return 0;
} }
@@ -347,7 +348,13 @@ static sqlite3_file *multiplexSubOpen(
}else{ }else{
*rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[iChunk].z, *rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[iChunk].z,
SQLITE_ACCESS_EXISTS, &bExists); SQLITE_ACCESS_EXISTS, &bExists);
if( *rc || !bExists ) return 0; if( *rc || !bExists ){
if( *rc ){
sqlite3_log(*rc, "multiplexor.xAccess failure on %s",
pGroup->aReal[iChunk].z);
}
return 0;
}
flags &= ~SQLITE_OPEN_CREATE; flags &= ~SQLITE_OPEN_CREATE;
} }
pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile ); pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile );
@@ -359,6 +366,8 @@ static sqlite3_file *multiplexSubOpen(
*rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen, *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
flags, pOutFlags); flags, pOutFlags);
if( (*rc)!=SQLITE_OK ){ if( (*rc)!=SQLITE_OK ){
sqlite3_log(*rc, "multiplexor.xOpen failure on %s",
pGroup->aReal[iChunk].z);
sqlite3_free(pSubOpen); sqlite3_free(pSubOpen);
pGroup->aReal[iChunk].p = 0; pGroup->aReal[iChunk].p = 0;
return 0; return 0;

View File

@@ -120,6 +120,9 @@ struct quota_FILE {
FILE *f; /* Open stdio file pointer */ FILE *f; /* Open stdio file pointer */
sqlite3_int64 iOfst; /* Current offset into the file */ sqlite3_int64 iOfst; /* Current offset into the file */
quotaFile *pFile; /* The file record in the quota system */ quotaFile *pFile; /* The file record in the quota system */
#if SQLITE_OS_WIN
char *zMbcsName; /* Full MBCS pathname of the file */
#endif
}; };
@@ -979,7 +982,7 @@ int sqlite3_quota_file(const char *zFilename){
quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){ quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){
quota_FILE *p = 0; quota_FILE *p = 0;
char *zFull = 0; char *zFull = 0;
char *zFullTranslated; char *zFullTranslated = 0;
int rc; int rc;
quotaGroup *pGroup; quotaGroup *pGroup;
quotaFile *pFile; quotaFile *pFile;
@@ -995,7 +998,6 @@ quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){
zFullTranslated = quota_utf8_to_mbcs(zFull); zFullTranslated = quota_utf8_to_mbcs(zFull);
if( zFullTranslated==0 ) goto quota_fopen_error; if( zFullTranslated==0 ) goto quota_fopen_error;
p->f = fopen(zFullTranslated, zMode); p->f = fopen(zFullTranslated, zMode);
quota_mbcs_free(zFullTranslated);
if( p->f==0 ) goto quota_fopen_error; if( p->f==0 ) goto quota_fopen_error;
quotaEnter(); quotaEnter();
pGroup = quotaGroupFind(zFull); pGroup = quotaGroupFind(zFull);
@@ -1010,9 +1012,13 @@ quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){
} }
quotaLeave(); quotaLeave();
sqlite3_free(zFull); sqlite3_free(zFull);
#if SQLITE_OS_WIN
p->zMbcsName = zFullTranslated;
#endif
return p; return p;
quota_fopen_error: quota_fopen_error:
quota_mbcs_free(zFullTranslated);
sqlite3_free(zFull); sqlite3_free(zFull);
if( p && p->f ) fclose(p->f); if( p && p->f ) fclose(p->f);
sqlite3_free(p); sqlite3_free(p);
@@ -1045,6 +1051,7 @@ size_t sqlite3_quota_fwrite(
sqlite3_int64 iEnd; sqlite3_int64 iEnd;
sqlite3_int64 szNew; sqlite3_int64 szNew;
quotaFile *pFile; quotaFile *pFile;
size_t rc;
iOfst = ftell(p->f); iOfst = ftell(p->f);
iEnd = iOfst + size*nmemb; iEnd = iOfst + size*nmemb;
@@ -1068,8 +1075,23 @@ size_t sqlite3_quota_fwrite(
pGroup->iSize = szNew; pGroup->iSize = szNew;
pFile->iSize = iEnd; pFile->iSize = iEnd;
quotaLeave(); quotaLeave();
}else{
pFile = 0;
} }
return fwrite(pBuf, size, nmemb, p->f); rc = fwrite(pBuf, size, nmemb, p->f);
/* If the write was incomplete, adjust the file size and group size
** downward */
if( rc<nmemb && pFile ){
size_t nWritten = rc>=0 ? rc : 0;
sqlite3_int64 iNewEnd = iOfst + size*nWritten;
if( iNewEnd<iEnd ) iNewEnd = iEnd;
quotaEnter();
pFile->pGroup->iSize += iNewEnd - pFile->iSize;
pFile->iSize = iNewEnd;
quotaLeave();
}
return rc;
} }
/* /*
@@ -1093,6 +1115,9 @@ int sqlite3_quota_fclose(quota_FILE *p){
} }
quotaLeave(); quotaLeave();
} }
#if SQLITE_OS_WIN
quota_mbcs_free(p->zMbcsName);
#endif
sqlite3_free(p); sqlite3_free(p);
return rc; return rc;
} }
@@ -1135,6 +1160,83 @@ long sqlite3_quota_ftell(quota_FILE *p){
return ftell(p->f); return ftell(p->f);
} }
/*
** Truncate a file to szNew bytes.
*/
int sqlite3_quota_ftruncate(quota_FILE *p, sqlite3_int64 szNew){
quotaFile *pFile = p->pFile;
int rc;
if( (pFile = p->pFile)!=0 && pFile->iSize<szNew ){
quotaGroup *pGroup;
if( pFile->iSize<szNew ){
/* This routine cannot be used to extend a file that is under
** quota management. Only true truncation is allowed. */
return -1;
}
pGroup = pFile->pGroup;
quotaEnter();
pGroup->iSize += szNew - pFile->iSize;
quotaLeave();
}
#if SQLITE_OS_UNIX
rc = ftruncate(fileno(p->f), szNew);
#endif
#if SQLITE_OS_WIN
rc = _chsize_s(_fileno(p->f), szNew);
#endif
if( pFile && rc==0 ){
quotaGroup *pGroup = pFile->pGroup;
quotaEnter();
pGroup->iSize += szNew - pFile->iSize;
pFile->iSize = szNew;
quotaLeave();
}
return rc;
}
/*
** Determine the time that the given file was last modified, in
** seconds size 1970. Write the result into *pTime. Return 0 on
** success and non-zero on any kind of error.
*/
int sqlite3_quota_file_mtime(quota_FILE *p, time_t *pTime){
int rc;
#if SQLITE_OS_UNIX
struct stat buf;
rc = fstat(fileno(p->f), &buf);
#endif
#if SQLITE_OS_WIN
struct _stati64 buf;
rc = _stati64(p->zMbcsName, &buf);
#endif
if( rc==0 ) *pTime = buf.st_mtime;
return rc;
}
/*
** Return the true size of the file, as reported by the operating
** system.
*/
sqlite3_int64 sqlite3_quota_file_truesize(quota_FILE *p){
int rc;
#if SQLITE_OS_UNIX
struct stat buf;
rc = fstat(fileno(p->f), &buf);
#endif
#if SQLITE_OS_WIN
struct _stati64 buf;
rc = _stati64(p->zMbcsName, &buf);
#endif
return rc==0 ? buf.st_size : -1;
}
/*
** Return the size of the file, as it is known to the quota subsystem.
*/
sqlite3_int64 sqlite3_quota_file_size(quota_FILE *p){
return p->pFile ? p->pFile->iSize : -1;
}
/* /*
** Remove a managed file. Update quotas accordingly. ** Remove a managed file. Update quotas accordingly.
*/ */
@@ -1656,6 +1758,96 @@ static int test_quota_ftell(
return TCL_OK; return TCL_OK;
} }
/*
** tclcmd: sqlite3_quota_ftruncate HANDLE SIZE
*/
static int test_quota_ftruncate(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
quota_FILE *p;
sqlite3_int64 x;
Tcl_WideInt w;
int rc;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE SIZE");
return TCL_ERROR;
}
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
if( Tcl_GetWideIntFromObj(interp, objv[2], &w) ) return TCL_ERROR;
x = (sqlite3_int64)w;
rc = sqlite3_quota_ftruncate(p, x);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return TCL_OK;
}
/*
** tclcmd: sqlite3_quota_file_size HANDLE
*/
static int test_quota_file_size(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
quota_FILE *p;
sqlite3_int64 x;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
return TCL_ERROR;
}
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
x = sqlite3_quota_file_size(p);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x));
return TCL_OK;
}
/*
** tclcmd: sqlite3_quota_file_truesize HANDLE
*/
static int test_quota_file_truesize(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
quota_FILE *p;
sqlite3_int64 x;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
return TCL_ERROR;
}
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
x = sqlite3_quota_file_truesize(p);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x));
return TCL_OK;
}
/*
** tclcmd: sqlite3_quota_file_mtime HANDLE
*/
static int test_quota_file_mtime(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
quota_FILE *p;
time_t t;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
return TCL_ERROR;
}
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
t = 0;
sqlite3_quota_file_mtime(p, &t);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(t));
return TCL_OK;
}
/* /*
** tclcmd: sqlite3_quota_remove FILENAME ** tclcmd: sqlite3_quota_remove FILENAME
*/ */
@@ -1713,21 +1905,25 @@ int Sqlitequota_Init(Tcl_Interp *interp){
char *zName; char *zName;
Tcl_ObjCmdProc *xProc; Tcl_ObjCmdProc *xProc;
} aCmd[] = { } aCmd[] = {
{ "sqlite3_quota_initialize", test_quota_initialize }, { "sqlite3_quota_initialize", test_quota_initialize },
{ "sqlite3_quota_shutdown", test_quota_shutdown }, { "sqlite3_quota_shutdown", test_quota_shutdown },
{ "sqlite3_quota_set", test_quota_set }, { "sqlite3_quota_set", test_quota_set },
{ "sqlite3_quota_file", test_quota_file }, { "sqlite3_quota_file", test_quota_file },
{ "sqlite3_quota_dump", test_quota_dump }, { "sqlite3_quota_dump", test_quota_dump },
{ "sqlite3_quota_fopen", test_quota_fopen }, { "sqlite3_quota_fopen", test_quota_fopen },
{ "sqlite3_quota_fread", test_quota_fread }, { "sqlite3_quota_fread", test_quota_fread },
{ "sqlite3_quota_fwrite", test_quota_fwrite }, { "sqlite3_quota_fwrite", test_quota_fwrite },
{ "sqlite3_quota_fclose", test_quota_fclose }, { "sqlite3_quota_fclose", test_quota_fclose },
{ "sqlite3_quota_fflush", test_quota_fflush }, { "sqlite3_quota_fflush", test_quota_fflush },
{ "sqlite3_quota_fseek", test_quota_fseek }, { "sqlite3_quota_fseek", test_quota_fseek },
{ "sqlite3_quota_rewind", test_quota_rewind }, { "sqlite3_quota_rewind", test_quota_rewind },
{ "sqlite3_quota_ftell", test_quota_ftell }, { "sqlite3_quota_ftell", test_quota_ftell },
{ "sqlite3_quota_remove", test_quota_remove }, { "sqlite3_quota_ftruncate", test_quota_ftruncate },
{ "sqlite3_quota_glob", test_quota_glob }, { "sqlite3_quota_file_size", test_quota_file_size },
{ "sqlite3_quota_file_truesize", test_quota_file_truesize },
{ "sqlite3_quota_file_mtime", test_quota_file_mtime },
{ "sqlite3_quota_remove", test_quota_remove },
{ "sqlite3_quota_glob", test_quota_glob },
}; };
int i; int i;

View File

@@ -29,6 +29,14 @@
#ifndef _QUOTA_H_ #ifndef _QUOTA_H_
#include "sqlite3.h" #include "sqlite3.h"
#include <stdio.h> #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#if SQLITE_OS_UNIX
# include <unistd.h>
#endif
#if SQLITE_OS_WIN
# include <windows.h>
#endif
/* Make this callable from C++ */ /* Make this callable from C++ */
#ifdef __cplusplus #ifdef __cplusplus
@@ -182,6 +190,48 @@ int sqlite3_quota_fseek(quota_FILE*, long, int);
void sqlite3_quota_rewind(quota_FILE*); void sqlite3_quota_rewind(quota_FILE*);
long sqlite3_quota_ftell(quota_FILE*); long sqlite3_quota_ftell(quota_FILE*);
/*
** Truncate a file previously opened by sqlite3_quota_fopen(). Return
** zero on success and non-zero on any kind of failure.
**
** The newSize argument must be less than or equal to the current file size.
** Any attempt to "truncate" a file to a larger size results in
** undefined behavior.
*/
int sqlite3_quota_ftrunate(quota_FILE*, sqlite3_int64 newSize);
/*
** Return the last modification time of the opened file, in seconds
** since 1970.
*/
int sqlite3_quota_file_mtime(quota_FILE*, time_t *pTime);
/*
** Return the size of the file as it is known to the quota system.
**
** This size might be different from the true size of the file on
** disk if some outside process has modified the file without using the
** quota mechanism, or if calls to sqlite3_quota_fwrite() have occurred
** which have increased the file size, but those writes have not yet been
** forced to disk using sqlite3_quota_fflush().
**
** Return -1 if the file is not participating in quota management.
*/
sqlite3_int64 sqlite3_quota_file_size(quota_FILE*);
/*
** Return the true size of the file.
**
** The true size should be the same as the size of the file as known
** to the quota system, however the sizes might be different if the
** file has been extended or truncated via some outside process or if
** pending writes have not yet been flushed to disk.
**
** Return -1 if the file does not exist or if the size of the file
** cannot be determined for some reason.
*/
sqlite3_int64 sqlite3_quota_file_truesize(quota_FILE*);
/* /*
** Delete a file from the disk, if that file is under quota management. ** Delete a file from the disk, if that file is under quota management.
** Adjust quotas accordingly. ** Adjust quotas accordingly.

View File

@@ -49,7 +49,11 @@ static void circle_del(void *p){
static int circle_geom( static int circle_geom(
sqlite3_rtree_geometry *p, sqlite3_rtree_geometry *p,
int nCoord, int nCoord,
#ifdef SQLITE_RTREE_INT_ONLY
sqlite3_int64 *aCoord,
#else
double *aCoord, double *aCoord,
#endif
int *pRes int *pRes
){ ){
int i; /* Iterator variable */ int i; /* Iterator variable */
@@ -188,8 +192,12 @@ static int gHere = 42;
*/ */
static int cube_geom( static int cube_geom(
sqlite3_rtree_geometry *p, sqlite3_rtree_geometry *p,
int nCoord, int nCoord,
#ifdef SQLITE_RTREE_INT_ONLY
sqlite3_int64 *aCoord,
#else
double *aCoord, double *aCoord,
#endif
int *piRes int *piRes
){ ){
Cube *pCube = (Cube *)p->pUser; Cube *pCube = (Cube *)p->pUser;

View File

@@ -2744,8 +2744,10 @@ case OP_Savepoint: {
rc = p->rc; rc = p->rc;
}else{ }else{
iSavepoint = db->nSavepoint - iSavepoint - 1; iSavepoint = db->nSavepoint - iSavepoint - 1;
for(ii=0; ii<db->nDb; ii++){ if( p1==SAVEPOINT_ROLLBACK ){
sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT); for(ii=0; ii<db->nDb; ii++){
sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT);
}
} }
for(ii=0; ii<db->nDb; ii++){ for(ii=0; ii<db->nDb; ii++){
rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);

View File

@@ -1240,7 +1240,7 @@ int sqlite3VdbeList(
for(j=0; j<nSub; j++){ for(j=0; j<nSub; j++){
if( apSub[j]==pOp->p4.pProgram ) break; if( apSub[j]==pOp->p4.pProgram ) break;
} }
if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, 1) ){ if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, nSub!=0) ){
apSub = (SubProgram **)pSub->z; apSub = (SubProgram **)pSub->z;
apSub[nSub++] = pOp->p4.pProgram; apSub[nSub++] = pOp->p4.pProgram;
pSub->flags |= MEM_Blob; pSub->flags |= MEM_Blob;

View File

@@ -59,10 +59,10 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
** Make sure pMem->z points to a writable allocation of at least ** Make sure pMem->z points to a writable allocation of at least
** n bytes. ** n bytes.
** **
** If the memory cell currently contains string or blob data ** If the third argument passed to this function is true, then memory
** and the third argument passed to this function is true, the ** cell pMem must contain a string or blob. In this case the content is
** current content of the cell is preserved. Otherwise, it may ** preserved. Otherwise, if the third parameter to this function is false,
** be discarded. ** any current string or blob value may be discarded.
** **
** This function sets the MEM_Dyn flag and clears any xDel callback. ** This function sets the MEM_Dyn flag and clears any xDel callback.
** It also clears MEM_Ephem and MEM_Static. If the preserve flag is ** It also clears MEM_Ephem and MEM_Static. If the preserve flag is
@@ -77,6 +77,10 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
); );
assert( (pMem->flags&MEM_RowSet)==0 ); assert( (pMem->flags&MEM_RowSet)==0 );
/* If the preserve flag is set to true, then the memory cell must already
** contain a valid string or blob value. */
assert( preserve==0 || pMem->flags&(MEM_Blob|MEM_Str) );
if( n<32 ) n = 32; if( n<32 ) n = 32;
if( sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){ if( sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){
if( preserve && pMem->z==pMem->zMalloc ){ if( preserve && pMem->z==pMem->zMalloc ){

View File

@@ -901,6 +901,12 @@ do_test capi3-11.9.3 {
do_test capi3-11.10 { do_test capi3-11.10 {
sqlite3_step $STMT sqlite3_step $STMT
} {SQLITE_ERROR} } {SQLITE_ERROR}
ifcapable !autoreset {
# If SQLITE_OMIT_AUTORESET is defined, then the statement must be
# reset() before it can be passed to step() again.
do_test capi3-11.11a { sqlite3_step $STMT } {SQLITE_MISUSE}
do_test capi3-11.11b { sqlite3_reset $STMT } {SQLITE_ABORT}
}
do_test capi3-11.11 { do_test capi3-11.11 {
sqlite3_step $STMT sqlite3_step $STMT
} {SQLITE_ROW} } {SQLITE_ROW}

View File

@@ -856,6 +856,12 @@ do_test capi3c-11.9.3 {
do_test capi3c-11.10 { do_test capi3c-11.10 {
sqlite3_step $STMT sqlite3_step $STMT
} {SQLITE_ABORT} } {SQLITE_ABORT}
ifcapable !autoreset {
# If SQLITE_OMIT_AUTORESET is defined, then the statement must be
# reset() before it can be passed to step() again.
do_test capi3-11.11a { sqlite3_step $STMT } {SQLITE_MISUSE}
do_test capi3-11.11b { sqlite3_reset $STMT } {SQLITE_ABORT}
}
do_test capi3c-11.11 { do_test capi3c-11.11 {
sqlite3_step $STMT sqlite3_step $STMT
} {SQLITE_ROW} } {SQLITE_ROW}

View File

@@ -489,5 +489,39 @@ do_execsql_test 4.2 {
SELECT * FROM x2 WHERE x2 MATCH 'a b c d e f g h i j k l m n o p q r s'; SELECT * FROM x2 WHERE x2 MATCH 'a b c d e f g h i j k l m n o p q r s';
} {{a b c d e f g h i j k l m n o p q r s t u v w x y m}} } {{a b c d e f g h i j k l m n o p q r s t u v w x y m}}
set tokenizers {1 simple}
ifcapable icu { lappend tokenizers 2 {icu en_US} }
foreach {tn tokenizer} $tokenizers {
do_execsql_test 5.$tn.1 "
CREATE VIRTUAL TABLE x3 USING FTS4(a, b, TOKENIZE $tokenizer)
"
do_execsql_test 5.$tn.2 {
BEGIN;
INSERT INTO x3 VALUES('b b b b b b b b b b b', 'b b b b b b b b b b b b b');
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 SELECT * FROM x3;
INSERT INTO x3 VALUES('a b c', NULL);
INSERT INTO x3 VALUES('a x c', NULL);
COMMIT;
SELECT * FROM x3 WHERE x3 MATCH 'a b';
} {{a b c} {}}
do_execsql_test 5.$tn.3 { DROP TABLE x3 }
}
finish_test finish_test

View File

@@ -20,6 +20,11 @@ source $testdir/bc_common.tcl
set ::testprefix fts4merge3 set ::testprefix fts4merge3
ifcapable !fts3 {
finish_test
return
}
if {"" == [bc_find_binaries backcompat.test]} { if {"" == [bc_find_binaries backcompat.test]} {
finish_test finish_test
return return

View File

@@ -258,17 +258,29 @@ do_test in-7.5 {
SELECT a FROM t1 WHERE a IN (5) AND b NOT IN (); SELECT a FROM t1 WHERE a IN (5) AND b NOT IN ();
} }
} {5} } {5}
do_test in-7.6 { do_test in-7.6.1 {
execsql { execsql {
SELECT a FROM ta WHERE a IN (); SELECT a FROM ta WHERE a IN ();
} }
} {} } {}
do_test in-7.6.2 {
db status step
} {0}
do_test in-7.7 { do_test in-7.7 {
execsql { execsql {
SELECT a FROM ta WHERE a NOT IN (); SELECT a FROM ta WHERE a NOT IN ();
} }
} {1 2 3 4 6 8 10} } {1 2 3 4 6 8 10}
do_test in-7.8.1 {
execsql {
SELECT * FROM ta LEFT JOIN tb ON (ta.b=tb.b) WHERE ta.a IN ();
}
} {}
do_test in-7.8.2 {
db status step
} {0}
do_test in-8.1 { do_test in-8.1 {
execsql { execsql {
SELECT b FROM t1 WHERE a IN ('hello','there') SELECT b FROM t1 WHERE a IN ('hello','there')

View File

@@ -76,6 +76,13 @@ do_test quota2-1.1 {
do_test quota2-1.2 { do_test quota2-1.2 {
set ::quota set ::quota
} {PWD/quota2a/xyz.txt 4000 7000} } {PWD/quota2a/xyz.txt 4000 7000}
do_test quota2-1.2.1 {
sqlite3_quota_file_size $::h1
} {4000}
do_test quota2-1.2.2 {
sqlite3_quota_fflush $::h1 1
sqlite3_quota_file_truesize $::h1
} {4000}
do_test quota2-1.3 { do_test quota2-1.3 {
sqlite3_quota_rewind $::h1 sqlite3_quota_rewind $::h1
set ::x [sqlite3_quota_fread $::h1 1001 7] set ::x [sqlite3_quota_fread $::h1 1001 7]
@@ -112,15 +119,43 @@ do_test quota2-1.11 {
standard_path [sqlite3_quota_dump] standard_path [sqlite3_quota_dump]
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 1 0}}} } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 1 0}}}
do_test quota2-1.12 { do_test quota2-1.12 {
sqlite3_quota_ftruncate $::h1 3500
sqlite3_quota_file_size $::h1
} {3500}
do_test quota2-1.13 {
sqlite3_quota_file_truesize $::h1
} {3500}
do_test quota2-1.14 {
standard_path [sqlite3_quota_dump]
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 3500 {PWD/quota2a/xyz.txt 3500 1 0}}}
do_test quota2-1.15 {
sqlite3_quota_fseek $::h1 0 SEEK_END
sqlite3_quota_ftell $::h1
} {3500}
do_test quota2-1.16 {
sqlite3_quota_fwrite $::h1 1 7000 $bigtext
} {500}
do_test quota2-1.17 {
sqlite3_quota_ftell $::h1
} {4000}
do_test quota2-1.18 {
sqlite3_quota_file_size $::h1
} {4000}
do_test quota2-1.19 {
sqlite3_quota_fflush $::h1 1
sqlite3_quota_file_truesize $::h1
} {4000}
do_test quota2-1.20 {
sqlite3_quota_fclose $::h1 sqlite3_quota_fclose $::h1
standard_path [sqlite3_quota_dump] standard_path [sqlite3_quota_dump]
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 0 0}}} } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 0 0}}}
do_test quota2-1.13 { do_test quota2-1.21 {
sqlite3_quota_remove quota2a/xyz.txt sqlite3_quota_remove quota2a/xyz.txt
standard_path [sqlite3_quota_dump] standard_path [sqlite3_quota_dump]
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}} } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}}
set quota {} set quota {}
do_test quota2-2.1 { do_test quota2-2.1 {
set ::h1 [sqlite3_quota_fopen quota2c/xyz.txt w+b] set ::h1 [sqlite3_quota_fopen quota2c/xyz.txt w+b]

96
test/savepoint7.test Normal file
View File

@@ -0,0 +1,96 @@
# 2012 March 31
#
# 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.
#
#***********************************************************************
#
# Focus on the interaction between RELEASE and ROLLBACK TO with
# pending query aborts. See ticket [27ca74af3c083f787a1c44b11fbb7c53bdbbcf1e].
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# The RELEASE of an inner savepoint should not effect pending queries.
#
do_test savepoint7-1.1 {
db eval {
CREATE TABLE t1(a,b,c);
CREATE TABLE t2(x,y,z);
INSERT INTO t1 VALUES(1,2,3);
INSERT INTO t1 VALUES(4,5,6);
INSERT INTO t1 VALUES(7,8,9);
SAVEPOINT x1;
}
db eval {SELECT * FROM t1} {
db eval {
SAVEPOINT x2;
INSERT INTO t2 VALUES($a,$b,$c);
RELEASE x2;
}
}
db eval {SELECT * FROM t2; RELEASE x1}
} {1 2 3 4 5 6 7 8 9}
do_test savepoint7-1.2 {
db eval {DELETE FROM t2;}
db eval {SELECT * FROM t1} {
db eval {
SAVEPOINT x2;
INSERT INTO t2 VALUES($a,$b,$c);
RELEASE x2;
}
}
db eval {SELECT * FROM t2}
} {1 2 3 4 5 6 7 8 9}
do_test savepoint7-1.3 {
db eval {DELETE FROM t2; BEGIN;}
db eval {SELECT * FROM t1} {
db eval {
SAVEPOINT x2;
INSERT INTO t2 VALUES($a,$b,$c);
RELEASE x2;
}
}
db eval {SELECT * FROM t2; ROLLBACK;}
} {1 2 3 4 5 6 7 8 9}
# However, a ROLLBACK of an inner savepoint will abort all queries, including
# queries in outer contexts.
#
do_test savepoint7-2.1 {
db eval {DELETE FROM t2; SAVEPOINT x1;}
set rc [catch {
db eval {SELECT * FROM t1} {
db eval {
SAVEPOINT x2;
INSERT INTO t2 VALUES($a,$b,$c);
ROLLBACK TO x2;
}
}
} msg]
db eval {RELEASE x1}
list $rc $msg [db eval {SELECT * FROM t2}]
} {1 {callback requested query abort} {}}
do_test savepoint7-2.2 {
db eval {DELETE FROM t2;}
set rc [catch {
db eval {SELECT * FROM t1} {
db eval {
SAVEPOINT x2;
INSERT INTO t2 VALUES($a,$b,$c);
ROLLBACK TO x2;
}
}
} msg]
list $rc $msg [db eval {SELECT * FROM t2}]
} {1 {callback requested query abort} {}}
finish_test

View File

@@ -331,6 +331,53 @@ do_test subquery-3.3.5 {
} }
} {1 1 2 1} } {1 1 2 1}
# The following tests check for aggregate subqueries in an aggregate
# query.
#
do_test subquery-3.4.1 {
execsql {
CREATE TABLE t34(x,y);
INSERT INTO t34 VALUES(106,4), (107,3), (106,5), (107,5);
SELECT a.x, avg(a.y)
FROM t34 AS a
GROUP BY a.x
HAVING NOT EXISTS( SELECT b.x, avg(b.y)
FROM t34 AS b
GROUP BY b.x
HAVING avg(a.y) > avg(b.y));
}
} {107 4.0}
do_test subquery-3.4.2 {
execsql {
SELECT a.x, avg(a.y) AS avg1
FROM t34 AS a
GROUP BY a.x
HAVING NOT EXISTS( SELECT b.x, avg(b.y) AS avg2
FROM t34 AS b
GROUP BY b.x
HAVING avg1 > avg2);
}
} {107 4.0}
do_test subquery-3.4.3 {
execsql {
SELECT
a.x,
avg(a.y),
NOT EXISTS ( SELECT b.x, avg(b.y)
FROM t34 AS b
GROUP BY b.x
HAVING avg(a.y) > avg(b.y)),
EXISTS ( SELECT c.x, avg(c.y)
FROM t34 AS c
GROUP BY c.x
HAVING avg(a.y) > avg(c.y))
FROM t34 AS a
GROUP BY a.x
ORDER BY a.x;
}
} {106 4.5 0 1 107 4.0 1 0}
#------------------------------------------------------------------ #------------------------------------------------------------------
# These tests - subquery-4.* - use the TCL statement cache to try # These tests - subquery-4.* - use the TCL statement cache to try
# and expose bugs to do with re-using statements that have been # and expose bugs to do with re-using statements that have been

View File

@@ -12,8 +12,8 @@ make sqlite3.c
gcc -o sqlite3 -g -Os -I. \ gcc -o sqlite3 -g -Os -I. \
-DSQLITE_THREADSAFE=0 \ -DSQLITE_THREADSAFE=0 \
-DSQLITE_ENABLE_VFSTRACE \ -DSQLITE_ENABLE_VFSTRACE \
-DSQLITE_ENABLE_STAT2 \ -DSQLITE_ENABLE_STAT3 \
-DSQLITE_ENABLE_FTS3 \ -DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_RTREE \
-DHAVE_READLINE \ -DHAVE_READLINE \
-DHAVE_USLEEP=1 \ -DHAVE_USLEEP=1 \

View File

@@ -9,6 +9,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "sqlite3.h"
static int pagesize = 1024; /* Size of a database page */ static int pagesize = 1024; /* Size of a database page */
@@ -450,6 +451,224 @@ static void decode_trunk_page(
} }
} }
/*
** A short text comment on the use of each page.
*/
static char **zPageUse;
/*
** Add a comment on the use of a page.
*/
static void page_usage_msg(int pgno, const char *zFormat, ...){
va_list ap;
char *zMsg;
va_start(ap, zFormat);
zMsg = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
if( pgno<=0 || pgno>mxPage ){
printf("ERROR: page %d out of bounds. Range=1..%d. Msg: %s\n",
pgno, mxPage, zMsg);
sqlite3_free(zMsg);
return;
}
if( zPageUse[pgno]!=0 ){
printf("ERROR: page %d used multiple times:\n", pgno);
printf("ERROR: previous: %s\n", zPageUse[pgno]);
printf("ERROR: current: %s\n", zPageUse[pgno]);
sqlite3_free(zPageUse[pgno]);
}
zPageUse[pgno] = zMsg;
}
/*
** Find overflow pages of a cell and describe their usage.
*/
static void page_usage_cell(
unsigned char cType, /* Page type */
unsigned char *a, /* Cell content */
int pgno, /* page containing the cell */
int cellno /* Index of the cell on the page */
){
int i;
int nDesc = 0;
int n = 0;
i64 nPayload;
i64 rowid;
int nLocal;
i = 0;
if( cType<=5 ){
a += 4;
n += 4;
}
if( cType!=5 ){
i = decodeVarint(a, &nPayload);
a += i;
n += i;
nLocal = localPayload(nPayload, cType);
}else{
nPayload = nLocal = 0;
}
if( cType==5 || cType==13 ){
i = decodeVarint(a, &rowid);
a += i;
n += i;
}
if( nLocal<nPayload ){
int ovfl = decodeInt32(a+nLocal);
int cnt = 0;
while( ovfl && (cnt++)<mxPage ){
page_usage_msg(ovfl, "overflow %d from cell %d of page %d",
cnt, cellno, pgno);
a = getContent((ovfl-1)*pagesize, 4);
ovfl = decodeInt32(a);
free(a);
}
}
}
/*
** Describe the usages of a b-tree page
*/
static void page_usage_btree(
int pgno, /* Page to describe */
int parent, /* Parent of this page. 0 for root pages */
int idx, /* Which child of the parent */
const char *zName /* Name of the table */
){
unsigned char *a;
const char *zType = "corrupt node";
int nCell;
int i;
int hdr = pgno==1 ? 100 : 0;
if( pgno<=0 || pgno>mxPage ) return;
a = getContent((pgno-1)*pagesize, pagesize);
switch( a[hdr] ){
case 2: zType = "interior node of index"; break;
case 5: zType = "interior node of table"; break;
case 10: zType = "leaf of index"; break;
case 13: zType = "leaf of table"; break;
}
if( parent ){
page_usage_msg(pgno, "%s [%s], child %d of page %d",
zType, zName, idx, parent);
}else{
page_usage_msg(pgno, "root %s [%s]", zType, zName);
}
nCell = a[hdr+3]*256 + a[hdr+4];
if( a[hdr]==2 || a[hdr]==5 ){
int cellstart = hdr+12;
unsigned int child;
for(i=0; i<nCell; i++){
int ofst;
ofst = cellstart + i*2;
ofst = a[ofst]*256 + a[ofst+1];
child = decodeInt32(a+ofst);
page_usage_btree(child, pgno, i, zName);
}
child = decodeInt32(a+cellstart-4);
page_usage_btree(child, pgno, i, zName);
}
if( a[hdr]==2 || a[hdr]==10 || a[hdr]==13 ){
int cellstart = hdr + 8 + 4*(a[hdr]<=5);
for(i=0; i<nCell; i++){
int ofst;
ofst = cellstart + i*2;
ofst = a[ofst]*256 + a[ofst+1];
page_usage_cell(a[hdr], a+ofst, pgno, i);
}
}
free(a);
}
/*
** Determine page usage by the freelist
*/
static void page_usage_freelist(int pgno){
unsigned char *a;
int cnt = 0;
int i;
int n;
int iNext;
int parent = 1;
while( pgno>0 && pgno<=mxPage && (cnt++)<mxPage ){
page_usage_msg(pgno, "freelist trunk #%d child of %d", cnt, parent);
a = getContent((pgno-1)*pagesize, pagesize);
iNext = decodeInt32(a);
n = decodeInt32(a+4);
for(i=0; i<n; i++){
int child = decodeInt32(a + (i*4+8));
page_usage_msg(child, "freelist leaf, child %d of trunk page %d",
i, pgno);
}
free(a);
parent = pgno;
pgno = iNext;
}
}
/*
** Try to figure out how every page in the database file is being used.
*/
static void page_usage_report(const char *zDbName){
int i;
int rc;
sqlite3 *db;
sqlite3_stmt *pStmt;
unsigned char *a;
/* Avoid the pathological case */
if( mxPage<1 ){
printf("empty database\n");
return;
}
/* Open the database file */
rc = sqlite3_open(zDbName, &db);
if( rc ){
printf("cannot open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return;
}
/* Set up global variables zPageUse[] and mxPage to record page
** usages */
zPageUse = sqlite3_malloc( sizeof(zPageUse[0])*(mxPage+1) );
if( zPageUse==0 ) out_of_memory();
memset(zPageUse, 0, sizeof(zPageUse[0])*(mxPage+1));
/* Discover the usage of each page */
a = getContent(0, 100);
page_usage_freelist(decodeInt32(a+32));
free(a);
page_usage_btree(1, 0, 0, "sqlite_master");
rc = sqlite3_prepare_v2(db,
"SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage",
-1, &pStmt, 0);
if( rc==SQLITE_OK ){
while( sqlite3_step(pStmt)==SQLITE_ROW ){
int pgno = sqlite3_column_int(pStmt, 2);
page_usage_btree(pgno, 0, 0, sqlite3_column_text(pStmt, 1));
}
}else{
printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db));
}
sqlite3_finalize(pStmt);
sqlite3_close(db);
/* Print the report and free memory used */
for(i=1; i<=mxPage; i++){
printf("%5d: %s\n", i, zPageUse[i] ? zPageUse[i] : "???");
sqlite3_free(zPageUse[i]);
}
sqlite3_free(zPageUse);
zPageUse = 0;
}
/* /*
** Print a usage comment ** Print a usage comment
*/ */
@@ -458,6 +677,7 @@ static void usage(const char *argv0){
fprintf(stderr, fprintf(stderr,
"args:\n" "args:\n"
" dbheader Show database header\n" " dbheader Show database header\n"
" pgidx Index of how each page is used\n"
" NNN..MMM Show hex of pages NNN through MMM\n" " NNN..MMM Show hex of pages NNN through MMM\n"
" NNN..end Show hex of pages NNN through end of file\n" " NNN..end Show hex of pages NNN through end of file\n"
" NNNb Decode btree page NNN\n" " NNNb Decode btree page NNN\n"
@@ -503,6 +723,10 @@ int main(int argc, char **argv){
print_db_header(); print_db_header();
continue; continue;
} }
if( strcmp(argv[i], "pgidx")==0 ){
page_usage_report(argv[1]);
continue;
}
if( !isdigit(argv[i][0]) ){ if( !isdigit(argv[i][0]) ){
fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]); fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
continue; continue;

View File

@@ -49,15 +49,14 @@ if {$true_file_size<512} {
# #
set extension [file extension $file_to_analyze] set extension [file extension $file_to_analyze]
set pattern $file_to_analyze set pattern $file_to_analyze
append pattern {[0-9][0-9]} append pattern {[0-3][0-9][0-9]}
foreach f [glob -nocomplain $pattern] { foreach f [glob -nocomplain $pattern] {
incr true_file_size [file size $f] incr true_file_size [file size $f]
set extension {} set extension {}
} }
if {[string length $extension]>=2 && [string length $extension]<=4} { if {[string length $extension]>=2 && [string length $extension]<=4} {
set pattern [file rootname $file_to_analyze] set pattern [file rootname $file_to_analyze]
append pattern [string range $extension 0 1] append pattern {.[0-3][0-9][0-9]}
append pattern {[0-9][0-9]}
foreach f [glob -nocomplain $pattern] { foreach f [glob -nocomplain $pattern] {
incr true_file_size [file size $f] incr true_file_size [file size $f]
} }

View File

@@ -9,5 +9,6 @@ echo '************* FTS4 and RTREE ****************'
scan-build gcc -c -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \ scan-build gcc -c -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
-DSQLITE_DEBUG sqlite3.c 2>&1 | grep -v 'ANALYZE:' -DSQLITE_DEBUG sqlite3.c 2>&1 | grep -v 'ANALYZE:'
echo '********** ENABLE_STAT3. THREADSAFE=0 *******' echo '********** ENABLE_STAT3. THREADSAFE=0 *******'
scan-build gcc -c -DSQLITE_ENABLE_STAT3 -DSQLITE_THREADSAFE=0 \ scan-build gcc -c -I. -DSQLITE_ENABLE_STAT3 -DSQLITE_THREADSAFE=0 \
-DSQLITE_DEBUG sqlite3.c 2>&1 | grep -v 'ANALYZE:' -DSQLITE_DEBUG \
sqlite3.c ../sqlite/src/shell.c -ldl 2>&1 | grep -v 'ANALYZE:'