mirror of https://github.com/sqlite/sqlite
Import all the latest trunk changes into the WinRT branch. Refactor and/or remove WinCE-specific macros and functions used for file locking to improve clarity of presentation.
FossilOrigin-Name: ad5cd15f49b286896f94ab1ff207077beee40e12
This commit is contained in:
commit
a749486e31
|
@ -1,6 +1,6 @@
|
|||
#! /bin/sh
|
||||
# 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,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
|
@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
|||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.7.11'
|
||||
PACKAGE_STRING='sqlite 3.7.11'
|
||||
PACKAGE_VERSION='3.7.12'
|
||||
PACKAGE_STRING='sqlite 3.7.12'
|
||||
PACKAGE_BUGREPORT=''
|
||||
|
||||
# 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.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
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]...
|
||||
|
||||
|
@ -1550,7 +1550,7 @@ fi
|
|||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.11:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.12:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
|
@ -1666,7 +1666,7 @@ fi
|
|||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.7.11
|
||||
sqlite configure 3.7.12
|
||||
generated by GNU Autoconf 2.62
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
$ $0 $@
|
||||
|
@ -14032,7 +14032,7 @@ exec 6>&1
|
|||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.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
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
|
@ -14085,7 +14085,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
|||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.7.11
|
||||
sqlite config.status 3.7.12
|
||||
configured by $0, generated by GNU Autoconf 2.62,
|
||||
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
|
|
@ -110,7 +110,10 @@ static int icuOpen(
|
|||
|
||||
*ppCursor = 0;
|
||||
|
||||
if( nInput<0 ){
|
||||
if( zInput==0 ){
|
||||
nInput = 0;
|
||||
zInput = "";
|
||||
}else if( nInput<0 ){
|
||||
nInput = strlen(zInput);
|
||||
}
|
||||
nChar = nInput+1;
|
||||
|
|
|
@ -73,6 +73,7 @@ static int fts3termConnectMethod(
|
|||
Fts3termTable *p; /* Virtual table object to return */
|
||||
int iIndex = 0;
|
||||
|
||||
UNUSED_PARAMETER(pCtx);
|
||||
if( argc==5 ){
|
||||
iIndex = atoi(argv[4]);
|
||||
argc--;
|
||||
|
@ -231,12 +232,12 @@ static int fts3termNextMethod(sqlite3_vtab_cursor *pCursor){
|
|||
|
||||
if( v==1 ){
|
||||
pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v);
|
||||
pCsr->iCol += v;
|
||||
pCsr->iCol += (int)v;
|
||||
pCsr->iPos = 0;
|
||||
pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v);
|
||||
}
|
||||
|
||||
pCsr->iPos += (v - 2);
|
||||
pCsr->iPos += (int)(v - 2);
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -357,7 +358,10 @@ int sqlite3Fts3InitTerm(sqlite3 *db){
|
|||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindFunction */
|
||||
0 /* xRename */
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0 /* xRollbackTo */
|
||||
};
|
||||
int rc; /* Return code */
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
#include <string.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 */
|
||||
#include "fts3Int.h"
|
||||
|
@ -161,6 +162,8 @@ static int fts3_near_match_cmd(
|
|||
Tcl_Obj **apExprToken;
|
||||
int nExprToken;
|
||||
|
||||
UNUSED_PARAMETER(clientData);
|
||||
|
||||
/* Must have 3 or more arguments. */
|
||||
if( objc<3 || (objc%2)==0 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DOCUMENT EXPR ?OPTION VALUE?...");
|
||||
|
@ -314,6 +317,7 @@ static int fts3_configure_incr_load_cmd(
|
|||
Tcl_SetObjResult(interp, pRet);
|
||||
Tcl_DecrRefCount(pRet);
|
||||
#endif
|
||||
UNUSED_PARAMETER(clientData);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -352,6 +356,8 @@ static int testTokenizerCreate(
|
|||
sqlite3_tokenizer **ppTokenizer
|
||||
){
|
||||
test_tokenizer *pNew;
|
||||
UNUSED_PARAMETER(argc);
|
||||
UNUSED_PARAMETER(argv);
|
||||
|
||||
pNew = sqlite3_malloc(sizeof(test_tokenizer));
|
||||
if( !pNew ) return SQLITE_NOMEM;
|
||||
|
@ -507,6 +513,7 @@ static int fts3_test_tokenizer_cmd(
|
|||
(const unsigned char *)&pPtr, sizeof(sqlite3_tokenizer_module *)
|
||||
));
|
||||
#endif
|
||||
UNUSED_PARAMETER(clientData);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -524,4 +531,5 @@ int Sqlitetestfts3_Init(Tcl_Interp *interp){
|
|||
);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_FTS3 || SQLITE_ENABLE_FTS4 */
|
||||
#endif /* ifdef SQLITE_TEST */
|
||||
|
|
|
@ -3739,7 +3739,6 @@ static int fts3IncrmergeAppend(
|
|||
pLeaf->key.n = 0;
|
||||
pLeaf->block.n = 0;
|
||||
|
||||
nPrefix = 0;
|
||||
nSuffix = nTerm;
|
||||
nSpace = 1;
|
||||
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
|
||||
|
|
|
@ -182,6 +182,19 @@ struct Rtree {
|
|||
#define RTREE_COORD_REAL32 0
|
||||
#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
|
||||
** maximum. In Gutman's notation:
|
||||
|
@ -217,20 +230,25 @@ struct RtreeCursor {
|
|||
};
|
||||
|
||||
union RtreeCoord {
|
||||
float f;
|
||||
RtreeValue f;
|
||||
int i;
|
||||
};
|
||||
|
||||
/*
|
||||
** The argument is an RtreeCoord. Return the value stored within the RtreeCoord
|
||||
** formatted as a double. This macro assumes that local variable pRtree points
|
||||
** to the Rtree structure associated with the RtreeCoord.
|
||||
** formatted as a RtreeDValue (double or int64). This macro assumes that local
|
||||
** variable pRtree points to the Rtree structure associated with the
|
||||
** RtreeCoord.
|
||||
*/
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
# define DCOORD(coord) ((RtreeDValue)coord.i)
|
||||
#else
|
||||
# define DCOORD(coord) ( \
|
||||
(pRtree->eCoordType==RTREE_COORD_REAL32) ? \
|
||||
((double)coord.f) : \
|
||||
((double)coord.i) \
|
||||
)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A search constraint.
|
||||
|
@ -238,8 +256,8 @@ union RtreeCoord {
|
|||
struct RtreeConstraint {
|
||||
int iCoord; /* Index of constrained coordinate */
|
||||
int op; /* Constraining operation */
|
||||
double rValue; /* Constraint value. */
|
||||
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
|
||||
RtreeDValue rValue; /* Constraint value. */
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
|
||||
sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */
|
||||
};
|
||||
|
||||
|
@ -287,10 +305,10 @@ struct RtreeCell {
|
|||
*/
|
||||
struct RtreeMatchArg {
|
||||
u32 magic; /* Always RTREE_GEOMETRY_MAGIC */
|
||||
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
|
||||
int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue*, int *);
|
||||
void *pContext;
|
||||
int nParam;
|
||||
double aParam[1];
|
||||
RtreeDValue aParam[1];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -302,7 +320,7 @@ struct RtreeMatchArg {
|
|||
** the geometry callback function).
|
||||
*/
|
||||
struct RtreeGeomCallback {
|
||||
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
|
||||
void *pContext;
|
||||
};
|
||||
|
||||
|
@ -868,7 +886,7 @@ static int testRtreeGeom(
|
|||
int *pbRes /* OUT: Test result */
|
||||
){
|
||||
int i;
|
||||
double aCoord[RTREE_MAX_DIMENSIONS*2];
|
||||
RtreeDValue aCoord[RTREE_MAX_DIMENSIONS*2];
|
||||
int nCoord = pRtree->nDim*2;
|
||||
|
||||
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);
|
||||
for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){
|
||||
RtreeConstraint *p = &pCursor->aConstraint[ii];
|
||||
double cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
|
||||
double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
|
||||
RtreeDValue cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
|
||||
RtreeDValue cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
|
||||
|
||||
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
|
||||
|
@ -951,7 +969,7 @@ static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
|
|||
nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
|
||||
for(ii=0; ii<pCursor->nConstraint; ii++){
|
||||
RtreeConstraint *p = &pCursor->aConstraint[ii];
|
||||
double coord = DCOORD(cell.aCoord[p->iCoord]);
|
||||
RtreeDValue coord = DCOORD(cell.aCoord[p->iCoord]);
|
||||
int res;
|
||||
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
|
||||
|
@ -1149,9 +1167,12 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
|||
}else{
|
||||
RtreeCoord c;
|
||||
nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c);
|
||||
#ifndef SQLITE_RTREE_INT_ONLY
|
||||
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
|
||||
sqlite3_result_double(ctx, c.f);
|
||||
}else{
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
assert( pRtree->eCoordType==RTREE_COORD_INT32 );
|
||||
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. */
|
||||
nBlob = sqlite3_value_bytes(pValue);
|
||||
if( nBlob<(int)sizeof(RtreeMatchArg)
|
||||
|| ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0
|
||||
|| ((nBlob-sizeof(RtreeMatchArg))%sizeof(RtreeDValue))!=0
|
||||
){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
@ -1212,7 +1233,7 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
|
|||
|
||||
memcpy(p, sqlite3_value_blob(pValue), nBlob);
|
||||
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);
|
||||
return SQLITE_ERROR;
|
||||
|
@ -1284,7 +1305,11 @@ static int rtreeFilter(
|
|||
break;
|
||||
}
|
||||
}else{
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
p->rValue = sqlite3_value_int64(argv[ii]);
|
||||
#else
|
||||
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.
|
||||
*/
|
||||
static float cellArea(Rtree *pRtree, RtreeCell *p){
|
||||
float area = 1.0;
|
||||
static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
|
||||
RtreeDValue area = (RtreeDValue)1;
|
||||
int ii;
|
||||
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;
|
||||
}
|
||||
|
@ -1431,11 +1456,11 @@ static float cellArea(Rtree *pRtree, RtreeCell *p){
|
|||
** Return the margin length of cell p. The margin length is the sum
|
||||
** of the objects size in each dimension.
|
||||
*/
|
||||
static float cellMargin(Rtree *pRtree, RtreeCell *p){
|
||||
float margin = 0.0;
|
||||
static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
|
||||
RtreeDValue margin = (RtreeDValue)0;
|
||||
int ii;
|
||||
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;
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
|
||||
float area;
|
||||
static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
|
||||
RtreeDValue area;
|
||||
RtreeCell cell;
|
||||
memcpy(&cell, p, sizeof(RtreeCell));
|
||||
area = cellArea(pRtree, &cell);
|
||||
|
@ -1490,7 +1515,7 @@ static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
|
|||
}
|
||||
|
||||
#if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT
|
||||
static float cellOverlap(
|
||||
static RtreeDValue cellOverlap(
|
||||
Rtree *pRtree,
|
||||
RtreeCell *p,
|
||||
RtreeCell *aCell,
|
||||
|
@ -1498,7 +1523,7 @@ static float cellOverlap(
|
|||
int iExclude
|
||||
){
|
||||
int ii;
|
||||
float overlap = 0.0;
|
||||
RtreeDValue overlap = 0.0;
|
||||
for(ii=0; ii<nCell; ii++){
|
||||
#if VARIANT_RSTARTREE_CHOOSESUBTREE
|
||||
if( ii!=iExclude )
|
||||
|
@ -1508,10 +1533,9 @@ static float cellOverlap(
|
|||
#endif
|
||||
{
|
||||
int jj;
|
||||
float o = 1.0;
|
||||
RtreeDValue o = (RtreeDValue)1;
|
||||
for(jj=0; jj<(pRtree->nDim*2); jj+=2){
|
||||
double x1;
|
||||
double x2;
|
||||
RtreeDValue x1, x2;
|
||||
|
||||
x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj]));
|
||||
x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1]));
|
||||
|
@ -1520,7 +1544,7 @@ static float cellOverlap(
|
|||
o = 0.0;
|
||||
break;
|
||||
}else{
|
||||
o = o * (float)(x2-x1);
|
||||
o = o * (x2-x1);
|
||||
}
|
||||
}
|
||||
overlap += o;
|
||||
|
@ -1531,7 +1555,7 @@ static float cellOverlap(
|
|||
#endif
|
||||
|
||||
#if VARIANT_RSTARTREE_CHOOSESUBTREE
|
||||
static float cellOverlapEnlargement(
|
||||
static RtreeDValue cellOverlapEnlargement(
|
||||
Rtree *pRtree,
|
||||
RtreeCell *p,
|
||||
RtreeCell *pInsert,
|
||||
|
@ -1539,12 +1563,11 @@ static float cellOverlapEnlargement(
|
|||
int nCell,
|
||||
int iExclude
|
||||
){
|
||||
double before;
|
||||
double after;
|
||||
RtreeDValue before, after;
|
||||
before = cellOverlap(pRtree, p, aCell, nCell, iExclude);
|
||||
cellUnion(pRtree, p, pInsert);
|
||||
after = cellOverlap(pRtree, p, aCell, nCell, iExclude);
|
||||
return (float)(after-before);
|
||||
return (after-before);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1568,11 +1591,11 @@ static int ChooseLeaf(
|
|||
int iCell;
|
||||
sqlite3_int64 iBest = 0;
|
||||
|
||||
float fMinGrowth = 0.0;
|
||||
float fMinArea = 0.0;
|
||||
RtreeDValue fMinGrowth = 0.0;
|
||||
RtreeDValue fMinArea = 0.0;
|
||||
#if VARIANT_RSTARTREE_CHOOSESUBTREE
|
||||
float fMinOverlap = 0.0;
|
||||
float overlap;
|
||||
RtreeDValue fMinOverlap = 0.0;
|
||||
RtreeDValue overlap;
|
||||
#endif
|
||||
|
||||
int nCell = NCELL(pNode);
|
||||
|
@ -1603,8 +1626,8 @@ static int ChooseLeaf(
|
|||
*/
|
||||
for(iCell=0; iCell<nCell; iCell++){
|
||||
int bBest = 0;
|
||||
float growth;
|
||||
float area;
|
||||
RtreeDValue growth;
|
||||
RtreeDValue area;
|
||||
nodeGetCell(pRtree, pNode, iCell, &cell);
|
||||
growth = cellGrowth(pRtree, &cell, pCell);
|
||||
area = cellArea(pRtree, &cell);
|
||||
|
@ -1731,7 +1754,7 @@ static void LinearPickSeeds(
|
|||
int i;
|
||||
int iLeftSeed = 0;
|
||||
int iRightSeed = 1;
|
||||
float maxNormalInnerWidth = 0.0;
|
||||
RtreeDValue maxNormalInnerWidth = (RtreeDValue)0;
|
||||
|
||||
/* Pick two "seed" cells from the array of cells. The algorithm used
|
||||
** here is the LinearPickSeeds algorithm from Gutman[1984]. The
|
||||
|
@ -1739,18 +1762,18 @@ static void LinearPickSeeds(
|
|||
** variables iLeftSeek and iRightSeed.
|
||||
*/
|
||||
for(i=0; i<pRtree->nDim; i++){
|
||||
float x1 = DCOORD(aCell[0].aCoord[i*2]);
|
||||
float x2 = DCOORD(aCell[0].aCoord[i*2+1]);
|
||||
float x3 = x1;
|
||||
float x4 = x2;
|
||||
RtreeDValue x1 = DCOORD(aCell[0].aCoord[i*2]);
|
||||
RtreeDValue x2 = DCOORD(aCell[0].aCoord[i*2+1]);
|
||||
RtreeDValue x3 = x1;
|
||||
RtreeDValue x4 = x2;
|
||||
int jj;
|
||||
|
||||
int iCellLeft = 0;
|
||||
int iCellRight = 0;
|
||||
|
||||
for(jj=1; jj<nCell; jj++){
|
||||
float left = DCOORD(aCell[jj].aCoord[i*2]);
|
||||
float right = DCOORD(aCell[jj].aCoord[i*2+1]);
|
||||
RtreeDValue left = DCOORD(aCell[jj].aCoord[i*2]);
|
||||
RtreeDValue right = DCOORD(aCell[jj].aCoord[i*2+1]);
|
||||
|
||||
if( left<x1 ) x1 = left;
|
||||
if( right>x4 ) x4 = right;
|
||||
|
@ -1765,7 +1788,7 @@ static void LinearPickSeeds(
|
|||
}
|
||||
|
||||
if( x4!=x1 ){
|
||||
float normalwidth = (x3 - x2) / (x4 - x1);
|
||||
RtreeDValue normalwidth = (x3 - x2) / (x4 - x1);
|
||||
if( normalwidth>maxNormalInnerWidth ){
|
||||
iLeftSeed = iCellLeft;
|
||||
iRightSeed = iCellRight;
|
||||
|
@ -1794,13 +1817,13 @@ static RtreeCell *QuadraticPickNext(
|
|||
#define FABS(a) ((a)<0.0?-1.0*(a):(a))
|
||||
|
||||
int iSelect = -1;
|
||||
float fDiff;
|
||||
RtreeDValue fDiff;
|
||||
int ii;
|
||||
for(ii=0; ii<nCell; ii++){
|
||||
if( aiUsed[ii]==0 ){
|
||||
float left = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
|
||||
float right = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
|
||||
float diff = FABS(right-left);
|
||||
RtreeDValue left = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
|
||||
RtreeDValue right = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
|
||||
RtreeDValue diff = FABS(right-left);
|
||||
if( iSelect<0 || diff>fDiff ){
|
||||
fDiff = diff;
|
||||
iSelect = ii;
|
||||
|
@ -1827,13 +1850,13 @@ static void QuadraticPickSeeds(
|
|||
|
||||
int iLeftSeed = 0;
|
||||
int iRightSeed = 1;
|
||||
float fWaste = 0.0;
|
||||
RtreeDValue fWaste = 0.0;
|
||||
|
||||
for(ii=0; ii<nCell; ii++){
|
||||
for(jj=ii+1; jj<nCell; jj++){
|
||||
float right = cellArea(pRtree, &aCell[jj]);
|
||||
float growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]);
|
||||
float waste = growth - right;
|
||||
RtreeDValue right = cellArea(pRtree, &aCell[jj]);
|
||||
RtreeDValue growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]);
|
||||
RtreeDValue waste = growth - right;
|
||||
|
||||
if( waste>fWaste ){
|
||||
iLeftSeed = ii;
|
||||
|
@ -1868,7 +1891,7 @@ static void QuadraticPickSeeds(
|
|||
static void SortByDistance(
|
||||
int *aIdx,
|
||||
int nIdx,
|
||||
float *aDistance,
|
||||
RtreeDValue *aDistance,
|
||||
int *aSpare
|
||||
){
|
||||
if( nIdx>1 ){
|
||||
|
@ -1894,8 +1917,8 @@ static void SortByDistance(
|
|||
aIdx[iLeft+iRight] = aLeft[iLeft];
|
||||
iLeft++;
|
||||
}else{
|
||||
float fLeft = aDistance[aLeft[iLeft]];
|
||||
float fRight = aDistance[aRight[iRight]];
|
||||
RtreeDValue fLeft = aDistance[aLeft[iLeft]];
|
||||
RtreeDValue fRight = aDistance[aRight[iRight]];
|
||||
if( fLeft<fRight ){
|
||||
aIdx[iLeft+iRight] = aLeft[iLeft];
|
||||
iLeft++;
|
||||
|
@ -1911,8 +1934,8 @@ static void SortByDistance(
|
|||
{
|
||||
int jj;
|
||||
for(jj=1; jj<nIdx; jj++){
|
||||
float left = aDistance[aIdx[jj-1]];
|
||||
float right = aDistance[aIdx[jj]];
|
||||
RtreeDValue left = aDistance[aIdx[jj-1]];
|
||||
RtreeDValue right = aDistance[aIdx[jj]];
|
||||
assert( left<=right );
|
||||
}
|
||||
}
|
||||
|
@ -1955,10 +1978,10 @@ static void SortByDimension(
|
|||
memcpy(aSpare, aLeft, sizeof(int)*nLeft);
|
||||
aLeft = aSpare;
|
||||
while( iLeft<nLeft || iRight<nRight ){
|
||||
double xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]);
|
||||
double xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]);
|
||||
double xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]);
|
||||
double xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]);
|
||||
RtreeDValue xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]);
|
||||
RtreeDValue xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]);
|
||||
RtreeDValue xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]);
|
||||
RtreeDValue xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]);
|
||||
if( (iLeft!=nLeft) && ((iRight==nRight)
|
||||
|| (xleft1<xright1)
|
||||
|| (xleft1==xright1 && xleft2<xright2)
|
||||
|
@ -1976,10 +1999,10 @@ static void SortByDimension(
|
|||
{
|
||||
int jj;
|
||||
for(jj=1; jj<nIdx; jj++){
|
||||
float xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2];
|
||||
float xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1];
|
||||
float xright1 = aCell[aIdx[jj]].aCoord[iDim*2];
|
||||
float xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1];
|
||||
RtreeDValue xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2];
|
||||
RtreeDValue xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1];
|
||||
RtreeDValue xright1 = aCell[aIdx[jj]].aCoord[iDim*2];
|
||||
RtreeDValue xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1];
|
||||
assert( xleft1<=xright1 && (xleft1<xright1 || xleft2<=xright2) );
|
||||
}
|
||||
}
|
||||
|
@ -2006,7 +2029,7 @@ static int splitNodeStartree(
|
|||
|
||||
int iBestDim = 0;
|
||||
int iBestSplit = 0;
|
||||
float fBestMargin = 0.0;
|
||||
RtreeDValue fBestMargin = 0.0;
|
||||
|
||||
int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
|
||||
|
||||
|
@ -2027,9 +2050,9 @@ static int splitNodeStartree(
|
|||
}
|
||||
|
||||
for(ii=0; ii<pRtree->nDim; ii++){
|
||||
float margin = 0.0;
|
||||
float fBestOverlap = 0.0;
|
||||
float fBestArea = 0.0;
|
||||
RtreeDValue margin = 0.0;
|
||||
RtreeDValue fBestOverlap = 0.0;
|
||||
RtreeDValue fBestArea = 0.0;
|
||||
int iBestLeft = 0;
|
||||
int nLeft;
|
||||
|
||||
|
@ -2041,8 +2064,8 @@ static int splitNodeStartree(
|
|||
RtreeCell left;
|
||||
RtreeCell right;
|
||||
int kk;
|
||||
float overlap;
|
||||
float area;
|
||||
RtreeDValue overlap;
|
||||
RtreeDValue area;
|
||||
|
||||
memcpy(&left, &aCell[aaSorted[ii][0]], 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--){
|
||||
RtreeCell *pNext;
|
||||
pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed);
|
||||
float diff =
|
||||
RtreeDValue diff =
|
||||
cellGrowth(pRtree, pBboxLeft, pNext) -
|
||||
cellGrowth(pRtree, pBboxRight, pNext)
|
||||
;
|
||||
|
@ -2458,32 +2481,34 @@ static int Reinsert(
|
|||
int *aOrder;
|
||||
int *aSpare;
|
||||
RtreeCell *aCell;
|
||||
float *aDistance;
|
||||
RtreeDValue *aDistance;
|
||||
int nCell;
|
||||
float aCenterCoord[RTREE_MAX_DIMENSIONS];
|
||||
RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS];
|
||||
int iDim;
|
||||
int ii;
|
||||
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;
|
||||
n = (nCell+1)&(~1);
|
||||
|
||||
/* Allocate the buffers used by this operation. The allocation is
|
||||
** relinquished before this function returns.
|
||||
*/
|
||||
aCell = (RtreeCell *)sqlite3_malloc(nCell * (
|
||||
aCell = (RtreeCell *)sqlite3_malloc(n * (
|
||||
sizeof(RtreeCell) + /* aCell array */
|
||||
sizeof(int) + /* aOrder array */
|
||||
sizeof(int) + /* aSpare array */
|
||||
sizeof(float) /* aDistance array */
|
||||
sizeof(RtreeDValue) /* aDistance array */
|
||||
));
|
||||
if( !aCell ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
aOrder = (int *)&aCell[nCell];
|
||||
aSpare = (int *)&aOrder[nCell];
|
||||
aDistance = (float *)&aSpare[nCell];
|
||||
aOrder = (int *)&aCell[n];
|
||||
aSpare = (int *)&aOrder[n];
|
||||
aDistance = (RtreeDValue *)&aSpare[n];
|
||||
|
||||
for(ii=0; ii<nCell; ii++){
|
||||
if( ii==(nCell-1) ){
|
||||
|
@ -2493,18 +2518,18 @@ static int Reinsert(
|
|||
}
|
||||
aOrder[ii] = ii;
|
||||
for(iDim=0; iDim<pRtree->nDim; iDim++){
|
||||
aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2]);
|
||||
aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2+1]);
|
||||
aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]);
|
||||
aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]);
|
||||
}
|
||||
}
|
||||
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++){
|
||||
aDistance[ii] = 0.0;
|
||||
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]));
|
||||
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]. */
|
||||
assert( nData==(pRtree->nDim*2 + 3) );
|
||||
#ifndef SQLITE_RTREE_INT_ONLY
|
||||
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
|
||||
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
|
||||
cell.aCoord[ii].f = (float)sqlite3_value_double(azData[ii+3]);
|
||||
cell.aCoord[ii+1].f = (float)sqlite3_value_double(azData[ii+4]);
|
||||
cell.aCoord[ii].f = (RtreeValue)sqlite3_value_double(azData[ii+3]);
|
||||
cell.aCoord[ii+1].f = (RtreeValue)sqlite3_value_double(azData[ii+4]);
|
||||
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
|
||||
rc = SQLITE_CONSTRAINT;
|
||||
goto constraint;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
|
||||
cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
|
||||
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);
|
||||
nCell = (int)strlen(zCell);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -3196,7 +3230,11 @@ int sqlite3RtreeInit(sqlite3 *db){
|
|||
rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
void *c = (void *)RTREE_COORD_INT32;
|
||||
#else
|
||||
void *c = (void *)RTREE_COORD_REAL32;
|
||||
#endif
|
||||
rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
|
@ -3230,7 +3268,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
|
|||
RtreeMatchArg *pBlob;
|
||||
int nBlob;
|
||||
|
||||
nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(double);
|
||||
nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue);
|
||||
pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
|
||||
if( !pBlob ){
|
||||
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->nParam = nArg;
|
||||
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]);
|
||||
#endif
|
||||
}
|
||||
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(
|
||||
sqlite3 *db,
|
||||
const char *zGeom,
|
||||
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *),
|
||||
int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue *, int *),
|
||||
void *pContext
|
||||
){
|
||||
RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */
|
||||
|
|
|
@ -104,6 +104,18 @@ for {set nCol 1} {$nCol<[llength $cols]} {incr nCol} {
|
|||
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
|
||||
# r-tree tables.
|
||||
#
|
||||
|
@ -117,8 +129,8 @@ do_test rtree-1.4.1 {
|
|||
do_test rtree-1.4.2 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { SELECT * FROM t1 ORDER BY ii }
|
||||
} {1 5.0 10.0 2 15.0 20.0}
|
||||
execsql_intout { SELECT * FROM t1 ORDER BY ii }
|
||||
} {1 5 10 2 15 20}
|
||||
do_test rtree-1.4.3 {
|
||||
execsql { DROP TABLE t1 }
|
||||
} {}
|
||||
|
@ -127,12 +139,12 @@ do_test rtree-1.4.3 {
|
|||
# column names.
|
||||
#
|
||||
do_test rtree-1.5.1 {
|
||||
execsql {
|
||||
execsql_intout {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree("the key", "x dim.", "x2'dim");
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
SELECT "the key", "x dim.", "x2'dim" FROM t1;
|
||||
}
|
||||
} {1 2.0 3.0}
|
||||
} {1 2 3}
|
||||
do_test rtree-1.5.1 {
|
||||
execsql { DROP TABLE t1 }
|
||||
} {}
|
||||
|
@ -161,8 +173,8 @@ do_test rtree-2.1.1 {
|
|||
|
||||
do_test rtree-2.1.2 {
|
||||
execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
|
||||
execsql { SELECT * FROM t1 }
|
||||
} {1 1.0 3.0 2.0 4.0}
|
||||
execsql_intout { SELECT * FROM t1 }
|
||||
} {1 1 3 2 4}
|
||||
do_test rtree-2.1.3 {
|
||||
execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
|
||||
execsql { SELECT rowid FROM t1 ORDER BY rowid }
|
||||
|
@ -201,17 +213,17 @@ do_test rtree-3.1.1 {
|
|||
}
|
||||
} {}
|
||||
do_test rtree-3.1.2 {
|
||||
execsql {
|
||||
execsql_intout {
|
||||
INSERT INTO t1 VALUES(5, 1, 3, 2, 4);
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {5 1.0 3.0 2.0 4.0}
|
||||
} {5 1 3 2 4}
|
||||
do_test rtree-3.1.3 {
|
||||
execsql {
|
||||
execsql_intout {
|
||||
INSERT INTO t1 VALUES(6, 2, 6, 4, 8);
|
||||
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)):
|
||||
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) }
|
||||
} {}
|
||||
do_test rtree-5.1.2 {
|
||||
execsql {
|
||||
execsql_intout {
|
||||
INSERT INTO t2 VALUES(1, 10, 20);
|
||||
INSERT INTO t2 VALUES(2, 30, 40);
|
||||
INSERT INTO t2 VALUES(3, 50, 60);
|
||||
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 {
|
||||
execsql {
|
||||
execsql_intout {
|
||||
DELETE FROM t2 WHERE ii=2;
|
||||
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 {
|
||||
execsql {
|
||||
execsql_intout {
|
||||
DELETE FROM t2 WHERE ii=1;
|
||||
SELECT * FROM t2 ORDER BY ii;
|
||||
}
|
||||
} {3 50.0 60.0}
|
||||
} {3 50 60}
|
||||
do_test rtree-5.1.5 {
|
||||
execsql {
|
||||
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) }
|
||||
} {}
|
||||
do_test rtree-6.1.2 {
|
||||
execsql {
|
||||
execsql_intout {
|
||||
INSERT INTO t3 VALUES(1, 2, 3, 4, 5);
|
||||
UPDATE t3 SET x2=5;
|
||||
SELECT * FROM t3;
|
||||
}
|
||||
} {1 2.0 5.0 4.0 5.0}
|
||||
} {1 2 5 4 5}
|
||||
do_test rtree-6.1.3 {
|
||||
execsql { UPDATE t3 SET ii = 2 }
|
||||
execsql { SELECT * FROM t3 }
|
||||
} {2 2.0 5.0 4.0 5.0}
|
||||
execsql_intout { SELECT * FROM t3 }
|
||||
} {2 2 5 4 5}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases rtree-7.* test rename operations.
|
||||
|
@ -286,29 +298,29 @@ do_test rtree-7.1.1 {
|
|||
} {}
|
||||
do_test rtree-7.1.2 {
|
||||
execsql { ALTER TABLE t4 RENAME TO t5 }
|
||||
execsql { SELECT * FROM t5 }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
execsql_intout { SELECT * FROM t5 }
|
||||
} {1 2 3 4 5 6 7}
|
||||
do_test rtree-7.1.3 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { SELECT * FROM t5 }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
execsql_intout { SELECT * FROM t5 }
|
||||
} {1 2 3 4 5 6 7}
|
||||
do_test rtree-7.1.4 {
|
||||
execsql { ALTER TABLE t5 RENAME TO 'raisara "one"'''}
|
||||
execsql { SELECT * FROM "raisara ""one""'" }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
execsql_intout { SELECT * FROM "raisara ""one""'" }
|
||||
} {1 2 3 4 5 6 7}
|
||||
do_test rtree-7.1.5 {
|
||||
execsql { SELECT * FROM 'raisara "one"''' }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
execsql_intout { SELECT * FROM 'raisara "one"''' }
|
||||
} {1 2 3 4 5 6 7}
|
||||
do_test rtree-7.1.6 {
|
||||
execsql { ALTER TABLE "raisara ""one""'" RENAME TO "abc 123" }
|
||||
execsql { SELECT * FROM "abc 123" }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
execsql_intout { SELECT * FROM "abc 123" }
|
||||
} {1 2 3 4 5 6 7}
|
||||
do_test rtree-7.1.7 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { SELECT * FROM "abc 123" }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
execsql_intout { SELECT * FROM "abc 123" }
|
||||
} {1 2 3 4 5 6 7}
|
||||
|
||||
# An error midway through a rename operation.
|
||||
do_test rtree-7.2.1 {
|
||||
|
@ -318,8 +330,8 @@ do_test rtree-7.2.1 {
|
|||
catchsql { ALTER TABLE "abc 123" RENAME TO t4 }
|
||||
} {1 {SQL logic error or missing database}}
|
||||
do_test rtree-7.2.2 {
|
||||
execsql { SELECT * FROM "abc 123" }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
execsql_intout { SELECT * FROM "abc 123" }
|
||||
} {1 2 3 4 5 6 7}
|
||||
do_test rtree-7.2.3 {
|
||||
execsql {
|
||||
DROP TABLE t4_node;
|
||||
|
@ -330,13 +342,13 @@ do_test rtree-7.2.3 {
|
|||
do_test rtree-7.2.4 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { SELECT * FROM "abc 123" }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
execsql_intout { SELECT * FROM "abc 123" }
|
||||
} {1 2 3 4 5 6 7}
|
||||
do_test rtree-7.2.5 {
|
||||
execsql { DROP TABLE t4_rowid }
|
||||
execsql { ALTER TABLE "abc 123" RENAME TO t4 }
|
||||
execsql { SELECT * FROM t4 }
|
||||
} {1 2.0 3.0 4.0 5.0 6.0 7.0}
|
||||
execsql_intout { SELECT * FROM t4 }
|
||||
} {1 2 3 4 5 6 7}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
|
@ -27,6 +27,7 @@ if {[info exists G(isquick)] && $G(isquick)} {
|
|||
set ::NROW 250
|
||||
}
|
||||
|
||||
ifcapable !rtree_int_only {
|
||||
# Return a floating point number between -X and X.
|
||||
#
|
||||
proc rand {X} {
|
||||
|
@ -41,6 +42,22 @@ proc randincr {X} {
|
|||
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.
|
||||
#
|
||||
|
|
|
@ -49,9 +49,11 @@ do_test rtree5-1.6 {
|
|||
do_test rtree5-1.7 {
|
||||
execsql { SELECT count(*) FROM t1 WHERE x1==5 }
|
||||
} {1}
|
||||
ifcapable !rtree_int_only {
|
||||
do_test rtree5-1.8 {
|
||||
execsql { SELECT count(*) FROM t1 WHERE x1==5.2 }
|
||||
} {0}
|
||||
}
|
||||
do_test rtree5-1.9 {
|
||||
execsql { SELECT count(*) FROM t1 WHERE x1==5.0 }
|
||||
} {1}
|
||||
|
|
|
@ -16,7 +16,7 @@ if {![info exists testdir]} {
|
|||
}
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !rtree {
|
||||
ifcapable {!rtree || rtree_int_only} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
|
|
@ -24,6 +24,18 @@ ifcapable !rtree||!vacuum {
|
|||
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 {
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
|
@ -32,27 +44,27 @@ do_test rtree7-1.1 {
|
|||
}
|
||||
} {}
|
||||
do_test rtree7-1.2 {
|
||||
execsql { SELECT * FROM rt }
|
||||
} {1 1.0 2.0 3.0 4.0}
|
||||
execsql_intout { SELECT * FROM rt }
|
||||
} {1 1 2 3 4}
|
||||
do_test rtree7-1.3 {
|
||||
execsql {
|
||||
execsql_intout {
|
||||
PRAGMA page_size = 2048;
|
||||
VACUUM;
|
||||
SELECT * FROM rt;
|
||||
}
|
||||
} {1 1.0 2.0 3.0 4.0}
|
||||
} {1 1 2 3 4}
|
||||
do_test rtree7-1.4 {
|
||||
for {set i 2} {$i <= 51} {incr i} {
|
||||
execsql { INSERT INTO rt VALUES($i, 1, 2, 3, 4) }
|
||||
}
|
||||
execsql { SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt }
|
||||
} {51.0 102.0 153.0 204.0}
|
||||
execsql_intout { SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt }
|
||||
} {51 102 153 204}
|
||||
do_test rtree7-1.5 {
|
||||
execsql {
|
||||
execsql_intout {
|
||||
PRAGMA page_size = 512;
|
||||
VACUUM;
|
||||
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
|
||||
|
|
|
@ -17,6 +17,7 @@ if {![info exists testdir]} {
|
|||
}
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !rtree { finish_test ; return }
|
||||
ifcapable rtree_int_only { finish_test; return }
|
||||
|
||||
register_cube_geom db
|
||||
|
||||
|
|
|
@ -18,6 +18,19 @@ if {![info exists testdir]} {
|
|||
source $testdir/tester.tcl
|
||||
ifcapable !rtree { finish_test ; return }
|
||||
|
||||
ifcapable rtree_int_only {
|
||||
do_test rtreeB-1.1-intonly {
|
||||
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 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);
|
||||
|
@ -29,6 +42,6 @@ do_test rtreeB-1.1 {
|
|||
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
|
||||
|
|
|
@ -31,7 +31,11 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
|
|||
int sqlite3_rtree_geometry_callback(
|
||||
sqlite3 *db,
|
||||
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
|
||||
);
|
||||
|
||||
|
|
127
manifest
127
manifest
|
@ -1,5 +1,5 @@
|
|||
C When\scompiling\sfor\sWinRT,\salways\suse\sthe\s'appcontainer'\slinker\soption.
|
||||
D 2012-04-17T21:00:12.605
|
||||
C Import\sall\sthe\slatest\strunk\schanges\sinto\sthe\sWinRT\sbranch.\s\sRefactor\sand/or\sremove\sWinCE-specific\smacros\sand\sfunctions\sused\sfor\sfile\slocking\sto\simprove\sclarity\sof\spresentation.
|
||||
D 2012-04-18T05:57:38.819
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
|
@ -23,7 +23,7 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
|
|||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure 4ee31677412c454d0978a64872faf3ec36ff94ca x
|
||||
F configure eb9e5e7f4c1601b5acf674a724e1a778481d2835 x
|
||||
F configure.ac 9ee886c21c095b3272137b1553ae416c8b8c8557
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
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_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
|
||||
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_snippet.c 51a3a34c217e24678a133782c1dfb6f2f70fe559
|
||||
F ext/fts3/fts3_term.c d3466cf99432291be08e379d89645462431809d6
|
||||
F ext/fts3/fts3_test.c 6b7cc68aef4efb084e1449f7d20c4b20d3bdf6b4
|
||||
F ext/fts3/fts3_term.c 41e82ad335213d1c24356cf310dca1d3c13e7366
|
||||
F ext/fts3/fts3_test.c f153a121c763993e3d94cc99c012ee68d13231ae
|
||||
F ext/fts3/fts3_tokenizer.c 3da7254a9881f7e270ab28e2004e0d22b3212bce
|
||||
F ext/fts3/fts3_tokenizer.h 66dec98e365854b6cd2d54f1a96bb6d428fc5a68
|
||||
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/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
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/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
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/rtree1.test 28e1b8da4da98093ce3210187434dd760a8d89d8
|
||||
F ext/rtree/rtree1.test e474a2b5eff231496dbd073fe67e5fbaf7f444c9
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
|
||||
F ext/rtree/rtree4.test 0061e6f464fd3dc6a79f82454c5a1c3dadbe42af
|
||||
F ext/rtree/rtree5.test ce3d7ccae2cfd9d2e1052b462424964c9bdcda12
|
||||
F ext/rtree/rtree6.test 0b380bd9af93f3bc496eef42502a336f58949c1b
|
||||
F ext/rtree/rtree7.test bcb647b42920b3b5d025846689147778485cc318
|
||||
F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
|
||||
F ext/rtree/rtree5.test 9a229678a00f40e6aedb40cb3a07ec5444af892c
|
||||
F ext/rtree/rtree6.test 3ff9113b4a872fa935309e3511cd9b7cdb4d2472
|
||||
F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
|
||||
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/rtreeB.test b1916a9cecb86b02529c4cc5a546e8d6e7ff10da
|
||||
F ext/rtree/rtreeB.test 983e567b49b5dca165940f66b87e161aa30e82b2
|
||||
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
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/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
|
@ -126,16 +126,16 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
|||
F src/backup.c 6be23a344d3301ae38e92fddb3a33b91c309fce4
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 02aeee1f6d425e11f7b9b2d9d461ac501645ed6f
|
||||
F src/btree.c df800f10896bc2ddaa1125c532d6e7a7b9efc532
|
||||
F src/btree.h 48a013f8964f12d944d90e4700df47b72dd6d923
|
||||
F src/btreeInt.h 26d8ca625b141927fe6620c1d2cf58eaf494ca0c
|
||||
F src/build.c 139dc386ebdaa78d2198247ebcf003305a5babe3
|
||||
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
|
||||
F src/btreeInt.h 38a639c0542c29fe8331a221c4aed0cb8686249e
|
||||
F src/build.c 987c6933ea170e443dc6a79d52f8d2506206b12b
|
||||
F src/callback.c 0cb4228cdcd827dcc5def98fb099edcc9142dbcd
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 500d019da966631ad957c37705642be87524463b
|
||||
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
||||
F src/delete.c 4c20ea4f6213b3bc1c6a510586864b679946e05e
|
||||
F src/expr.c 7e40ea9f6899e31134be3c1b88b8347cf9ec40d7
|
||||
F src/expr.c 1b2383adc4391ddae38abb71fd4690a3af8efb01
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
|
||||
F src/func.c c6b3c94320253a35bda43fb69cc292618e3285d6
|
||||
|
@ -143,7 +143,7 @@ F src/global.c 4cfdca5cb0edd33c4d021baec4ede958cb2c793b
|
|||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c d7c69718acbb92e10e4b121da7bed13903342962
|
||||
F src/insert.c 0bbffe75c254c62a5686ab5e7f88e29235e16174
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
|
||||
|
@ -167,11 +167,11 @@ F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c
|
|||
F src/os.h 38aabd5e3ecd4162332076f55bb09cec02165cca
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
|
||||
F src/os_unix.c 0e3d2942d228d0366fb80a3640f35caf413b66d1
|
||||
F src/os_win.c 6f8080e783082d3d94ea56537f2248df4e273843
|
||||
F src/os_unix.c 424d46e0edab969293c2223f09923b2178171f47
|
||||
F src/os_win.c c3487c9c506c1253bb4c65abc3caf988b9addb6c
|
||||
F src/pager.c 85988507fa20acc60defb834722eddf4633e4aeb
|
||||
F src/pager.h ef1eaf8593e78f73885c1dfac27ad83bee23bdc5
|
||||
F src/parse.y 537c8db136af5f481630becdc0c8bdd36a704c30
|
||||
F src/parse.y eb054bb40a5bf90d3422a01ed0e5df229461727a
|
||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||
F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c
|
||||
F src/pcache1.c b30b1c35908346ecc43d8d9d17f2ddf6817f8f60
|
||||
|
@ -179,23 +179,23 @@ F src/pragma.c 149d8400ff783741d41389176832241cbff8f856
|
|||
F src/prepare.c ec4989f7f480544bdc4192fe663470d2a2d7d61e
|
||||
F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 3d3e80a98f203ac6b9329e9621e29eda85ddfd40
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c f6f141cb1ea13f1e6564d3e162700e4937baa2a1
|
||||
F src/shell.c abf18d6ee54f2631860a98fdd7ab1327f470db67
|
||||
F src/sqlite.h.in d7f0850ad874328e7ca477f836e8c5d189fbc7a2
|
||||
F src/resolve.c 969ec2bc52db1b068054ecf5ddc74f244102a71d
|
||||
F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1
|
||||
F src/select.c d7b9018b7dd2e821183d69477ab55c39b8272335
|
||||
F src/shell.c 11185a9a4574f363bd4268a2780d37480ae00040
|
||||
F src/sqlite.h.in 21eb2ff783710a8cf2b435890dc1ffc750058169
|
||||
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
|
||||
F src/sqliteInt.h 3756ece33f1e7f8fe2adf8e523566825c809316e
|
||||
F src/sqliteInt.h c5e917c4f1453f3972b1fd0c81105dfe4f09cc32
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 086dfdd72e5892de223968a258e1ccbd9693e717
|
||||
F src/test1.c 1a1df7eed3e8b58987b5716de7a37cc79a10f3f2
|
||||
F src/test1.c 9667a33a4fc849ce668501ae21cf6fb04898c6a9
|
||||
F src/test2.c 711555927f1f7e8db9aab86b512bc6934a774abe
|
||||
F src/test3.c 91d3f1a09cfae3533ef17d8b484a160f3d1f1a21
|
||||
F src/test3.c f82399ec50d9cd7378bf9d6db6c1409d5e77b042
|
||||
F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
|
||||
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
|
||||
F src/test6.c 846ed1ed2f470de9b1e205fe3878a12e237b3e19
|
||||
F src/test6.c 3329df2dbc0293031d763947ec08c9eef982ef1d
|
||||
F src/test7.c 2e0781754905c8adc3268d8f0967e7633af58843
|
||||
F src/test8.c 61b41d79509a479dec1ac32b6d4209b27c4b1ba5
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
|
@ -203,37 +203,37 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
|
|||
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
|
||||
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
|
||||
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
|
||||
F src/test_config.c f82aa7dd51f42256ac18ffba3217ebffa9db85a3
|
||||
F src/test_config.c 16f4bcb82fa82b39e92c8de49962a63b87e5faad
|
||||
F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
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_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a
|
||||
F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
|
||||
F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
|
||||
F src/test_journal.c a6a6baf343f79b942331f13378d045e7e270ae64
|
||||
F src/test_journal.c b964473ff1b7a65626763f068fa6a810385d1fbf
|
||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||
F src/test_malloc.c 3f5903a1528fd32fe4c472a3bd0259128d8faaef
|
||||
F src/test_multiplex.c 0404a61d7795438be5ee5fd3711eed80724df34d
|
||||
F src/test_multiplex.c 3dffd0fe6c96ac7c5150485b55244e73faab5380
|
||||
F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d
|
||||
F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
|
||||
F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
|
||||
F src/test_osinst.c 6abf0a37ce831120c4ef1b913afdd813e7ac1a73
|
||||
F src/test_onefile.c 5e1382e7844c703c77c4c2aee82f8359555b5a8e
|
||||
F src/test_osinst.c 7f790ac89c5a585d51b341274d9691c3391e0923
|
||||
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
|
||||
F src/test_quota.c b4a6519417d87870e7ef5838dbf3cae164dcc28d
|
||||
F src/test_quota.h 9ffa1d3ad6d0a6a24e8670ea64b909c717ec3358
|
||||
F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1
|
||||
F src/test_quota.c 2ab468f5817b84f7105f78b77c300649ea5af8d1
|
||||
F src/test_quota.h ee5da2ae7f84d1c8e0e0e2ab33f01d69f10259b5
|
||||
F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9
|
||||
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
|
||||
F src/test_stat.c 80271ad7d776a79babe0e025bb3a1bfcd3a3cfb1
|
||||
F src/test_stat.c d7035cfcc0ff1f93c000b621f36524318e004e11
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_syscall.c a992d8c80ea91fbf21fb2dd570db40e77dd7e6ae
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c e286f2173563f2a1747c24bcda6b9d030bf4f4e4
|
||||
F src/test_vfs.c 73f46bd9b5183ebcb77da22773886b81157cdc3d
|
||||
F src/test_vfstrace.c 6b28adb2a0e8ecd0f2e3581482e1f658b11b4067
|
||||
F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
|
||||
F src/test_wholenumber.c 3d2b9ed1505c40ad5c5ca2ad16ae7a289d6cc251
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12
|
||||
F src/trigger.c ee7e178fb9188f44b532cebd449a7c1df90fb684
|
||||
|
@ -241,13 +241,13 @@ F src/update.c d3076782c887c10e882996550345da9c4c9f9dea
|
|||
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
|
||||
F src/util.c 4f6cfad661b2e3454b0cdd5b1b9d39a54942d0e3
|
||||
F src/vacuum.c bfd53f9bd20a8fdb70b0fa8e77182b866875c0d8
|
||||
F src/vdbe.c 8913926230bfc9d183fcd44e3d023c6d393b6548
|
||||
F src/vdbe.c e1d26b98288889c22f00cf4851ec351ee67ad8b9
|
||||
F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb
|
||||
F src/vdbeInt.h 6ff4180a05683566a8835d12f7ec504b22932c82
|
||||
F src/vdbeapi.c 3662b6a468a2a4605a15dfab313baa6dff81ad91
|
||||
F src/vdbeaux.c 79cf42b70e211a52d664fc4d585ee2da0a64deac
|
||||
F src/vdbeaux.c d52c8a424fdd4b1d5cf1ac93cc7cd20da023ec5c
|
||||
F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
|
||||
F src/vdbemem.c fb0ac964ccbcd94f595eb993c05bfd9c52468a4a
|
||||
F src/vdbemem.c cb55e84b8e2c15704968ee05f0fae25883299b74
|
||||
F src/vdbesort.c b25814d385895544ebc8118245c8311ded7f81c9
|
||||
F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843
|
||||
F src/vtab.c ab90fb600a3f5e4b7c48d22a4cdb2d6b23239847
|
||||
|
@ -316,13 +316,13 @@ F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
|
|||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test f64136b0893c293d0b910ed057b3b711249099a7
|
||||
F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360
|
||||
F test/capi3.test 9c8b58b6a6aeb14e69bd8c8c7721b47d640464d1
|
||||
F test/capi3.test 8dedb0050610e9ff95cd9d487beb0ce5f33a31ee
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test 1b5424d2ac57b7b443b5de5b9a287642c02279b6
|
||||
F test/capi3c.test 01f197d73f4d4d66316483662f475cab7ab5bd60
|
||||
F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1
|
||||
F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/check.test db2b29d557544347d28e25b8406f5d5ecc3d1bc3
|
||||
F test/check.test 06795c188bf1776673fd2ac0787aa1c7238970d8
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04
|
||||
F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49
|
||||
|
@ -477,7 +477,7 @@ F test/fts3corrupt.test 7b0f91780ca36118d73324ec803187208ad33b32
|
|||
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
|
||||
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
|
||||
F test/fts3d.test bf640d79722b720fa1c81834c48cdaa45d531b1a
|
||||
F test/fts3defer.test 2ea3fa028f8d9523f9c33dd8acc4555d567ea4ac
|
||||
F test/fts3defer.test 6c2707be1b05b9790ba8ff91d3391d5fb425269e
|
||||
F test/fts3defer2.test 35867d33ba6db03f6c73bd6f5fc333ae14f68c81
|
||||
F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297
|
||||
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
|
||||
|
@ -502,7 +502,7 @@ F test/fts4content.test 17b2360f7d1a9a7e5aa8022783f5c5731b6dfd4f
|
|||
F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7
|
||||
F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee
|
||||
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
|
||||
F test/fts4merge3.test 640611c05f01e9e018ac10afd188b018d8fcd4e5
|
||||
F test/fts4merge3.test 125c3334f49bc171b3310efc99358cd05475c1d6
|
||||
F test/func.test 9809b7622d721904a8cc33c1ffb87f46d506ed01
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
|
||||
|
@ -515,7 +515,7 @@ F test/fuzzer1.test 69cf1036b92fd3b8e1fd65bef4d7ee3f085c28fb
|
|||
F test/fuzzerfault.test ff2282c81797b6a355f0748d8b54c7287c5d2b25
|
||||
F test/hook.test 5f3749de6462a6b87b4209b74adf7df5ac2df639
|
||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test a7b8a0f43da81cd08645b7a710099ffe9ad1126b
|
||||
F test/in.test 5941096407d8c133b9eff15bd3e666624b6cbde3
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
|
||||
|
@ -651,7 +651,7 @@ F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
|||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26
|
||||
F test/quota.test b5b3eec55a059e0fe493c66c6e27bd2c07676cfd
|
||||
F test/quota2.test 8ce58614614cd2b4eb70cd378e616811aed7b34e
|
||||
F test/quota2.test de299a13c41e90101e48a725e31f9b7425da1356
|
||||
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
|
||||
F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
|
||||
|
@ -669,6 +669,7 @@ F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec
|
|||
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
|
||||
F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
|
||||
F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423
|
||||
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
|
||||
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
|
||||
F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
|
||||
|
@ -712,7 +713,7 @@ F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
|||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 08e8185b3fd5b010c90d7ad82b9dd4ea1cbf14b0
|
||||
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
|
||||
F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
|
||||
F test/subquery.test c5e0d183f1ae6251453338a465b32ae11326e0fa
|
||||
F test/subquery2.test edcad5c118f0531c2e21bf16a09bbb105252d4cd
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
|
@ -955,7 +956,7 @@ F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
|||
F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F test/zerodamage.test 0de750389990b1078bab203c712dc3fefd1d8b82
|
||||
F tool/build-shell.sh 12aa4391073a777fcb6dcc490b219a018ae98bac
|
||||
F tool/build-shell.sh b64a481901fc9ffe5ca8812a2a9255b6cfb77381
|
||||
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
||||
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
|
||||
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
|
||||
|
@ -981,12 +982,12 @@ F tool/shell2.test 5dc76b8005b465f420fed8241621da7513060ff3
|
|||
F tool/shell3.test 4fad469e8003938426355afdf34155f08c587836
|
||||
F tool/shell4.test 35f9c3d452b4e76d5013c63e1fd07478a62f14ce
|
||||
F tool/shell5.test 0e987fb8d40638bb5c90163cb58cbe3e07dbed56
|
||||
F tool/showdb.c 43e913d954684c2f5007dcab46d1a1308852a0ad
|
||||
F tool/showdb.c 2e28d8e499b016485672e9a7ac65dacc0d28ff69
|
||||
F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02
|
||||
F tool/showwal.c f09e5a80a293919290ec85a6a37c85a5ddcf37d9
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
|
||||
F tool/spaceanal.tcl 15f6cd939b4ecc14d061de7e8ace89e26c30c40b
|
||||
F tool/spaceanal.tcl e42273000686a4afbf6a5e5d7fb12be65e92afb1
|
||||
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
|
||||
F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
|
@ -997,9 +998,9 @@ F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
|
|||
F tool/symbols.sh fec58532668296d7c7dc48be9c87f75ccdb5814f
|
||||
F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
|
||||
F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
P a1a85b846aac07979e732a9f36d178bd567e103a
|
||||
R 4b6ce0aef842e29a9d007bcf92b1249b
|
||||
P 300bcfe31102d4428567d56810b57d1d54c1d43b 430bb59d798286a86c351de92c429345f016b3f0
|
||||
R f8499f4b4cfea9459167b2ec1c6f0e24
|
||||
U mistachkin
|
||||
Z ed5b0893d8bcb11e5301ff71a81a98a7
|
||||
Z c68bf45e8579755b27c882f840c88e2c
|
||||
|
|
|
@ -1 +1 @@
|
|||
300bcfe31102d4428567d56810b57d1d54c1d43b
|
||||
ad5cd15f49b286896f94ab1ff207077beee40e12
|
42
src/btree.c
42
src/btree.c
|
@ -7554,6 +7554,25 @@ static void checkAppendMsg(
|
|||
#endif /* 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
|
||||
** 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);
|
||||
return 1;
|
||||
}
|
||||
if( pCheck->anRef[iPage]==1 ){
|
||||
if( getPageReferenced(pCheck, iPage) ){
|
||||
checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage);
|
||||
return 1;
|
||||
}
|
||||
return (pCheck->anRef[iPage]++)>1;
|
||||
setPageReferenced(pCheck, iPage);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
|
@ -7948,17 +7968,15 @@ char *sqlite3BtreeIntegrityCheck(
|
|||
sqlite3BtreeLeave(p);
|
||||
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;
|
||||
sqlite3BtreeLeave(p);
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; }
|
||||
i = PENDING_BYTE_PAGE(pBt);
|
||||
if( i<=sCheck.nPage ){
|
||||
sCheck.anRef[i] = 1;
|
||||
}
|
||||
if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
|
||||
sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), 20000);
|
||||
sCheck.errMsg.useMalloc = 2;
|
||||
|
||||
|
@ -7983,18 +8001,18 @@ char *sqlite3BtreeIntegrityCheck(
|
|||
*/
|
||||
for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
|
||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||
if( sCheck.anRef[i]==0 ){
|
||||
if( getPageReferenced(&sCheck, i)==0 ){
|
||||
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
|
||||
}
|
||||
#else
|
||||
/* If the database supports auto-vacuum, make sure no tables contain
|
||||
** references to pointer-map pages.
|
||||
*/
|
||||
if( sCheck.anRef[i]==0 &&
|
||||
if( getPageReferenced(&sCheck, i)==0 &&
|
||||
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
|
||||
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) ){
|
||||
checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
|
||||
}
|
||||
|
@ -8015,7 +8033,7 @@ char *sqlite3BtreeIntegrityCheck(
|
|||
/* Clean up and report errors.
|
||||
*/
|
||||
sqlite3BtreeLeave(p);
|
||||
sqlite3_free(sCheck.anRef);
|
||||
sqlite3_free(sCheck.aPgRef);
|
||||
if( sCheck.mallocFailed ){
|
||||
sqlite3StrAccumReset(&sCheck.errMsg);
|
||||
*pnErr = sCheck.nErr+1;
|
||||
|
|
|
@ -631,12 +631,18 @@ struct BtCursor {
|
|||
/*
|
||||
** This structure is passed around through all the sanity checking routines
|
||||
** 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;
|
||||
struct IntegrityCk {
|
||||
BtShared *pBt; /* The tree being checked out */
|
||||
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 */
|
||||
int mxErr; /* Stop accumulating errors when this reaches zero */
|
||||
int nErr; /* Number of messages written to zErrMsg so far */
|
||||
|
|
17
src/build.c
17
src/build.c
|
@ -537,7 +537,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
|||
sqlite3DbFree(db, pTable->zColAff);
|
||||
sqlite3SelectDelete(db, pTable->pSelect);
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
sqlite3ExprDelete(db, pTable->pCheck);
|
||||
sqlite3ExprListDelete(db, pTable->pCheck);
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
sqlite3VtabClear(db, pTable);
|
||||
|
@ -1200,15 +1200,17 @@ void sqlite3AddCheckConstraint(
|
|||
Parse *pParse, /* Parsing context */
|
||||
Expr *pCheckExpr /* The check expression */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
Table *pTab = pParse->pNewTable;
|
||||
if( pTab && !IN_DECLARE_VTAB ){
|
||||
pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck, pCheckExpr);
|
||||
pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
|
||||
if( pParse->constraintName.n ){
|
||||
sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3ExprDelete(db, pCheckExpr);
|
||||
sqlite3ExprDelete(pParse->db, pCheckExpr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1478,6 +1480,8 @@ void sqlite3EndTable(
|
|||
if( p->pCheck ){
|
||||
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
|
||||
NameContext sNC; /* Name context for pParse->pNewTable */
|
||||
ExprList *pList; /* List of all CHECK constraints */
|
||||
int i; /* Loop counter */
|
||||
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
memset(&sSrc, 0, sizeof(sSrc));
|
||||
|
@ -1488,10 +1492,13 @@ void sqlite3EndTable(
|
|||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = &sSrc;
|
||||
sNC.isCheck = 1;
|
||||
if( sqlite3ResolveExprNames(&sNC, p->pCheck) ){
|
||||
pList = p->pCheck;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_CHECK) */
|
||||
|
||||
/* If the db->init.busy is 1 it means we are reading the SQL off the
|
||||
|
|
|
@ -223,38 +223,57 @@ CollSeq *sqlite3FindCollSeq(
|
|||
** that uses encoding enc. The value returned indicates how well the
|
||||
** 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:
|
||||
**
|
||||
** 0: Not a match, or if nArg<0 and the function is has no implementation.
|
||||
** 1: A variable arguments function that prefers UTF-8 when a UTF-16
|
||||
** encoding is requested, or vice versa.
|
||||
** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is
|
||||
** requested, or vice versa.
|
||||
** 3: A variable arguments function using the same text encoding.
|
||||
** 4: A function with the exact number of arguments requested that
|
||||
** 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.
|
||||
** 0: Not a match.
|
||||
** 1: UTF8/16 conversion required and function takes any number of arguments.
|
||||
** 2: UTF16 byte order change required and function takes any number of args.
|
||||
** 3: encoding matches and function takes any number of arguments
|
||||
** 4: UTF8/16 conversion required - argument count matches exactly
|
||||
** 5: UTF16 byte order conversion required - argument count matches exactly
|
||||
** 6: Perfect match: encoding and argument count match exactly.
|
||||
**
|
||||
** 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){
|
||||
int match = 0;
|
||||
if( p->nArg==-1 || p->nArg==nArg
|
||||
|| (nArg==-1 && (p->xFunc!=0 || p->xStep!=0))
|
||||
#define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */
|
||||
static int matchQuality(
|
||||
FuncDef *p, /* The function we are evaluating for match quality */
|
||||
int nArg, /* Desired number of arguments. (-1)==any */
|
||||
u8 enc /* Desired text encoding */
|
||||
){
|
||||
match = 1;
|
||||
if( p->nArg==nArg || nArg==-1 ){
|
||||
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;
|
||||
}
|
||||
|
||||
/* Bonus points if the text encoding matches */
|
||||
if( enc==p->iPrefEnc ){
|
||||
match += 2;
|
||||
}
|
||||
else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) ||
|
||||
(enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){
|
||||
match += 1;
|
||||
}
|
||||
match += 2; /* Exact encoding match */
|
||||
}else if( (enc & p->iPrefEnc & 2)!=0 ){
|
||||
match += 1; /* Both are UTF16, but with different byte orders */
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
|
@ -310,13 +329,12 @@ void sqlite3FuncDefInsert(
|
|||
**
|
||||
** If the createFlag argument is true, then a new (blank) FuncDef
|
||||
** structure is created and liked into the "db" structure if a
|
||||
** no matching function previously existed. When createFlag is true
|
||||
** and the nArg parameter is -1, then only a function that accepts
|
||||
** any number of arguments will be returned.
|
||||
** no matching function previously existed.
|
||||
**
|
||||
** If createFlag is false and nArg is -1, then the first valid
|
||||
** function found is returned. A function is valid if either xFunc
|
||||
** or xStep is non-zero.
|
||||
** If nArg is -2, then the first valid function found is returned. A
|
||||
** function is valid if either xFunc or xStep is non-zero. The nArg==(-2)
|
||||
** 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
|
||||
** 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 nArg, /* Number of arguments. -1 means any number */
|
||||
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 *pBest = 0; /* Best match found so far */
|
||||
int bestScore = 0; /* Score of best match */
|
||||
int h; /* Hash value */
|
||||
|
||||
|
||||
assert( nArg>=(-2) );
|
||||
assert( nArg>=(-1) || createFlag==0 );
|
||||
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
|
||||
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
|
||||
** 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->zName = (char *)&pBest[1];
|
||||
pBest->nArg = (u16)nArg;
|
||||
|
|
84
src/expr.c
84
src/expr.c
|
@ -484,23 +484,55 @@ Expr *sqlite3PExpr(
|
|||
Expr *pRight, /* Right operand */
|
||||
const Token *pToken /* Argument token */
|
||||
){
|
||||
Expr *p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
|
||||
Expr *p;
|
||||
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 ) {
|
||||
sqlite3ExprCheckHeight(pParse, p->nHeight);
|
||||
}
|
||||
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
|
||||
** 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){
|
||||
if( pLeft==0 ){
|
||||
return pRight;
|
||||
}else if( pRight==0 ){
|
||||
return pLeft;
|
||||
}else if( exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight) ){
|
||||
sqlite3ExprDelete(db, pLeft);
|
||||
sqlite3ExprDelete(db, pRight);
|
||||
return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0);
|
||||
}else{
|
||||
Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0);
|
||||
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 ){
|
||||
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( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
|
||||
return 2;
|
||||
|
@ -3783,6 +3815,41 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
|
|||
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
|
||||
** the new element. Return a negative number if malloc fails.
|
||||
|
@ -3898,9 +3965,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
|||
return WRC_Prune;
|
||||
}
|
||||
case TK_AGG_FUNCTION: {
|
||||
/* The pNC->nDepth==0 test causes aggregate functions in subqueries
|
||||
** to be ignored */
|
||||
if( pNC->nDepth==0 ){
|
||||
if( !sqlite3FunctionUsesOtherSrc(pExpr, pSrcList) ){
|
||||
/* Check to see if pExpr is a duplicate of another aggregate
|
||||
** function that is already in the pAggInfo structure
|
||||
*/
|
||||
|
@ -3944,16 +4009,8 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
|||
return WRC_Continue;
|
||||
}
|
||||
static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
|
||||
NameContext *pNC = pWalker->u.pNC;
|
||||
if( pNC->nDepth==0 ){
|
||||
pNC->nDepth++;
|
||||
sqlite3WalkSelect(pWalker, pSelect);
|
||||
pNC->nDepth--;
|
||||
return WRC_Prune;
|
||||
}else{
|
||||
return WRC_Continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Analyze the given expression looking for aggregate functions and
|
||||
|
@ -3965,6 +4022,7 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
|
|||
*/
|
||||
void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
|
||||
Walker w;
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = analyzeAggregate;
|
||||
w.xSelectCallback = analyzeAggregatesInSelect;
|
||||
w.u.pNC = pNC;
|
||||
|
|
29
src/insert.c
29
src/insert.c
|
@ -1157,9 +1157,11 @@ void sqlite3GenerateConstraintChecks(
|
|||
int regData; /* Register containing first data column */
|
||||
int iCur; /* Table cursor number */
|
||||
Index *pIdx; /* Pointer to one of the indices */
|
||||
sqlite3 *db; /* Database connection */
|
||||
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
||||
int regOldRowid = (rowidChng && isUpdate) ? rowidChng : regRowid;
|
||||
|
||||
db = pParse->db;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
assert( v!=0 );
|
||||
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
||||
|
@ -1192,7 +1194,7 @@ void sqlite3GenerateConstraintChecks(
|
|||
char *zMsg;
|
||||
sqlite3VdbeAddOp3(v, OP_HaltIfNull,
|
||||
SQLITE_CONSTRAINT, onError, regData+i);
|
||||
zMsg = sqlite3MPrintf(pParse->db, "%s.%s may not be NULL",
|
||||
zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL",
|
||||
pTab->zName, pTab->aCol[i].zName);
|
||||
sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
|
||||
break;
|
||||
|
@ -1214,19 +1216,28 @@ void sqlite3GenerateConstraintChecks(
|
|||
/* Test all CHECK constraints
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){
|
||||
int allOk = sqlite3VdbeMakeLabel(v);
|
||||
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
|
||||
ExprList *pCheck = pTab->pCheck;
|
||||
pParse->ckBase = regData;
|
||||
sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, SQLITE_JUMPIFNULL);
|
||||
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
|
||||
for(i=0; i<pCheck->nExpr; i++){
|
||||
int allOk = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
|
||||
if( onError==OE_Ignore ){
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
||||
}else{
|
||||
char *zConsName = pCheck->a[i].zName;
|
||||
if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
|
||||
sqlite3HaltConstraint(pParse, onError, 0, 0);
|
||||
if( zConsName ){
|
||||
zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
|
||||
}else{
|
||||
zConsName = 0;
|
||||
}
|
||||
sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, allOk);
|
||||
}
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_CHECK) */
|
||||
|
||||
/* If we have an INTEGER PRIMARY KEY, make sure the primary key
|
||||
|
@ -1281,7 +1292,7 @@ void sqlite3GenerateConstraintChecks(
|
|||
** table.
|
||||
*/
|
||||
Trigger *pTrigger = 0;
|
||||
if( pParse->db->flags&SQLITE_RecTriggers ){
|
||||
if( db->flags&SQLITE_RecTriggers ){
|
||||
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
||||
}
|
||||
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
|
||||
|
@ -1370,7 +1381,7 @@ void sqlite3GenerateConstraintChecks(
|
|||
char *zErr;
|
||||
|
||||
sqlite3StrAccumInit(&errMsg, 0, 0, 200);
|
||||
errMsg.db = pParse->db;
|
||||
errMsg.db = db;
|
||||
zSep = pIdx->nColumn>1 ? "columns " : "column ";
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
|
||||
|
@ -1394,7 +1405,7 @@ void sqlite3GenerateConstraintChecks(
|
|||
Trigger *pTrigger = 0;
|
||||
assert( onError==OE_Replace );
|
||||
sqlite3MultiWrite(pParse);
|
||||
if( pParse->db->flags&SQLITE_RecTriggers ){
|
||||
if( db->flags&SQLITE_RecTriggers ){
|
||||
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
||||
}
|
||||
sqlite3GenerateRowDelete(
|
||||
|
@ -1724,7 +1735,7 @@ static int xferOptimization(
|
|||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
if( pDest->pCheck && sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
|
||||
if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck, pDest->pCheck) ){
|
||||
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
|
||||
}
|
||||
#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
|
||||
** 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
|
||||
** 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.
|
||||
*/
|
||||
static int robust_open(const char *z, int f, mode_t m){
|
||||
int rc;
|
||||
int fd;
|
||||
mode_t m2;
|
||||
mode_t origM = 0;
|
||||
if( m==0 ){
|
||||
|
@ -537,11 +537,20 @@ static int robust_open(const char *z, int f, mode_t m){
|
|||
m2 = m;
|
||||
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 ){
|
||||
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';
|
||||
fd = robust_open(zDirname, O_RDONLY|O_BINARY, 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));
|
||||
}
|
||||
}
|
||||
|
@ -3421,7 +3427,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
|
|||
** actual file size after the operation may be larger than the requested
|
||||
** size).
|
||||
*/
|
||||
if( pFile->szChunk ){
|
||||
if( pFile->szChunk>0 ){
|
||||
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
|
||||
}
|
||||
|
||||
|
@ -5183,10 +5189,6 @@ static int unixOpen(
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
noLock = eType!=SQLITE_OPEN_MAIN_DB;
|
||||
|
||||
|
||||
|
|
220
src/os_win.c
220
src/os_win.c
|
@ -221,26 +221,6 @@ static int sqlite3_os_type = 0;
|
|||
# define SYSCALL sqlite3_syscall_ptr
|
||||
#endif
|
||||
|
||||
#if SQLITE_OS_WINCE
|
||||
/*
|
||||
** These macros are necessary because Windows CE does not natively support the
|
||||
** Win32 APIs LockFile, UnlockFile, and LockFileEx.
|
||||
*/
|
||||
|
||||
# define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e)
|
||||
# define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e)
|
||||
# define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f)
|
||||
|
||||
/*
|
||||
** These are the special syscall hacks for Windows CE. The locking related
|
||||
** defines here refer to the macros defined just above.
|
||||
*/
|
||||
|
||||
# define osLockFile LockFile
|
||||
# define osUnlockFile UnlockFile
|
||||
# define osLockFileEx LockFileEx
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This function is not available on Windows CE or WinRT.
|
||||
*/
|
||||
|
@ -749,7 +729,11 @@ static struct win_syscall {
|
|||
#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
|
||||
FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[63].pCurrent)
|
||||
|
||||
#if !SQLITE_OS_WINCE
|
||||
{ "MapViewOfFileEx", (SYSCALL)MapViewOfFileEx, 0 },
|
||||
#else
|
||||
{ "MapViewOfFileEx", (SYSCALL)0, 0 },
|
||||
#endif
|
||||
|
||||
#define osMapViewOfFileEx ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,SIZE_T, \
|
||||
LPVOID))aSyscall[64].pCurrent)
|
||||
|
@ -1490,49 +1474,6 @@ static void logIoerr(int nRetry){
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock a file region.
|
||||
*/
|
||||
static BOOL winLockFile(
|
||||
HANDLE hFile,
|
||||
DWORD flags,
|
||||
DWORD offsetLow,
|
||||
DWORD offsetHigh,
|
||||
DWORD numBytesLow,
|
||||
DWORD numBytesHigh
|
||||
){
|
||||
if( isNT() ){
|
||||
OVERLAPPED ovlp;
|
||||
memset(&ovlp, 0, sizeof(OVERLAPPED));
|
||||
ovlp.Offset = offsetLow;
|
||||
ovlp.OffsetHigh = offsetHigh;
|
||||
return osLockFileEx(hFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
|
||||
}else{
|
||||
return osLockFile(hFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlock a file region.
|
||||
*/
|
||||
static BOOL winUnlockFile(
|
||||
HANDLE hFile,
|
||||
DWORD offsetLow,
|
||||
DWORD offsetHigh,
|
||||
DWORD numBytesLow,
|
||||
DWORD numBytesHigh
|
||||
){
|
||||
if( isNT() ){
|
||||
OVERLAPPED ovlp;
|
||||
memset(&ovlp, 0, sizeof(OVERLAPPED));
|
||||
ovlp.Offset = offsetLow;
|
||||
ovlp.OffsetHigh = offsetHigh;
|
||||
return osUnlockFileEx(hFile, 0, numBytesLow, numBytesHigh, &ovlp);
|
||||
}else{
|
||||
return osUnlockFile(hFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh);
|
||||
}
|
||||
}
|
||||
|
||||
#if SQLITE_OS_WINCE
|
||||
/*************************************************************************
|
||||
** This section contains code for WinCE only.
|
||||
|
@ -1703,7 +1644,7 @@ static void winceDestroyLock(winFile *pFile){
|
|||
** An implementation of the LockFile() API of Windows for CE
|
||||
*/
|
||||
static BOOL winceLockFile(
|
||||
HANDLE *phFile,
|
||||
LPHANDLE phFile,
|
||||
DWORD dwFileOffsetLow,
|
||||
DWORD dwFileOffsetHigh,
|
||||
DWORD nNumberOfBytesToLockLow,
|
||||
|
@ -1767,7 +1708,7 @@ static BOOL winceLockFile(
|
|||
** An implementation of the UnlockFile API of Windows for CE
|
||||
*/
|
||||
static BOOL winceUnlockFile(
|
||||
HANDLE *phFile,
|
||||
LPHANDLE phFile,
|
||||
DWORD dwFileOffsetLow,
|
||||
DWORD dwFileOffsetHigh,
|
||||
DWORD nNumberOfBytesToUnlockLow,
|
||||
|
@ -1824,35 +1765,74 @@ static BOOL winceUnlockFile(
|
|||
winceMutexRelease(pFile->hMutex);
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
/*
|
||||
** An implementation of the LockFileEx() API of Windows for CE
|
||||
*/
|
||||
static BOOL winceLockFileEx(
|
||||
HANDLE *phFile,
|
||||
DWORD dwFlags,
|
||||
DWORD dwReserved,
|
||||
DWORD nNumberOfBytesToLockLow,
|
||||
DWORD nNumberOfBytesToLockHigh,
|
||||
LPOVERLAPPED lpOverlapped
|
||||
){
|
||||
UNUSED_PARAMETER(dwReserved);
|
||||
UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
|
||||
|
||||
/* If the caller wants a shared read lock, forward this call
|
||||
** to winceLockFile */
|
||||
if (lpOverlapped->Offset == (DWORD)SHARED_FIRST &&
|
||||
dwFlags == 1 &&
|
||||
nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
|
||||
return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
** End of the special code for wince
|
||||
*****************************************************************************/
|
||||
#endif /* SQLITE_OS_WINCE */
|
||||
|
||||
/*
|
||||
** Lock a file region.
|
||||
*/
|
||||
static BOOL winLockFile(
|
||||
LPHANDLE phFile,
|
||||
DWORD flags,
|
||||
DWORD offsetLow,
|
||||
DWORD offsetHigh,
|
||||
DWORD numBytesLow,
|
||||
DWORD numBytesHigh
|
||||
){
|
||||
#if SQLITE_OS_WINCE
|
||||
/*
|
||||
** NOTE: Windows CE is handled differently here due its lack of the Win32
|
||||
** API LockFile.
|
||||
*/
|
||||
return winceLockFile(phFile, offsetLow, offsetHigh,
|
||||
numBytesLow, numBytesHigh);
|
||||
#else
|
||||
if( isNT() ){
|
||||
OVERLAPPED ovlp;
|
||||
memset(&ovlp, 0, sizeof(OVERLAPPED));
|
||||
ovlp.Offset = offsetLow;
|
||||
ovlp.OffsetHigh = offsetHigh;
|
||||
return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
|
||||
}else{
|
||||
return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
|
||||
numBytesHigh);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlock a file region.
|
||||
*/
|
||||
static BOOL winUnlockFile(
|
||||
LPHANDLE phFile,
|
||||
DWORD offsetLow,
|
||||
DWORD offsetHigh,
|
||||
DWORD numBytesLow,
|
||||
DWORD numBytesHigh
|
||||
){
|
||||
#if SQLITE_OS_WINCE
|
||||
/*
|
||||
** NOTE: Windows CE is handled differently here due its lack of the Win32
|
||||
** API UnlockFile.
|
||||
*/
|
||||
return winceUnlockFile(phFile, offsetLow, offsetHigh,
|
||||
numBytesLow, numBytesHigh);
|
||||
#else
|
||||
if( isNT() ){
|
||||
OVERLAPPED ovlp;
|
||||
memset(&ovlp, 0, sizeof(OVERLAPPED));
|
||||
ovlp.Offset = offsetLow;
|
||||
ovlp.OffsetHigh = offsetHigh;
|
||||
return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp);
|
||||
}else{
|
||||
return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
|
||||
numBytesHigh);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
** The next group of routines implement the I/O methods specified
|
||||
** by the sqlite3_io_methods object.
|
||||
|
@ -1978,7 +1958,9 @@ static int winRead(
|
|||
int amt, /* Number of bytes to read */
|
||||
sqlite3_int64 offset /* Begin reading at this offset */
|
||||
){
|
||||
#if !SQLITE_OS_WINCE
|
||||
OVERLAPPED overlapped; /* The offset for ReadFile. */
|
||||
#endif
|
||||
winFile *pFile = (winFile*)id; /* file handle */
|
||||
DWORD nRead; /* Number of bytes actually read from file */
|
||||
int nRetry = 0; /* Number of retrys */
|
||||
|
@ -1987,11 +1969,18 @@ static int winRead(
|
|||
SimulateIOError(return SQLITE_IOERR_READ);
|
||||
OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
|
||||
|
||||
#if SQLITE_OS_WINCE
|
||||
if( seekWinFile(pFile, offset) ){
|
||||
return SQLITE_FULL;
|
||||
}
|
||||
while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
|
||||
#else
|
||||
memset(&overlapped, 0, sizeof(OVERLAPPED));
|
||||
overlapped.Offset = (LONG)(offset & 0xffffffff);
|
||||
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
|
||||
while( !osReadFile(pFile->h, pBuf, amt, &nRead, &overlapped) &&
|
||||
osGetLastError()!=ERROR_HANDLE_EOF ){
|
||||
#endif
|
||||
DWORD lastErrno;
|
||||
if( retryIoerr(&nRetry, &lastErrno) ) continue;
|
||||
pFile->lastErrno = lastErrno;
|
||||
|
@ -2029,19 +2018,32 @@ static int winWrite(
|
|||
|
||||
OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
|
||||
|
||||
#if SQLITE_OS_WINCE
|
||||
rc = seekWinFile(pFile, offset);
|
||||
if( rc==0 ){
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
#if !SQLITE_OS_WINCE
|
||||
OVERLAPPED overlapped; /* The offset for WriteFile. */
|
||||
#endif
|
||||
u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
|
||||
int nRem = amt; /* Number of bytes yet to be written */
|
||||
DWORD nWrite; /* Bytes written by each WriteFile() call */
|
||||
DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
|
||||
|
||||
#if !SQLITE_OS_WINCE
|
||||
memset(&overlapped, 0, sizeof(OVERLAPPED));
|
||||
overlapped.Offset = (LONG)(offset & 0xffffffff);
|
||||
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
|
||||
#endif
|
||||
|
||||
while( nRem>0 ){
|
||||
#if SQLITE_OS_WINCE
|
||||
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
|
||||
#else
|
||||
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
|
||||
#endif
|
||||
if( retryIoerr(&nRetry, &lastErrno) ) continue;
|
||||
break;
|
||||
}
|
||||
|
@ -2049,9 +2051,11 @@ static int winWrite(
|
|||
lastErrno = osGetLastError();
|
||||
break;
|
||||
}
|
||||
#if !SQLITE_OS_WINCE
|
||||
offset += nWrite;
|
||||
overlapped.Offset = (LONG)(offset & 0xffffffff);
|
||||
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
|
||||
#endif
|
||||
aRem += nWrite;
|
||||
nRem -= nWrite;
|
||||
}
|
||||
|
@ -2258,15 +2262,23 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
|
|||
static int getReadLock(winFile *pFile){
|
||||
int res;
|
||||
if( isNT() ){
|
||||
res = winLockFile(pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0,
|
||||
#if SQLITE_OS_WINCE
|
||||
/*
|
||||
** NOTE: Windows CE is handled differently here due its lack of the Win32
|
||||
** API LockFileEx.
|
||||
*/
|
||||
res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0);
|
||||
#else
|
||||
res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0,
|
||||
SHARED_SIZE, 0);
|
||||
#endif
|
||||
}
|
||||
#ifdef SQLITE_WIN32_HAS_ANSI
|
||||
else{
|
||||
int lk;
|
||||
sqlite3_randomness(sizeof(lk), &lk);
|
||||
pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
|
||||
res = winLockFile(pFile->h, SQLITE_LOCKFILE_FLAGS,
|
||||
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
|
||||
SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
|
||||
}
|
||||
#endif
|
||||
|
@ -2284,11 +2296,11 @@ static int unlockReadLock(winFile *pFile){
|
|||
int res;
|
||||
DWORD lastErrno;
|
||||
if( isNT() ){
|
||||
res = winUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
|
||||
res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
|
||||
}
|
||||
#ifdef SQLITE_WIN32_HAS_ANSI
|
||||
else{
|
||||
res = winUnlockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
|
||||
res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
|
||||
}
|
||||
#endif
|
||||
if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){
|
||||
|
@ -2361,7 +2373,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
|||
&& (pFile->locktype==RESERVED_LOCK))
|
||||
){
|
||||
int cnt = 3;
|
||||
while( cnt-->0 && (res = winLockFile(pFile->h, SQLITE_LOCKFILE_FLAGS,
|
||||
while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
|
||||
PENDING_BYTE, 0, 1, 0))==0 ){
|
||||
/* Try 3 times to get the pending lock. This is needed to work
|
||||
** around problems caused by indexing and/or anti-virus software on
|
||||
|
@ -2394,7 +2406,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
|||
*/
|
||||
if( locktype==RESERVED_LOCK && res ){
|
||||
assert( pFile->locktype==SHARED_LOCK );
|
||||
res = winLockFile(pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0);
|
||||
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0);
|
||||
if( res ){
|
||||
newLocktype = RESERVED_LOCK;
|
||||
}else{
|
||||
|
@ -2415,7 +2427,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
|||
assert( pFile->locktype>=SHARED_LOCK );
|
||||
res = unlockReadLock(pFile);
|
||||
OSTRACE(("unreadlock = %d\n", res));
|
||||
res = winLockFile(pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
|
||||
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
|
||||
SHARED_SIZE, 0);
|
||||
if( res ){
|
||||
newLocktype = EXCLUSIVE_LOCK;
|
||||
|
@ -2430,7 +2442,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
|||
** release it now.
|
||||
*/
|
||||
if( gotPendingLock && locktype==SHARED_LOCK ){
|
||||
winUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
|
||||
winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
|
||||
}
|
||||
|
||||
/* Update the state of the lock has held in the file descriptor then
|
||||
|
@ -2464,9 +2476,9 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
|
|||
rc = 1;
|
||||
OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc));
|
||||
}else{
|
||||
rc = winLockFile(pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0);
|
||||
rc = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0);
|
||||
if( rc ){
|
||||
winUnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
|
||||
winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
|
||||
}
|
||||
rc = !rc;
|
||||
OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc));
|
||||
|
@ -2496,7 +2508,7 @@ static int winUnlock(sqlite3_file *id, int locktype){
|
|||
pFile->locktype, pFile->sharedLockByte));
|
||||
type = pFile->locktype;
|
||||
if( type>=EXCLUSIVE_LOCK ){
|
||||
winUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
|
||||
winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
|
||||
if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
|
||||
/* This should never happen. We should always be able to
|
||||
** reacquire the read lock */
|
||||
|
@ -2505,13 +2517,13 @@ static int winUnlock(sqlite3_file *id, int locktype){
|
|||
}
|
||||
}
|
||||
if( type>=RESERVED_LOCK ){
|
||||
winUnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
|
||||
winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
|
||||
}
|
||||
if( locktype==NO_LOCK && type>=SHARED_LOCK ){
|
||||
unlockReadLock(pFile);
|
||||
}
|
||||
if( type>=PENDING_LOCK ){
|
||||
winUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
|
||||
winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
|
||||
}
|
||||
pFile->locktype = (u8)locktype;
|
||||
return rc;
|
||||
|
@ -2756,12 +2768,12 @@ static int winShmSystemLock(
|
|||
|
||||
/* Release/Acquire the system-level lock */
|
||||
if( lockType==_SHM_UNLCK ){
|
||||
rc = winUnlockFile(pFile->hFile.h, ofst, 0, nByte, 0);
|
||||
rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
|
||||
}else{
|
||||
/* Initialize the locking parameters */
|
||||
DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
|
||||
if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
|
||||
rc = winLockFile(pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
|
||||
rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
|
||||
}
|
||||
|
||||
if( rc!= 0 ){
|
||||
|
|
15
src/parse.y
15
src/parse.y
|
@ -273,10 +273,10 @@ signed ::= minus_num.
|
|||
// "carglist" is a list of additional constraints that come after the
|
||||
// column name and column type in a CREATE TABLE statement.
|
||||
//
|
||||
carglist ::= carglist carg.
|
||||
carglist ::= carglist cname ccons.
|
||||
carglist ::= .
|
||||
carg ::= CONSTRAINT nm ccons.
|
||||
carg ::= ccons.
|
||||
cname ::= CONSTRAINT nm(X). {pParse->constraintName = X;}
|
||||
cname ::= . {pParse->constraintName.n = 0;}
|
||||
ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,&X);}
|
||||
ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,&X);}
|
||||
ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,&X);}
|
||||
|
@ -339,15 +339,10 @@ init_deferred_pred_opt(A) ::= . {A = 0;}
|
|||
init_deferred_pred_opt(A) ::= INITIALLY DEFERRED. {A = 1;}
|
||||
init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE. {A = 0;}
|
||||
|
||||
// For the time being, the only constraint we care about is the primary
|
||||
// key and UNIQUE. Both create indices.
|
||||
//
|
||||
conslist_opt(A) ::= . {A.n = 0; A.z = 0;}
|
||||
conslist_opt(A) ::= COMMA(X) conslist. {A = X;}
|
||||
conslist ::= conslist COMMA tcons.
|
||||
conslist ::= conslist tcons.
|
||||
conslist ::= tcons.
|
||||
tcons ::= CONSTRAINT nm.
|
||||
conslist ::= conslist COMMA cname tcons.
|
||||
conslist ::= cname tcons.
|
||||
tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R).
|
||||
{sqlite3AddPrimaryKey(pParse,X,R,I,0);}
|
||||
tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
|
||||
|
|
|
@ -533,7 +533,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||
nId = sqlite3Strlen30(zId);
|
||||
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 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 ){
|
||||
no_such_func = 1;
|
||||
}else{
|
||||
|
|
196
src/rowset.c
196
src/rowset.c
|
@ -76,6 +76,11 @@
|
|||
|
||||
/*
|
||||
** 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 {
|
||||
i64 v; /* ROWID value for this entry */
|
||||
|
@ -105,12 +110,18 @@ struct RowSet {
|
|||
struct RowSetEntry *pEntry; /* List of entries using pRight */
|
||||
struct RowSetEntry *pLast; /* Last entry on the pEntry list */
|
||||
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 */
|
||||
u8 isSorted; /* True if pEntry is sorted */
|
||||
u8 rsFlags; /* Various flags */
|
||||
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
|
||||
** 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->pEntry = 0;
|
||||
p->pLast = 0;
|
||||
p->pTree = 0;
|
||||
p->pForest = 0;
|
||||
p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
|
||||
p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
|
||||
p->isSorted = 1;
|
||||
p->rsFlags = ROWSET_SORTED;
|
||||
p->iBatch = 0;
|
||||
return p;
|
||||
}
|
||||
|
@ -154,8 +165,33 @@ void sqlite3RowSetClear(RowSet *p){
|
|||
p->nFresh = 0;
|
||||
p->pEntry = 0;
|
||||
p->pLast = 0;
|
||||
p->pTree = 0;
|
||||
p->isSorted = 1;
|
||||
p->pForest = 0;
|
||||
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){
|
||||
struct RowSetEntry *pEntry; /* The new entry */
|
||||
struct RowSetEntry *pLast; /* The last prior entry */
|
||||
assert( p!=0 );
|
||||
if( p->nFresh==0 ){
|
||||
struct RowSetChunk *pNew;
|
||||
pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));
|
||||
if( pNew==0 ){
|
||||
return;
|
||||
}
|
||||
pNew->pNextChunk = p->pChunk;
|
||||
p->pChunk = pNew;
|
||||
p->pFresh = pNew->aEntry;
|
||||
p->nFresh = ROWSET_ENTRY_PER_CHUNK;
|
||||
}
|
||||
pEntry = p->pFresh++;
|
||||
p->nFresh--;
|
||||
|
||||
/* This routine is never called after sqlite3RowSetNext() */
|
||||
assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
|
||||
|
||||
pEntry = rowSetEntryAlloc(p);
|
||||
if( pEntry==0 ) return;
|
||||
pEntry->v = rowid;
|
||||
pEntry->pRight = 0;
|
||||
pLast = p->pLast;
|
||||
if( pLast ){
|
||||
if( p->isSorted && rowid<=pLast->v ){
|
||||
p->isSorted = 0;
|
||||
if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){
|
||||
p->rsFlags &= ~ROWSET_SORTED;
|
||||
}
|
||||
pLast->pRight = pEntry;
|
||||
}else{
|
||||
assert( p->pEntry==0 ); /* Fires if INSERT after SMALLEST */
|
||||
p->pEntry = pEntry;
|
||||
}
|
||||
p->pLast = pEntry;
|
||||
|
@ -202,7 +229,7 @@ void sqlite3RowSetInsert(RowSet *p, i64 rowid){
|
|||
** The input lists are connected via pRight pointers and are
|
||||
** 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 *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;
|
||||
struct RowSetEntry *pEntry;
|
||||
struct RowSetEntry *aBucket[40];
|
||||
struct RowSetEntry *pNext, *aBucket[40];
|
||||
|
||||
assert( p->isSorted==0 );
|
||||
memset(aBucket, 0, sizeof(aBucket));
|
||||
while( p->pEntry ){
|
||||
pEntry = p->pEntry;
|
||||
p->pEntry = pEntry->pRight;
|
||||
pEntry->pRight = 0;
|
||||
while( pIn ){
|
||||
pNext = pIn->pRight;
|
||||
pIn->pRight = 0;
|
||||
for(i=0; aBucket[i]; i++){
|
||||
pEntry = rowSetMerge(aBucket[i], pEntry);
|
||||
pIn = rowSetEntryMerge(aBucket[i], pIn);
|
||||
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++){
|
||||
pEntry = rowSetMerge(pEntry, aBucket[i]);
|
||||
pIn = rowSetEntryMerge(pIn, aBucket[i]);
|
||||
}
|
||||
p->pEntry = pEntry;
|
||||
p->pLast = 0;
|
||||
p->isSorted = 1;
|
||||
return pIn;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
** sorted already. If there is a binary tree on p->pTree, then
|
||||
** convert it into a list too and merge it into the p->pEntry list.
|
||||
** Take all the entries on p->pEntry and on the trees in p->pForest and
|
||||
** sort them all together into one big ordered list on p->pEntry.
|
||||
**
|
||||
** This routine should only be called once in the life of a RowSet.
|
||||
*/
|
||||
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 ){
|
||||
|
||||
/* While this module could theoretically support it, sqlite3RowSetNext()
|
||||
** is never called after sqlite3RowSetText() for the same RowSet. So
|
||||
** there is never a forest to deal with. Should this change, simply
|
||||
** 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(p->pTree, &pHead, &pTail);
|
||||
p->pTree = 0;
|
||||
p->pEntry = rowSetMerge(p->pEntry, pHead);
|
||||
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.
|
||||
*/
|
||||
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 ){
|
||||
*pRowid = p->pEntry->v;
|
||||
p->pEntry = p->pEntry->pRight;
|
||||
|
@ -396,19 +442,58 @@ int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
|
|||
/*
|
||||
** 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.
|
||||
**
|
||||
** 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){
|
||||
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( pRowSet->pEntry ){
|
||||
rowSetToList(pRowSet);
|
||||
pRowSet->pTree = rowSetListToTree(pRowSet->pEntry);
|
||||
p = pRowSet->pEntry;
|
||||
if( p ){
|
||||
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->pLast = 0;
|
||||
pRowSet->rsFlags |= ROWSET_SORTED;
|
||||
}
|
||||
pRowSet->iBatch = iBatch;
|
||||
}
|
||||
p = pRowSet->pTree;
|
||||
|
||||
/* Test to see if the iRowid value appears anywhere in the forest.
|
||||
** Return 1 if it does and 0 if not.
|
||||
*/
|
||||
for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
|
||||
p = pTree->pLeft;
|
||||
while( p ){
|
||||
if( p->v<iRowid ){
|
||||
p = p->pRight;
|
||||
|
@ -418,5 +503,6 @@ int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
17
src/select.c
17
src/select.c
|
@ -1258,9 +1258,17 @@ static int selectColumnsFromExprList(
|
|||
char *zName; /* Column name */
|
||||
int nName; /* Size of name in zName[] */
|
||||
|
||||
*pnCol = nCol = pEList ? pEList->nExpr : 0;
|
||||
aCol = *paCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
|
||||
if( aCol==0 ) return SQLITE_NOMEM;
|
||||
if( pEList ){
|
||||
nCol = pEList->nExpr;
|
||||
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++){
|
||||
/* Get an appropriate name for the column
|
||||
*/
|
||||
|
@ -2843,7 +2851,8 @@ static int flattenSubquery(
|
|||
|
||||
/* Authorize the subquery */
|
||||
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;
|
||||
|
||||
/* If the sub-query is a compound SELECT statement, then (by restrictions
|
||||
|
|
128
src/shell.c
128
src/shell.c
|
@ -421,6 +421,7 @@ struct callback_data {
|
|||
int statsOn; /* True to display memory stats before each finalize */
|
||||
int cnt; /* Number of records displayed so far */
|
||||
FILE *out; /* Write results here */
|
||||
FILE *traceOut; /* Output for sqlite3_trace() */
|
||||
int nErr; /* Number of errors seen */
|
||||
int mode; /* An output mode setting */
|
||||
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, '"');
|
||||
if( zTmp ){
|
||||
zSelect = appendText(zSelect, zTmp, '\'');
|
||||
free(zTmp);
|
||||
}
|
||||
zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
|
||||
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);
|
||||
run_table_dump_query(p, zSelect, 0);
|
||||
}
|
||||
if( zSelect ) free(zSelect);
|
||||
free(zSelect);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1367,7 +1369,7 @@ static int run_schema_dump_query(
|
|||
}
|
||||
zQ2 = malloc( len+100 );
|
||||
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);
|
||||
if( rc ){
|
||||
fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
|
||||
|
@ -1433,6 +1435,7 @@ static char zHelp[] =
|
|||
" If TABLE specified, only list tables matching\n"
|
||||
" LIKE pattern TABLE.\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"
|
||||
".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
|
||||
;
|
||||
|
@ -1522,6 +1525,52 @@ static int booleanValue(char *zArg){
|
|||
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
|
||||
** process that line.
|
||||
|
@ -1601,6 +1650,13 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
bail_on_error = booleanValue(azArg[1]);
|
||||
}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 ){
|
||||
struct callback_data data;
|
||||
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 ){
|
||||
const char *zFile = azArg[1];
|
||||
if( p->pLog && p->pLog!=stdout && p->pLog!=stderr ){
|
||||
fclose(p->pLog);
|
||||
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);
|
||||
}
|
||||
}
|
||||
output_file_close(p->pLog);
|
||||
p->pLog = output_file_open(zFile);
|
||||
}else
|
||||
|
||||
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
|
||||
|
||||
if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
|
||||
if( p->out!=stdout ){
|
||||
if( p->outfile[0]=='|' ){
|
||||
pclose(p->out);
|
||||
}else{
|
||||
fclose(p->out);
|
||||
output_file_close(p->out);
|
||||
}
|
||||
}
|
||||
if( strcmp(azArg[1],"stdout")==0 ){
|
||||
p->out = stdout;
|
||||
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout");
|
||||
}else if( azArg[1][0]=='|' ){
|
||||
p->outfile[0] = 0;
|
||||
if( azArg[1][0]=='|' ){
|
||||
p->out = popen(&azArg[1][1], "w");
|
||||
if( p->out==0 ){
|
||||
fprintf(stderr,"Error: cannot open pipe \"%s\"\n", &azArg[1][1]);
|
||||
|
@ -2020,9 +2058,11 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
|
||||
}
|
||||
}else{
|
||||
p->out = fopen(azArg[1], "wb");
|
||||
p->out = output_file_open(azArg[1]);
|
||||
if( p->out==0 ){
|
||||
if( strcmp(azArg[1],"off")!=0 ){
|
||||
fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]);
|
||||
}
|
||||
p->out = stdout;
|
||||
rc = 1;
|
||||
} else {
|
||||
|
@ -2396,6 +2436,18 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
enableTimer = booleanValue(azArg[1]);
|
||||
}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 ){
|
||||
printf("SQLite %s %s\n" /*extra-version-info*/,
|
||||
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
|
||||
** 0 return indicates an error of some kind. Space to hold the
|
||||
** resulting string is obtained from malloc(). The calling
|
||||
** function should free the result.
|
||||
** 0 return indicates an error of some kind.
|
||||
*/
|
||||
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)
|
||||
struct passwd *pwent;
|
||||
|
@ -2625,7 +2676,7 @@ static char *find_home_dir(void){
|
|||
#if defined(_WIN32_WCE)
|
||||
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
|
||||
*/
|
||||
home_dir = strdup("/");
|
||||
home_dir = "/";
|
||||
#else
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
|
||||
|
@ -2681,7 +2732,6 @@ static int process_sqliterc(
|
|||
const char *sqliterc = sqliterc_override;
|
||||
char *zBuf = 0;
|
||||
FILE *in = NULL;
|
||||
int nBuf;
|
||||
int rc = 0;
|
||||
|
||||
if (sqliterc == NULL) {
|
||||
|
@ -2692,15 +2742,8 @@ static int process_sqliterc(
|
|||
#endif
|
||||
return 1;
|
||||
}
|
||||
nBuf = strlen30(home_dir) + 16;
|
||||
zBuf = malloc( nBuf );
|
||||
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;
|
||||
zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
|
||||
sqliterc = zBuf;
|
||||
}
|
||||
in = fopen(sqliterc,"rb");
|
||||
if( in ){
|
||||
|
@ -2710,7 +2753,7 @@ static int process_sqliterc(
|
|||
rc = process_input(p,in);
|
||||
fclose(in);
|
||||
}
|
||||
free(zBuf);
|
||||
sqlite3_free(zBuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -3051,7 +3094,6 @@ int main(int argc, char **argv){
|
|||
write_history(zHistory);
|
||||
free(zHistory);
|
||||
}
|
||||
free(zHome);
|
||||
}else{
|
||||
rc = process_input(&data, stdin);
|
||||
}
|
||||
|
|
|
@ -1542,7 +1542,7 @@ struct sqlite3_mem_methods {
|
|||
** [SQLITE_USE_URI] symbol defined.
|
||||
**
|
||||
** [[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.
|
||||
** They are retained for backwards compatibility but are now no-ops.
|
||||
** </dl>
|
||||
|
|
|
@ -1281,7 +1281,7 @@ struct Table {
|
|||
FKey *pFKey; /* Linked list of all foreign keys in this table */
|
||||
char *zColAff; /* String defining the affinity of each column */
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
Expr *pCheck; /* The AND of all CHECK constraints */
|
||||
ExprList *pCheck; /* All CHECK constraints */
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
|
||||
|
@ -2011,7 +2011,6 @@ struct NameContext {
|
|||
u8 allowAgg; /* Aggregate functions allowed here */
|
||||
u8 hasAgg; /* True if aggregates are seen */
|
||||
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 */
|
||||
NameContext *pNext; /* Next outer name context. NULL for outermost */
|
||||
};
|
||||
|
@ -2216,6 +2215,7 @@ struct Parse {
|
|||
int regRowid; /* Register holding rowid of CREATE TABLE entry */
|
||||
int regRoot; /* Register holding root page number for new objects */
|
||||
int nMaxArg; /* Max args passed to user function by sub-program */
|
||||
Token constraintName;/* Name of the constraint currently being parsed */
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
int nTableLock; /* Number of locks in aTableLock */
|
||||
TableLock *aTableLock; /* Required table locks for shared-cache mode */
|
||||
|
@ -2476,6 +2476,7 @@ struct Walker {
|
|||
union { /* Extra data for callback */
|
||||
NameContext *pNC; /* Naming context */
|
||||
int i; /* Integer value */
|
||||
SrcList *pSrcList; /* FROM clause */
|
||||
} u;
|
||||
};
|
||||
|
||||
|
@ -2844,7 +2845,7 @@ SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
|
|||
IdList *sqlite3IdListDup(sqlite3*,IdList*);
|
||||
Select *sqlite3SelectDup(sqlite3*,Select*,int);
|
||||
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 sqlite3RegisterDateTimeFunctions(void);
|
||||
void sqlite3RegisterGlobalFunctions(void);
|
||||
|
|
|
@ -3263,7 +3263,7 @@ static int test_bind_text16(
|
|||
char *value;
|
||||
int rc;
|
||||
|
||||
void (*xDel)() = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT);
|
||||
void (*xDel)(void*) = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT);
|
||||
Tcl_Obj *oStmt = objv[objc-4];
|
||||
Tcl_Obj *oN = objv[objc-3];
|
||||
Tcl_Obj *oString = objv[objc-2];
|
||||
|
@ -3611,7 +3611,7 @@ static int test_prepare(
|
|||
if( bytes>=0 ){
|
||||
bytes = bytes - (zTail-zSql);
|
||||
}
|
||||
if( strlen(zTail)<bytes ){
|
||||
if( (int)strlen(zTail)<bytes ){
|
||||
bytes = strlen(zTail);
|
||||
}
|
||||
Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
|
||||
|
@ -5816,6 +5816,7 @@ struct win32FileLocker {
|
|||
|
||||
|
||||
#if SQLITE_OS_WIN
|
||||
#include <process.h>
|
||||
/*
|
||||
** The background thread that does file locking.
|
||||
*/
|
||||
|
@ -6128,7 +6129,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
#endif
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
{"sqlite3_column_database_name16",
|
||||
test_stmt_utf16, sqlite3_column_database_name16},
|
||||
test_stmt_utf16, (void*)sqlite3_column_database_name16},
|
||||
{"sqlite3_column_table_name16", test_stmt_utf16, (void*)sqlite3_column_table_name16},
|
||||
{"sqlite3_column_origin_name16", test_stmt_utf16, (void*)sqlite3_column_origin_name16},
|
||||
#endif
|
||||
|
|
|
@ -465,7 +465,7 @@ static int btree_varint_test(
|
|||
if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
|
||||
in = start;
|
||||
in *= mult;
|
||||
for(i=0; i<count; i++){
|
||||
for(i=0; i<(int)count; i++){
|
||||
char zErr[200];
|
||||
n1 = putVarint(zBuf, in);
|
||||
if( n1>9 || n1<1 ){
|
||||
|
|
16
src/test6.c
16
src/test6.c
|
@ -177,7 +177,7 @@ static int writeDbFile(CrashFile *p, u8 *z, i64 iAmt, i64 iOff){
|
|||
iSkip = 512;
|
||||
}
|
||||
if( (iAmt-iSkip)>0 ){
|
||||
rc = sqlite3OsWrite(p->pRealFile, &z[iSkip], iAmt-iSkip, iOff+iSkip);
|
||||
rc = sqlite3OsWrite(p->pRealFile, &z[iSkip], (int)(iAmt-iSkip), iOff+iSkip);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -306,8 +306,8 @@ static int writeListSync(CrashFile *pFile, int isCrash){
|
|||
}
|
||||
case 3: { /* Trash sectors */
|
||||
u8 *zGarbage;
|
||||
int iFirst = (pWrite->iOffset/g.iSectorSize);
|
||||
int iLast = (pWrite->iOffset+pWrite->nBuf-1)/g.iSectorSize;
|
||||
int iFirst = (int)(pWrite->iOffset/g.iSectorSize);
|
||||
int iLast = (int)((pWrite->iOffset+pWrite->nBuf-1)/g.iSectorSize);
|
||||
|
||||
assert(pWrite->zBuf);
|
||||
|
||||
|
@ -430,7 +430,7 @@ static int cfWrite(
|
|||
){
|
||||
CrashFile *pCrash = (CrashFile *)pFile;
|
||||
if( iAmt+iOfst>pCrash->iSize ){
|
||||
pCrash->iSize = iAmt+iOfst;
|
||||
pCrash->iSize = (int)(iAmt+iOfst);
|
||||
}
|
||||
while( pCrash->iSize>pCrash->nData ){
|
||||
u8 *zNew;
|
||||
|
@ -454,7 +454,7 @@ static int cfTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
|||
CrashFile *pCrash = (CrashFile *)pFile;
|
||||
assert(size>=0);
|
||||
if( pCrash->iSize>size ){
|
||||
pCrash->iSize = size;
|
||||
pCrash->iSize = (int)size;
|
||||
}
|
||||
return writeListAppend(pFile, size, 0, 0);
|
||||
}
|
||||
|
@ -518,7 +518,7 @@ static int cfFileControl(sqlite3_file *pFile, int op, void *pArg){
|
|||
i64 nByte = *(i64 *)pArg;
|
||||
if( nByte>pCrash->iSize ){
|
||||
if( SQLITE_OK==writeListAppend(pFile, nByte, 0, 0) ){
|
||||
pCrash->iSize = nByte;
|
||||
pCrash->iSize = (int)nByte;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
|
@ -635,11 +635,11 @@ static int cfOpen(
|
|||
iChunk = PENDING_BYTE;
|
||||
}
|
||||
memset(pWrapper->zData, 0, pWrapper->nData);
|
||||
rc = sqlite3OsRead(pReal, pWrapper->zData, iChunk, 0);
|
||||
rc = sqlite3OsRead(pReal, pWrapper->zData, (int)iChunk, 0);
|
||||
if( SQLITE_OK==rc && pWrapper->iSize>(PENDING_BYTE+512) && isDb ){
|
||||
i64 iOff = PENDING_BYTE+512;
|
||||
iChunk = pWrapper->iSize - iOff;
|
||||
rc = sqlite3OsRead(pReal, &pWrapper->zData[iOff], iChunk, iOff);
|
||||
rc = sqlite3OsRead(pReal, &pWrapper->zData[iOff], (int)iChunk, iOff);
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
|
|
|
@ -426,6 +426,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
|
|||
Tcl_SetVar2(interp, "sqlite_options", "rtree", "0", TCL_GLOBAL_ONLY);
|
||||
#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
|
||||
Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
|
|
@ -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
|
||||
** Tcl global variable namespace.
|
||||
** A virtual table module that implements the "fuzzer".
|
||||
*/
|
||||
static sqlite3_module fuzzerModule = {
|
||||
0, /* iVersion */
|
||||
|
|
|
@ -404,7 +404,7 @@ static int openTransaction(jt_file *pMain, jt_file *pJournal){
|
|||
/* Calculate and store a checksum for each page in the database file. */
|
||||
if( rc==SQLITE_OK ){
|
||||
int ii;
|
||||
for(ii=0; rc==SQLITE_OK && ii<pMain->nPage; ii++){
|
||||
for(ii=0; rc==SQLITE_OK && ii<(int)pMain->nPage; ii++){
|
||||
i64 iOff = (i64)(pMain->nPagesize) * (i64)ii;
|
||||
if( iOff==PENDING_BYTE ) continue;
|
||||
rc = sqlite3OsRead(pMain->pReal, aData, pMain->nPagesize, iOff);
|
||||
|
@ -466,7 +466,7 @@ static int readJournalFile(jt_file *p, jt_file *pMain){
|
|||
continue;
|
||||
}
|
||||
}
|
||||
nRec = (iSize-iOff) / (pMain->nPagesize+8);
|
||||
nRec = (u32)((iSize-iOff) / (pMain->nPagesize+8));
|
||||
}
|
||||
|
||||
/* Read all the records that follow the journal-header just read. */
|
||||
|
@ -538,7 +538,7 @@ static int jtWrite(
|
|||
}
|
||||
|
||||
if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
|
||||
if( iAmt<p->nPagesize
|
||||
if( iAmt<(int)p->nPagesize
|
||||
&& p->nPagesize%iAmt==0
|
||||
&& iOfst>=(PENDING_BYTE+512)
|
||||
&& iOfst+iAmt<=PENDING_BYTE+p->nPagesize
|
||||
|
@ -549,7 +549,7 @@ static int jtWrite(
|
|||
** pending-byte page.
|
||||
*/
|
||||
}else{
|
||||
u32 pgno = iOfst/p->nPagesize + 1;
|
||||
u32 pgno = (u32)(iOfst/p->nPagesize + 1);
|
||||
assert( (iAmt==1||iAmt==p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 );
|
||||
assert( pgno<=p->nPage || p->nSync>0 );
|
||||
assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) );
|
||||
|
@ -578,7 +578,7 @@ static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
|||
if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
|
||||
u32 pgno;
|
||||
u32 locking_page = (u32)(PENDING_BYTE/p->nPagesize+1);
|
||||
for(pgno=size/p->nPagesize+1; pgno<=p->nPage; pgno++){
|
||||
for(pgno=(u32)(size/p->nPagesize+1); pgno<=p->nPage; pgno++){
|
||||
assert( pgno==locking_page || sqlite3BitvecTest(p->pWritable, pgno) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -329,6 +329,7 @@ static sqlite3_file *multiplexSubOpen(
|
|||
** database may therefore not grow to larger than 400 chunks. Attempting
|
||||
** to open chunk 401 indicates the database is full. */
|
||||
if( iChunk>=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){
|
||||
sqlite3_log(SQLITE_FULL, "multiplexed chunk overflow: %s", pGroup->zName);
|
||||
*rc = SQLITE_FULL;
|
||||
return 0;
|
||||
}
|
||||
|
@ -347,7 +348,13 @@ static sqlite3_file *multiplexSubOpen(
|
|||
}else{
|
||||
*rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[iChunk].z,
|
||||
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;
|
||||
}
|
||||
pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile );
|
||||
|
@ -359,6 +366,8 @@ static sqlite3_file *multiplexSubOpen(
|
|||
*rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
|
||||
flags, pOutFlags);
|
||||
if( (*rc)!=SQLITE_OK ){
|
||||
sqlite3_log(*rc, "multiplexor.xOpen failure on %s",
|
||||
pGroup->aReal[iChunk].z);
|
||||
sqlite3_free(pSubOpen);
|
||||
pGroup->aReal[iChunk].p = 0;
|
||||
return 0;
|
||||
|
@ -529,7 +538,7 @@ static int multiplexOpen(
|
|||
pGroup->bEnabled = -1;
|
||||
pGroup->bTruncate = sqlite3_uri_boolean(zUri, "truncate",
|
||||
(flags & SQLITE_OPEN_MAIN_DB)==0);
|
||||
pGroup->szChunk = sqlite3_uri_int64(zUri, "chunksize",
|
||||
pGroup->szChunk = (int)sqlite3_uri_int64(zUri, "chunksize",
|
||||
SQLITE_MULTIPLEX_CHUNK_SIZE);
|
||||
pGroup->szChunk = (pGroup->szChunk+0xffff)&~0xffff;
|
||||
if( zName ){
|
||||
|
@ -597,7 +606,7 @@ static int multiplexOpen(
|
|||
bExists = multiplexSubSize(pGroup, 1, &rc)>0;
|
||||
if( rc==SQLITE_OK && bExists && sz==(sz&0xffff0000) && sz>0
|
||||
&& sz!=pGroup->szChunk ){
|
||||
pGroup->szChunk = sz;
|
||||
pGroup->szChunk = (int)sz;
|
||||
}else if( rc==SQLITE_OK && !bExists && sz>pGroup->szChunk ){
|
||||
pGroup->bEnabled = 0;
|
||||
}
|
||||
|
|
|
@ -288,7 +288,7 @@ static int tmpWrite(
|
|||
){
|
||||
tmp_file *pTmp = (tmp_file *)pFile;
|
||||
if( (iAmt+iOfst)>pTmp->nAlloc ){
|
||||
int nNew = 2*(iAmt+iOfst+pTmp->nAlloc);
|
||||
int nNew = (int)(2*(iAmt+iOfst+pTmp->nAlloc));
|
||||
char *zNew = sqlite3_realloc(pTmp->zAlloc, nNew);
|
||||
if( !zNew ){
|
||||
return SQLITE_NOMEM;
|
||||
|
@ -297,7 +297,7 @@ static int tmpWrite(
|
|||
pTmp->nAlloc = nNew;
|
||||
}
|
||||
memcpy(&pTmp->zAlloc[iOfst], zBuf, iAmt);
|
||||
pTmp->nSize = MAX(pTmp->nSize, iOfst+iAmt);
|
||||
pTmp->nSize = (int)MAX(pTmp->nSize, iOfst+iAmt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -306,7 +306,7 @@ static int tmpWrite(
|
|||
*/
|
||||
static int tmpTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
tmp_file *pTmp = (tmp_file *)pFile;
|
||||
pTmp->nSize = MIN(pTmp->nSize, size);
|
||||
pTmp->nSize = (int)MIN(pTmp->nSize, size);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -418,7 +418,7 @@ static int fsRead(
|
|||
/* Journal file. */
|
||||
int iRem = iAmt;
|
||||
int iBuf = 0;
|
||||
int ii = iOfst;
|
||||
int ii = (int)iOfst;
|
||||
while( iRem>0 && rc==SQLITE_OK ){
|
||||
int iRealOff = pReal->nBlob - BLOCKSIZE*((ii/BLOCKSIZE)+1) + ii%BLOCKSIZE;
|
||||
int iRealAmt = MIN(iRem, BLOCKSIZE - (iRealOff%BLOCKSIZE));
|
||||
|
@ -453,14 +453,14 @@ static int fsWrite(
|
|||
}else{
|
||||
rc = pF->pMethods->xWrite(pF, zBuf, iAmt, iOfst+BLOCKSIZE);
|
||||
if( rc==SQLITE_OK ){
|
||||
pReal->nDatabase = MAX(pReal->nDatabase, iAmt+iOfst);
|
||||
pReal->nDatabase = (int)MAX(pReal->nDatabase, iAmt+iOfst);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Journal file. */
|
||||
int iRem = iAmt;
|
||||
int iBuf = 0;
|
||||
int ii = iOfst;
|
||||
int ii = (int)iOfst;
|
||||
while( iRem>0 && rc==SQLITE_OK ){
|
||||
int iRealOff = pReal->nBlob - BLOCKSIZE*((ii/BLOCKSIZE)+1) + ii%BLOCKSIZE;
|
||||
int iRealAmt = MIN(iRem, BLOCKSIZE - (iRealOff%BLOCKSIZE));
|
||||
|
@ -475,7 +475,7 @@ static int fsWrite(
|
|||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pReal->nJournal = MAX(pReal->nJournal, iAmt+iOfst);
|
||||
pReal->nJournal = (int)MAX(pReal->nJournal, iAmt+iOfst);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,9 +489,9 @@ static int fsTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
|||
fs_file *p = (fs_file *)pFile;
|
||||
fs_real_file *pReal = p->pReal;
|
||||
if( p->eType==DATABASE_FILE ){
|
||||
pReal->nDatabase = MIN(pReal->nDatabase, size);
|
||||
pReal->nDatabase = (int)MIN(pReal->nDatabase, size);
|
||||
}else{
|
||||
pReal->nJournal = MIN(pReal->nJournal, size);
|
||||
pReal->nJournal = (int)MIN(pReal->nJournal, size);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -641,7 +641,7 @@ static int fsOpen(
|
|||
pReal->nBlob = BLOBSIZE;
|
||||
}else{
|
||||
unsigned char zS[4];
|
||||
pReal->nBlob = size;
|
||||
pReal->nBlob = (int)size;
|
||||
rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, 0);
|
||||
pReal->nDatabase = (zS[0]<<24)+(zS[1]<<16)+(zS[2]<<8)+zS[3];
|
||||
if( rc==SQLITE_OK ){
|
||||
|
|
|
@ -242,7 +242,7 @@ static sqlite3_uint64 vfslog_time(){
|
|||
}
|
||||
#endif
|
||||
|
||||
static void vfslog_call(sqlite3_vfs *, int, int, int, int, int, int);
|
||||
static void vfslog_call(sqlite3_vfs *, int, int, sqlite3_int64, int, int, int);
|
||||
static void vfslog_string(sqlite3_vfs *, const char *);
|
||||
|
||||
/*
|
||||
|
@ -648,7 +648,7 @@ static void vfslog_call(
|
|||
sqlite3_vfs *pVfs,
|
||||
int eEvent,
|
||||
int iFileid,
|
||||
int nClick,
|
||||
sqlite3_int64 nClick,
|
||||
int return_code,
|
||||
int size,
|
||||
int offset
|
||||
|
@ -661,7 +661,7 @@ static void vfslog_call(
|
|||
zRec = (unsigned char *)&p->aBuf[p->nBuf];
|
||||
put32bits(&zRec[0], eEvent);
|
||||
put32bits(&zRec[4], iFileid);
|
||||
put32bits(&zRec[8], nClick);
|
||||
put32bits(&zRec[8], (unsigned int)(nClick&0xffff));
|
||||
put32bits(&zRec[12], return_code);
|
||||
put32bits(&zRec[16], size);
|
||||
put32bits(&zRec[20], offset);
|
||||
|
@ -1043,7 +1043,7 @@ static int vlogColumn(
|
|||
}
|
||||
case 1: {
|
||||
char *zStr = pCsr->zTransient;
|
||||
if( val!=0 && val<pCsr->nFile ){
|
||||
if( val!=0 && val<(unsigned)pCsr->nFile ){
|
||||
zStr = pCsr->azFile[val];
|
||||
}
|
||||
sqlite3_result_text(ctx, zStr, -1, SQLITE_TRANSIENT);
|
||||
|
|
204
src/test_quota.c
204
src/test_quota.c
|
@ -120,6 +120,9 @@ struct quota_FILE {
|
|||
FILE *f; /* Open stdio file pointer */
|
||||
sqlite3_int64 iOfst; /* Current offset into the file */
|
||||
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 *p = 0;
|
||||
char *zFull = 0;
|
||||
char *zFullTranslated;
|
||||
char *zFullTranslated = 0;
|
||||
int rc;
|
||||
quotaGroup *pGroup;
|
||||
quotaFile *pFile;
|
||||
|
@ -995,7 +998,6 @@ quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){
|
|||
zFullTranslated = quota_utf8_to_mbcs(zFull);
|
||||
if( zFullTranslated==0 ) goto quota_fopen_error;
|
||||
p->f = fopen(zFullTranslated, zMode);
|
||||
quota_mbcs_free(zFullTranslated);
|
||||
if( p->f==0 ) goto quota_fopen_error;
|
||||
quotaEnter();
|
||||
pGroup = quotaGroupFind(zFull);
|
||||
|
@ -1010,9 +1012,13 @@ quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){
|
|||
}
|
||||
quotaLeave();
|
||||
sqlite3_free(zFull);
|
||||
#if SQLITE_OS_WIN
|
||||
p->zMbcsName = zFullTranslated;
|
||||
#endif
|
||||
return p;
|
||||
|
||||
quota_fopen_error:
|
||||
quota_mbcs_free(zFullTranslated);
|
||||
sqlite3_free(zFull);
|
||||
if( p && p->f ) fclose(p->f);
|
||||
sqlite3_free(p);
|
||||
|
@ -1045,6 +1051,7 @@ size_t sqlite3_quota_fwrite(
|
|||
sqlite3_int64 iEnd;
|
||||
sqlite3_int64 szNew;
|
||||
quotaFile *pFile;
|
||||
size_t rc;
|
||||
|
||||
iOfst = ftell(p->f);
|
||||
iEnd = iOfst + size*nmemb;
|
||||
|
@ -1060,7 +1067,7 @@ size_t sqlite3_quota_fwrite(
|
|||
}
|
||||
if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
|
||||
iEnd = pGroup->iLimit - pGroup->iSize + pFile->iSize;
|
||||
nmemb = (iEnd - iOfst)/size;
|
||||
nmemb = (size_t)((iEnd - iOfst)/size);
|
||||
iEnd = iOfst + size*nmemb;
|
||||
szNew = pGroup->iSize - pFile->iSize + iEnd;
|
||||
}
|
||||
|
@ -1068,8 +1075,23 @@ size_t sqlite3_quota_fwrite(
|
|||
pGroup->iSize = szNew;
|
||||
pFile->iSize = iEnd;
|
||||
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();
|
||||
}
|
||||
#if SQLITE_OS_WIN
|
||||
quota_mbcs_free(p->zMbcsName);
|
||||
#endif
|
||||
sqlite3_free(p);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1135,6 +1160,83 @@ long sqlite3_quota_ftell(quota_FILE *p){
|
|||
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.
|
||||
*/
|
||||
|
@ -1656,6 +1758,96 @@ static int test_quota_ftell(
|
|||
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
|
||||
*/
|
||||
|
@ -1726,6 +1918,10 @@ int Sqlitequota_Init(Tcl_Interp *interp){
|
|||
{ "sqlite3_quota_fseek", test_quota_fseek },
|
||||
{ "sqlite3_quota_rewind", test_quota_rewind },
|
||||
{ "sqlite3_quota_ftell", test_quota_ftell },
|
||||
{ "sqlite3_quota_ftruncate", test_quota_ftruncate },
|
||||
{ "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 },
|
||||
};
|
||||
|
|
|
@ -29,6 +29,14 @@
|
|||
#ifndef _QUOTA_H_
|
||||
#include "sqlite3.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++ */
|
||||
#ifdef __cplusplus
|
||||
|
@ -182,6 +190,48 @@ int sqlite3_quota_fseek(quota_FILE*, long, int);
|
|||
void sqlite3_quota_rewind(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.
|
||||
** Adjust quotas accordingly.
|
||||
|
|
|
@ -49,7 +49,11 @@ static void circle_del(void *p){
|
|||
static int circle_geom(
|
||||
sqlite3_rtree_geometry *p,
|
||||
int nCoord,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
sqlite3_int64 *aCoord,
|
||||
#else
|
||||
double *aCoord,
|
||||
#endif
|
||||
int *pRes
|
||||
){
|
||||
int i; /* Iterator variable */
|
||||
|
@ -189,7 +193,11 @@ static int gHere = 42;
|
|||
static int cube_geom(
|
||||
sqlite3_rtree_geometry *p,
|
||||
int nCoord,
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
sqlite3_int64 *aCoord,
|
||||
#else
|
||||
double *aCoord,
|
||||
#endif
|
||||
int *piRes
|
||||
){
|
||||
Cube *pCube = (Cube *)p->pUser;
|
||||
|
|
|
@ -324,12 +324,13 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
|||
u64 dummy;
|
||||
iOff += sqlite3GetVarint(&aData[iOff], &dummy);
|
||||
}
|
||||
if( nPayload>p->nMxPayload ) p->nMxPayload = nPayload;
|
||||
if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload;
|
||||
getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
|
||||
pCell->nLocal = nLocal;
|
||||
assert( nLocal>=0 );
|
||||
assert( nPayload>=nLocal );
|
||||
assert( nLocal<=(nUsable-35) );
|
||||
if( nPayload>nLocal ){
|
||||
if( nPayload>(u32)nLocal ){
|
||||
int j;
|
||||
int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
|
||||
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
|
||||
|
@ -378,7 +379,7 @@ static void statSizeAndOffset(StatCursor *pCsr){
|
|||
x[0] = pCsr->iPageno;
|
||||
if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
|
||||
pCsr->iOffset = x[0];
|
||||
pCsr->szPage = x[1];
|
||||
pCsr->szPage = (int)x[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,7 +401,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
|
|||
rc = sqlite3_step(pCsr->pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
int nPage;
|
||||
u32 iRoot = sqlite3_column_int64(pCsr->pStmt, 1);
|
||||
u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1);
|
||||
sqlite3PagerPagecount(pPager, &nPage);
|
||||
if( nPage==0 ){
|
||||
pCsr->isEof = 1;
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
typedef struct wholenumber_cursor wholenumber_cursor;
|
||||
struct wholenumber_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
unsigned iValue; /* Current value */
|
||||
unsigned mxValue; /* Maximum value */
|
||||
sqlite3_int64 iValue; /* Current value */
|
||||
sqlite3_int64 mxValue; /* Maximum value */
|
||||
};
|
||||
|
||||
/* Methods for the wholenumber module */
|
||||
|
|
|
@ -2734,9 +2734,11 @@ case OP_Savepoint: {
|
|||
rc = p->rc;
|
||||
}else{
|
||||
iSavepoint = db->nSavepoint - iSavepoint - 1;
|
||||
if( p1==SAVEPOINT_ROLLBACK ){
|
||||
for(ii=0; ii<db->nDb; ii++){
|
||||
sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT);
|
||||
}
|
||||
}
|
||||
for(ii=0; ii<db->nDb; ii++){
|
||||
rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);
|
||||
if( rc!=SQLITE_OK ){
|
||||
|
|
|
@ -1239,7 +1239,7 @@ int sqlite3VdbeList(
|
|||
for(j=0; j<nSub; j++){
|
||||
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[nSub++] = pOp->p4.pProgram;
|
||||
pSub->flags |= MEM_Blob;
|
||||
|
|
|
@ -59,10 +59,10 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
|||
** Make sure pMem->z points to a writable allocation of at least
|
||||
** n bytes.
|
||||
**
|
||||
** If the memory cell currently contains string or blob data
|
||||
** and the third argument passed to this function is true, the
|
||||
** current content of the cell is preserved. Otherwise, it may
|
||||
** be discarded.
|
||||
** If the third argument passed to this function is true, then memory
|
||||
** cell pMem must contain a string or blob. In this case the content is
|
||||
** preserved. Otherwise, if the third parameter to this function is false,
|
||||
** any current string or blob value may be discarded.
|
||||
**
|
||||
** 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
|
||||
|
@ -77,6 +77,10 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
|
|||
);
|
||||
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( sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){
|
||||
if( preserve && pMem->z==pMem->zMalloc ){
|
||||
|
|
|
@ -901,6 +901,12 @@ do_test capi3-11.9.3 {
|
|||
do_test capi3-11.10 {
|
||||
sqlite3_step $STMT
|
||||
} {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 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ROW}
|
||||
|
|
|
@ -856,6 +856,12 @@ do_test capi3c-11.9.3 {
|
|||
do_test capi3c-11.10 {
|
||||
sqlite3_step $STMT
|
||||
} {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 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ROW}
|
||||
|
|
|
@ -117,9 +117,9 @@ do_test check-1.17 {
|
|||
do_test check-2.1 {
|
||||
execsql {
|
||||
CREATE TABLE t2(
|
||||
x INTEGER CHECK( typeof(coalesce(x,0))=="integer" ),
|
||||
y REAL CHECK( typeof(coalesce(y,0.1))=='real' ),
|
||||
z TEXT CHECK( typeof(coalesce(z,''))=='text' )
|
||||
x INTEGER CONSTRAINT one CHECK( typeof(coalesce(x,0))=="integer" ),
|
||||
y REAL CONSTRAINT two CHECK( typeof(coalesce(y,0.1))=='real' ),
|
||||
z TEXT CONSTRAINT three CHECK( typeof(coalesce(z,''))=='text' )
|
||||
);
|
||||
}
|
||||
} {}
|
||||
|
@ -141,17 +141,17 @@ do_test check-2.4 {
|
|||
catchsql {
|
||||
INSERT INTO t2 VALUES(1.1, NULL, NULL);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
} {1 {constraint one failed}}
|
||||
do_test check-2.5 {
|
||||
catchsql {
|
||||
INSERT INTO t2 VALUES(NULL, 5, NULL);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
} {1 {constraint two failed}}
|
||||
do_test check-2.6 {
|
||||
catchsql {
|
||||
INSERT INTO t2 VALUES(NULL, NULL, 3.14159);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
} {1 {constraint three failed}}
|
||||
|
||||
ifcapable subquery {
|
||||
do_test check-3.1 {
|
||||
|
|
|
@ -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';
|
||||
} {{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
|
||||
|
|
|
@ -20,6 +20,11 @@ source $testdir/bc_common.tcl
|
|||
|
||||
set ::testprefix fts4merge3
|
||||
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
if {"" == [bc_find_binaries backcompat.test]} {
|
||||
finish_test
|
||||
return
|
||||
|
|
14
test/in.test
14
test/in.test
|
@ -258,17 +258,29 @@ do_test in-7.5 {
|
|||
SELECT a FROM t1 WHERE a IN (5) AND b NOT IN ();
|
||||
}
|
||||
} {5}
|
||||
do_test in-7.6 {
|
||||
do_test in-7.6.1 {
|
||||
execsql {
|
||||
SELECT a FROM ta WHERE a IN ();
|
||||
}
|
||||
} {}
|
||||
do_test in-7.6.2 {
|
||||
db status step
|
||||
} {0}
|
||||
do_test in-7.7 {
|
||||
execsql {
|
||||
SELECT a FROM ta WHERE a NOT IN ();
|
||||
}
|
||||
} {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 {
|
||||
execsql {
|
||||
SELECT b FROM t1 WHERE a IN ('hello','there')
|
||||
|
|
|
@ -83,6 +83,13 @@ do_test quota2-1.1 {
|
|||
do_test quota2-1.2 {
|
||||
set ::quota
|
||||
} {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 {
|
||||
sqlite3_quota_rewind $::h1
|
||||
set ::x [sqlite3_quota_fread $::h1 1001 7]
|
||||
|
@ -119,15 +126,43 @@ do_test quota2-1.11 {
|
|||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 1 0}}}
|
||||
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
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/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
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}}
|
||||
|
||||
|
||||
|
||||
set quota {}
|
||||
do_test quota2-2.1 {
|
||||
set ::h1 [sqlite3_quota_fopen quota2c/xyz.txt w+b]
|
||||
|
|
|
@ -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
|
|
@ -331,6 +331,53 @@ do_test subquery-3.3.5 {
|
|||
}
|
||||
} {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
|
||||
# and expose bugs to do with re-using statements that have been
|
||||
|
|
|
@ -12,8 +12,8 @@ make sqlite3.c
|
|||
gcc -o sqlite3 -g -Os -I. \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_ENABLE_VFSTRACE \
|
||||
-DSQLITE_ENABLE_STAT2 \
|
||||
-DSQLITE_ENABLE_FTS3 \
|
||||
-DSQLITE_ENABLE_STAT3 \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_ENABLE_RTREE \
|
||||
-DHAVE_READLINE \
|
||||
-DHAVE_USLEEP=1 \
|
||||
|
|
224
tool/showdb.c
224
tool/showdb.c
|
@ -9,6 +9,7 @@
|
|||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
|
||||
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
|
||||
*/
|
||||
|
@ -458,6 +677,7 @@ static void usage(const char *argv0){
|
|||
fprintf(stderr,
|
||||
"args:\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..end Show hex of pages NNN through end of file\n"
|
||||
" NNNb Decode btree page NNN\n"
|
||||
|
@ -503,6 +723,10 @@ int main(int argc, char **argv){
|
|||
print_db_header();
|
||||
continue;
|
||||
}
|
||||
if( strcmp(argv[i], "pgidx")==0 ){
|
||||
page_usage_report(argv[1]);
|
||||
continue;
|
||||
}
|
||||
if( !isdigit(argv[i][0]) ){
|
||||
fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
|
||||
continue;
|
||||
|
|
|
@ -49,15 +49,14 @@ if {$true_file_size<512} {
|
|||
#
|
||||
set extension [file extension $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] {
|
||||
incr true_file_size [file size $f]
|
||||
set extension {}
|
||||
}
|
||||
if {[string length $extension]>=2 && [string length $extension]<=4} {
|
||||
set pattern [file rootname $file_to_analyze]
|
||||
append pattern [string range $extension 0 1]
|
||||
append pattern {[0-9][0-9]}
|
||||
append pattern {.[0-3][0-9][0-9]}
|
||||
foreach f [glob -nocomplain $pattern] {
|
||||
incr true_file_size [file size $f]
|
||||
}
|
||||
|
|
|
@ -9,5 +9,6 @@ echo '************* FTS4 and RTREE ****************'
|
|||
scan-build gcc -c -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_DEBUG sqlite3.c 2>&1 | grep -v 'ANALYZE:'
|
||||
echo '********** ENABLE_STAT3. THREADSAFE=0 *******'
|
||||
scan-build gcc -c -DSQLITE_ENABLE_STAT3 -DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_DEBUG sqlite3.c 2>&1 | grep -v 'ANALYZE:'
|
||||
scan-build gcc -c -I. -DSQLITE_ENABLE_STAT3 -DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_DEBUG \
|
||||
sqlite3.c ../sqlite/src/shell.c -ldl 2>&1 | grep -v 'ANALYZE:'
|
||||
|
|
Loading…
Reference in New Issue