mirror of
https://github.com/status-im/sqlcipher.git
synced 2026-08-31 14:31:11 +00:00
Snapshot of upstream SQLite 3.30.1
This commit is contained in:
+3
-2
@@ -136,8 +136,8 @@ void sqlite3AlterRenameTable(
|
||||
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
|
||||
goto exit_rename_table;
|
||||
}
|
||||
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto
|
||||
exit_rename_table;
|
||||
if( SQLITE_OK!=sqlite3CheckObjectName(pParse,zName,"table",zName) ){
|
||||
goto exit_rename_table;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
@@ -435,6 +435,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
|
||||
sqlite3MayAbort(pParse);
|
||||
assert( pTab->addColOffset>0 );
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
|
||||
|
||||
+76
-137
@@ -27,13 +27,13 @@
|
||||
** is between 3.6.18 and 3.7.8, inclusive, and unless SQLite is compiled
|
||||
** with SQLITE_ENABLE_STAT2. The sqlite_stat2 table is deprecated.
|
||||
** The sqlite_stat2 table is superseded by sqlite_stat3, which is only
|
||||
** created and used by SQLite versions 3.7.9 and later and with
|
||||
** created and used by SQLite versions 3.7.9 through 3.29.0 when
|
||||
** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3
|
||||
** is a superset of sqlite_stat2. The sqlite_stat4 is an enhanced
|
||||
** version of sqlite_stat3 and is only available when compiled with
|
||||
** SQLITE_ENABLE_STAT4 and in SQLite versions 3.8.1 and later. It is
|
||||
** not possible to enable both STAT3 and STAT4 at the same time. If they
|
||||
** are both enabled, then STAT4 takes precedence.
|
||||
** is a superset of sqlite_stat2 and is also now deprecated. The
|
||||
** sqlite_stat4 is an enhanced version of sqlite_stat3 and is only
|
||||
** available when compiled with SQLITE_ENABLE_STAT4 and in SQLite
|
||||
** versions 3.8.1 and later. STAT4 is the only variant that is still
|
||||
** supported.
|
||||
**
|
||||
** For most applications, sqlite_stat1 provides all the statistics required
|
||||
** for the query planner to make good choices.
|
||||
@@ -144,17 +144,11 @@
|
||||
|
||||
#if defined(SQLITE_ENABLE_STAT4)
|
||||
# define IsStat4 1
|
||||
# define IsStat3 0
|
||||
#elif defined(SQLITE_ENABLE_STAT3)
|
||||
# define IsStat4 0
|
||||
# define IsStat3 1
|
||||
#else
|
||||
# define IsStat4 0
|
||||
# define IsStat3 0
|
||||
# undef SQLITE_STAT4_SAMPLES
|
||||
# define SQLITE_STAT4_SAMPLES 1
|
||||
#endif
|
||||
#define IsStat34 (IsStat3+IsStat4) /* 1 for STAT3 or STAT4. 0 otherwise */
|
||||
|
||||
/*
|
||||
** This routine generates code that opens the sqlite_statN tables.
|
||||
@@ -183,14 +177,10 @@ static void openStatTable(
|
||||
{ "sqlite_stat1", "tbl,idx,stat" },
|
||||
#if defined(SQLITE_ENABLE_STAT4)
|
||||
{ "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" },
|
||||
{ "sqlite_stat3", 0 },
|
||||
#elif defined(SQLITE_ENABLE_STAT3)
|
||||
{ "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" },
|
||||
{ "sqlite_stat4", 0 },
|
||||
#else
|
||||
{ "sqlite_stat3", 0 },
|
||||
{ "sqlite_stat4", 0 },
|
||||
#endif
|
||||
{ "sqlite_stat3", 0 },
|
||||
};
|
||||
int i;
|
||||
sqlite3 *db = pParse->db;
|
||||
@@ -271,7 +261,7 @@ typedef struct Stat4Sample Stat4Sample;
|
||||
struct Stat4Sample {
|
||||
tRowcnt *anEq; /* sqlite_stat4.nEq */
|
||||
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
tRowcnt *anLt; /* sqlite_stat4.nLt */
|
||||
union {
|
||||
i64 iRowid; /* Rowid in main table of the key */
|
||||
@@ -302,7 +292,7 @@ struct Stat4Accum {
|
||||
|
||||
/* Reclaim memory used by a Stat4Sample
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ){
|
||||
@@ -314,7 +304,7 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
||||
|
||||
/* Initialize the BLOB value of a ROWID
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
||||
@@ -330,7 +320,7 @@ static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
||||
|
||||
/* Initialize the INTEGER value of a ROWID.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
||||
@@ -343,7 +333,7 @@ static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
||||
/*
|
||||
** Copy the contents of object (*pFrom) into (*pTo).
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
||||
pTo->isPSample = pFrom->isPSample;
|
||||
pTo->iCol = pFrom->iCol;
|
||||
@@ -364,7 +354,7 @@ static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
||||
*/
|
||||
static void stat4Destructor(void *pOld){
|
||||
Stat4Accum *p = (Stat4Accum*)pOld;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int i;
|
||||
for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
||||
for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
|
||||
@@ -384,7 +374,7 @@ static void stat4Destructor(void *pOld){
|
||||
** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the
|
||||
** total number of columns in the table.
|
||||
**
|
||||
** Note 2: C is only used for STAT3 and STAT4.
|
||||
** Note 2: C is only used for STAT4.
|
||||
**
|
||||
** For indexes on ordinary rowid tables, N==K+1. But for indexes on
|
||||
** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
|
||||
@@ -407,7 +397,7 @@ static void statInit(
|
||||
int nColUp; /* nCol rounded up for alignment */
|
||||
int n; /* Bytes of space to allocate */
|
||||
sqlite3 *db; /* Database connection */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int mxSample = SQLITE_STAT4_SAMPLES;
|
||||
#endif
|
||||
|
||||
@@ -424,7 +414,7 @@ static void statInit(
|
||||
n = sizeof(*p)
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */
|
||||
+ sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */
|
||||
+ sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
|
||||
@@ -444,7 +434,7 @@ static void statInit(
|
||||
p->current.anDLt = (tRowcnt*)&p[1];
|
||||
p->current.anEq = &p->current.anDLt[nColUp];
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
{
|
||||
u8 *pSpace; /* Allocated space not yet assigned */
|
||||
int i; /* Used to iterate through p->aSample[] */
|
||||
@@ -479,7 +469,7 @@ static void statInit(
|
||||
sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor);
|
||||
}
|
||||
static const FuncDef statInitFuncdef = {
|
||||
2+IsStat34, /* nArg */
|
||||
2+IsStat4, /* nArg */
|
||||
SQLITE_UTF8, /* funcFlags */
|
||||
0, /* pUserData */
|
||||
0, /* pNext */
|
||||
@@ -519,7 +509,7 @@ static int sampleIsBetterPost(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/*
|
||||
** Return true if pNew is to be preferred over pOld.
|
||||
**
|
||||
@@ -538,15 +528,11 @@ static int sampleIsBetter(
|
||||
assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) );
|
||||
|
||||
if( (nEqNew>nEqOld) ) return 1;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( nEqNew==nEqOld ){
|
||||
if( pNew->iCol<pOld->iCol ) return 1;
|
||||
return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld));
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return (nEqNew==nEqOld && pNew->iHash>pOld->iHash);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -559,7 +545,6 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
|
||||
assert( IsStat4 || nEqZero==0 );
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0
|
||||
** values in the anEq[] array of any sample in Stat4Accum.a[]. In
|
||||
** other words, if nMaxEqZero is n, then it is guaranteed that there
|
||||
@@ -593,7 +578,6 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
goto find_new_min;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If necessary, remove sample iMin to make room for the new sample. */
|
||||
if( p->nSample>=p->mxSample ){
|
||||
@@ -614,10 +598,8 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
/* The "rows less-than" for the rowid column must be greater than that
|
||||
** for the last sample in the p->a[] array. Otherwise, the samples would
|
||||
** be out of order. */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
assert( p->nSample==0
|
||||
|| pNew->anLt[p->nCol-1] > p->a[p->nSample-1].anLt[p->nCol-1] );
|
||||
#endif
|
||||
|
||||
/* Insert the new sample */
|
||||
pSample = &p->a[p->nSample];
|
||||
@@ -627,9 +609,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
/* Zero the first nEqZero entries in the anEq[] array. */
|
||||
memset(pSample->anEq, 0, sizeof(tRowcnt)*nEqZero);
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
find_new_min:
|
||||
#endif
|
||||
find_new_min:
|
||||
if( p->nSample>=p->mxSample ){
|
||||
int iMin = -1;
|
||||
for(i=0; i<p->mxSample; i++){
|
||||
@@ -642,7 +622,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
p->iMin = iMin;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/*
|
||||
** Field iChng of the index being scanned has changed. So at this point
|
||||
@@ -683,28 +663,7 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_ENABLE_STAT3) && !defined(SQLITE_ENABLE_STAT4)
|
||||
if( iChng==0 ){
|
||||
tRowcnt nLt = p->current.anLt[0];
|
||||
tRowcnt nEq = p->current.anEq[0];
|
||||
|
||||
/* Check if this is to be a periodic sample. If so, add it. */
|
||||
if( (nLt/p->nPSample)!=(nLt+nEq)/p->nPSample ){
|
||||
p->current.isPSample = 1;
|
||||
sampleInsert(p, &p->current, 0);
|
||||
p->current.isPSample = 0;
|
||||
}else
|
||||
|
||||
/* Or if it is a non-periodic sample. Add it in this case too. */
|
||||
if( p->nSample<p->mxSample
|
||||
|| sampleIsBetter(p, &p->current, &p->a[p->iMin])
|
||||
){
|
||||
sampleInsert(p, &p->current, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifndef SQLITE_ENABLE_STAT4
|
||||
UNUSED_PARAMETER( p );
|
||||
UNUSED_PARAMETER( iChng );
|
||||
#endif
|
||||
@@ -724,7 +683,7 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
|
||||
** index being analyzed. The stat_get() SQL function will later be used to
|
||||
** extract relevant information for constructing the sqlite_statN tables.
|
||||
**
|
||||
** The R parameter is only used for STAT3 and STAT4
|
||||
** The R parameter is only used for STAT4
|
||||
*/
|
||||
static void statPush(
|
||||
sqlite3_context *context,
|
||||
@@ -756,14 +715,14 @@ static void statPush(
|
||||
}
|
||||
for(i=iChng; i<p->nCol; i++){
|
||||
p->current.anDLt[i]++;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
p->current.anLt[i] += p->current.anEq[i];
|
||||
#endif
|
||||
p->current.anEq[i] = 1;
|
||||
}
|
||||
}
|
||||
p->nRow++;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
|
||||
sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
|
||||
}else{
|
||||
@@ -796,7 +755,7 @@ static void statPush(
|
||||
#endif
|
||||
}
|
||||
static const FuncDef statPushFuncdef = {
|
||||
2+IsStat34, /* nArg */
|
||||
2+IsStat4, /* nArg */
|
||||
SQLITE_UTF8, /* funcFlags */
|
||||
0, /* pUserData */
|
||||
0, /* pNext */
|
||||
@@ -827,7 +786,7 @@ static const FuncDef statPushFuncdef = {
|
||||
** parameter will always be a poiner to a Stat4Accum object, never a
|
||||
** NULL.
|
||||
**
|
||||
** If neither STAT3 nor STAT4 are enabled, then J is always
|
||||
** If STAT4 is not enabled, then J is always
|
||||
** STAT_GET_STAT1 and is hence omitted and this routine becomes
|
||||
** a one-parameter function, stat_get(P), that always returns the
|
||||
** stat1 table entry information.
|
||||
@@ -838,8 +797,8 @@ static void statGet(
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
/* STAT3 and STAT4 have a parameter on this routine. */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/* STAT4 has a parameter on this routine. */
|
||||
int eCall = sqlite3_value_int(argv[1]);
|
||||
assert( argc==2 );
|
||||
assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ
|
||||
@@ -894,7 +853,7 @@ static void statGet(
|
||||
|
||||
sqlite3_result_text(context, zRet, -1, sqlite3_free);
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
else if( eCall==STAT_GET_ROWID ){
|
||||
if( p->iGet<0 ){
|
||||
samplePushPrevious(p, 0);
|
||||
@@ -923,9 +882,7 @@ static void statGet(
|
||||
}
|
||||
}
|
||||
|
||||
if( IsStat3 ){
|
||||
sqlite3_result_int64(context, (i64)aCnt[0]);
|
||||
}else{
|
||||
{
|
||||
char *zRet = sqlite3MallocZero(p->nCol * 25);
|
||||
if( zRet==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
@@ -942,13 +899,13 @@ static void statGet(
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
#ifndef SQLITE_DEBUG
|
||||
UNUSED_PARAMETER( argc );
|
||||
#endif
|
||||
}
|
||||
static const FuncDef statGetFuncdef = {
|
||||
1+IsStat34, /* nArg */
|
||||
1+IsStat4, /* nArg */
|
||||
SQLITE_UTF8, /* funcFlags */
|
||||
0, /* pUserData */
|
||||
0, /* pNext */
|
||||
@@ -961,7 +918,7 @@ static const FuncDef statGetFuncdef = {
|
||||
|
||||
static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
|
||||
assert( regOut!=regStat4 && regOut!=regStat4+1 );
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, iParam, regStat4+1);
|
||||
#elif SQLITE_DEBUG
|
||||
assert( iParam==STAT_GET_STAT1 );
|
||||
@@ -970,7 +927,7 @@ static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
|
||||
#endif
|
||||
sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut,
|
||||
(char*)&statGetFuncdef, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, 1 + IsStat34);
|
||||
sqlite3VdbeChangeP5(v, 1 + IsStat4);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -997,7 +954,7 @@ static void analyzeOneTable(
|
||||
int regNewRowid = iMem++; /* Rowid for the inserted record */
|
||||
int regStat4 = iMem++; /* Register to hold Stat4Accum object */
|
||||
int regChng = iMem++; /* Index of changed index field */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int regRowid = iMem++; /* Rowid argument passed to stat_push() */
|
||||
#endif
|
||||
int regTemp = iMem++; /* Temporary use register */
|
||||
@@ -1131,16 +1088,16 @@ static void analyzeOneTable(
|
||||
** (3) the number of rows in the index,
|
||||
**
|
||||
**
|
||||
** The third argument is only used for STAT3 and STAT4
|
||||
** The third argument is only used for STAT4
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
|
||||
#endif
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
|
||||
sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4,
|
||||
(char*)&statInitFuncdef, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, 2+IsStat34);
|
||||
sqlite3VdbeChangeP5(v, 2+IsStat4);
|
||||
|
||||
/* Implementation of the following:
|
||||
**
|
||||
@@ -1211,12 +1168,12 @@ static void analyzeOneTable(
|
||||
|
||||
/*
|
||||
** chng_addr_N:
|
||||
** regRowid = idx(rowid) // STAT34 only
|
||||
** stat_push(P, regChng, regRowid) // 3rd parameter STAT34 only
|
||||
** regRowid = idx(rowid) // STAT4 only
|
||||
** stat_push(P, regChng, regRowid) // 3rd parameter STAT4 only
|
||||
** Next csr
|
||||
** if !eof(csr) goto next_row;
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
assert( regRowid==(regStat4+2) );
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
|
||||
@@ -1237,7 +1194,7 @@ static void analyzeOneTable(
|
||||
assert( regChng==(regStat4+1) );
|
||||
sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp,
|
||||
(char*)&statPushFuncdef, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, 2+IsStat34);
|
||||
sqlite3VdbeChangeP5(v, 2+IsStat4);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
|
||||
|
||||
/* Add the entry to the stat1 table. */
|
||||
@@ -1251,8 +1208,8 @@ static void analyzeOneTable(
|
||||
#endif
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
|
||||
/* Add the entries to the stat3 or stat4 table. */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
/* Add the entries to the stat4 table. */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
{
|
||||
int regEq = regStat1;
|
||||
int regLt = regStat1+1;
|
||||
@@ -1275,21 +1232,17 @@ static void analyzeOneTable(
|
||||
callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
|
||||
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
|
||||
VdbeCoverage(v);
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
|
||||
#else
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample);
|
||||
#endif
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regTemp, regNewRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */
|
||||
sqlite3VdbeJumpHere(v, addrIsNull);
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/* End of analysis */
|
||||
sqlite3VdbeJumpHere(v, addrRewind);
|
||||
@@ -1464,7 +1417,7 @@ static void decodeIntArray(
|
||||
int i;
|
||||
tRowcnt v;
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( z==0 ) z = "";
|
||||
#else
|
||||
assert( z!=0 );
|
||||
@@ -1475,7 +1428,7 @@ static void decodeIntArray(
|
||||
v = v*10 + c - '0';
|
||||
z++;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( aOut ) aOut[i] = v;
|
||||
if( aLog ) aLog[i] = sqlite3LogEst(v);
|
||||
#else
|
||||
@@ -1486,7 +1439,7 @@ static void decodeIntArray(
|
||||
#endif
|
||||
if( *z==' ' ) z++;
|
||||
}
|
||||
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifndef SQLITE_ENABLE_STAT4
|
||||
assert( pIndex!=0 ); {
|
||||
#else
|
||||
if( pIndex ){
|
||||
@@ -1497,7 +1450,9 @@ static void decodeIntArray(
|
||||
if( sqlite3_strglob("unordered*", z)==0 ){
|
||||
pIndex->bUnordered = 1;
|
||||
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
|
||||
pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
|
||||
int sz = sqlite3Atoi(z+3);
|
||||
if( sz<2 ) sz = 2;
|
||||
pIndex->szIdxRow = sqlite3LogEst(sz);
|
||||
}else if( sqlite3_strglob("noskipscan*", z)==0 ){
|
||||
pIndex->noSkipScan = 1;
|
||||
}
|
||||
@@ -1551,7 +1506,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
if( pIndex ){
|
||||
tRowcnt *aiRowEst = 0;
|
||||
int nCol = pIndex->nKeyCol+1;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/* Index.aiRowEst may already be set here if there are duplicate
|
||||
** sqlite_stat1 entries for this index. In that case just clobber
|
||||
** the old data with the new instead of allocating a new array. */
|
||||
@@ -1587,7 +1542,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
** and its contents.
|
||||
*/
|
||||
void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( pIdx->aSample ){
|
||||
int j;
|
||||
for(j=0; j<pIdx->nSample; j++){
|
||||
@@ -1603,10 +1558,10 @@ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
|
||||
#else
|
||||
UNUSED_PARAMETER(db);
|
||||
UNUSED_PARAMETER(pIdx);
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/*
|
||||
** Populate the pIdx->aAvgEq[] array based on the samples currently
|
||||
** stored in pIdx->aSample[].
|
||||
@@ -1684,12 +1639,11 @@ static Index *findIndexOrPrimaryKey(
|
||||
}
|
||||
|
||||
/*
|
||||
** Load the content from either the sqlite_stat4 or sqlite_stat3 table
|
||||
** Load the content from either the sqlite_stat4
|
||||
** into the relevant Index.aSample[] arrays.
|
||||
**
|
||||
** Arguments zSql1 and zSql2 must point to SQL statements that return
|
||||
** data equivalent to the following (statements are different for stat3,
|
||||
** see the caller of this function for details):
|
||||
** data equivalent to the following:
|
||||
**
|
||||
** zSql1: SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx
|
||||
** zSql2: SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4
|
||||
@@ -1698,7 +1652,6 @@ static Index *findIndexOrPrimaryKey(
|
||||
*/
|
||||
static int loadStatTbl(
|
||||
sqlite3 *db, /* Database handle */
|
||||
int bStat3, /* Assume single column records only */
|
||||
const char *zSql1, /* SQL statement 1 (see above) */
|
||||
const char *zSql2, /* SQL statement 2 (see above) */
|
||||
const char *zDb /* Database name (e.g. "main") */
|
||||
@@ -1732,17 +1685,13 @@ static int loadStatTbl(
|
||||
if( zIndex==0 ) continue;
|
||||
nSample = sqlite3_column_int(pStmt, 1);
|
||||
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
|
||||
assert( pIdx==0 || bStat3 || pIdx->nSample==0 );
|
||||
/* Index.nSample is non-zero at this point if data has already been
|
||||
** loaded from the stat4 table. In this case ignore stat3 data. */
|
||||
if( pIdx==0 || pIdx->nSample ) continue;
|
||||
if( bStat3==0 ){
|
||||
assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
|
||||
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
|
||||
nIdxCol = pIdx->nKeyCol;
|
||||
}else{
|
||||
nIdxCol = pIdx->nColumn;
|
||||
}
|
||||
assert( pIdx==0 || pIdx->nSample==0 );
|
||||
if( pIdx==0 ) continue;
|
||||
assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
|
||||
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
|
||||
nIdxCol = pIdx->nKeyCol;
|
||||
}else{
|
||||
nIdxCol = pIdx->nColumn;
|
||||
}
|
||||
pIdx->nSampleCol = nIdxCol;
|
||||
nByte = sizeof(IndexSample) * nSample;
|
||||
@@ -1784,9 +1733,8 @@ static int loadStatTbl(
|
||||
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
|
||||
if( pIdx==0 ) continue;
|
||||
/* This next condition is true if data has already been loaded from
|
||||
** the sqlite_stat4 table. In this case ignore stat3 data. */
|
||||
** the sqlite_stat4 table. */
|
||||
nCol = pIdx->nSampleCol;
|
||||
if( bStat3 && nCol>1 ) continue;
|
||||
if( pIdx!=pPrevIdx ){
|
||||
initAvgEq(pPrevIdx);
|
||||
pPrevIdx = pIdx;
|
||||
@@ -1819,7 +1767,7 @@ static int loadStatTbl(
|
||||
}
|
||||
|
||||
/*
|
||||
** Load content from the sqlite_stat4 and sqlite_stat3 tables into
|
||||
** Load content from the sqlite_stat4 table into
|
||||
** the Index.aSample[] arrays of all indices.
|
||||
*/
|
||||
static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
@@ -1827,37 +1775,28 @@ static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
|
||||
assert( db->lookaside.bDisable );
|
||||
if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
|
||||
rc = loadStatTbl(db, 0,
|
||||
rc = loadStatTbl(db,
|
||||
"SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
|
||||
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
|
||||
zDb
|
||||
);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && sqlite3FindTable(db, "sqlite_stat3", zDb) ){
|
||||
rc = loadStatTbl(db, 1,
|
||||
"SELECT idx,count(*) FROM %Q.sqlite_stat3 GROUP BY idx",
|
||||
"SELECT idx,neq,nlt,ndlt,sqlite_record(sample) FROM %Q.sqlite_stat3",
|
||||
zDb
|
||||
);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/*
|
||||
** Load the content of the sqlite_stat1 and sqlite_stat3/4 tables. The
|
||||
** Load the content of the sqlite_stat1 and sqlite_stat4 tables. The
|
||||
** contents of sqlite_stat1 are used to populate the Index.aiRowEst[]
|
||||
** arrays. The contents of sqlite_stat3/4 are used to populate the
|
||||
** arrays. The contents of sqlite_stat4 are used to populate the
|
||||
** Index.aSample[] arrays.
|
||||
**
|
||||
** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR
|
||||
** is returned. In this case, even if SQLITE_ENABLE_STAT3/4 was defined
|
||||
** during compilation and the sqlite_stat3/4 table is present, no data is
|
||||
** is returned. In this case, even if SQLITE_ENABLE_STAT4 was defined
|
||||
** during compilation and the sqlite_stat4 table is present, no data is
|
||||
** read from it.
|
||||
**
|
||||
** If SQLITE_ENABLE_STAT3/4 was defined during compilation and the
|
||||
** If SQLITE_ENABLE_STAT4 was defined during compilation and the
|
||||
** sqlite_stat4 table is not present in the database, SQLITE_ERROR is
|
||||
** returned. However, in this case, data is read from the sqlite_stat1
|
||||
** table (if it is present) before returning.
|
||||
@@ -1885,7 +1824,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
|
||||
Index *pIdx = sqliteHashData(i);
|
||||
pIdx->hasStat1 = 0;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
sqlite3DeleteIndexSamples(db, pIdx);
|
||||
pIdx->aSample = 0;
|
||||
#endif
|
||||
@@ -1913,7 +1852,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
}
|
||||
|
||||
/* Load the statistics from the sqlite_stat4 table. */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( rc==SQLITE_OK ){
|
||||
db->lookaside.bDisable++;
|
||||
rc = loadStat4(db, sInfo.zDatabase);
|
||||
|
||||
@@ -299,6 +299,7 @@ static void detachFunc(
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
int i;
|
||||
Db *pDb = 0;
|
||||
HashElem *pEntry;
|
||||
char zErr[128];
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
@@ -323,6 +324,18 @@ static void detachFunc(
|
||||
goto detach_error;
|
||||
}
|
||||
|
||||
/* If any TEMP triggers reference the schema being detached, move those
|
||||
** triggers to reference the TEMP schema itself. */
|
||||
assert( db->aDb[1].pSchema );
|
||||
pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash);
|
||||
while( pEntry ){
|
||||
Trigger *pTrig = (Trigger*)sqliteHashData(pEntry);
|
||||
if( pTrig->pTabSchema==pDb->pSchema ){
|
||||
pTrig->pTabSchema = pTrig->pSchema;
|
||||
}
|
||||
pEntry = sqliteHashNext(pEntry);
|
||||
}
|
||||
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
@@ -560,6 +573,7 @@ int sqlite3FixExpr(
|
||||
Expr *pExpr /* The expression to be fixed to one database */
|
||||
){
|
||||
while( pExpr ){
|
||||
ExprSetProperty(pExpr, EP_Indirect);
|
||||
if( pExpr->op==TK_VARIABLE ){
|
||||
if( pFix->pParse->db->init.busy ){
|
||||
pExpr->op = TK_NULL;
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ int sqlite3_set_authorizer(
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->xAuth = (sqlite3_xauth)xAuth;
|
||||
db->pAuthArg = pArg;
|
||||
sqlite3ExpirePreparedStatements(db, 0);
|
||||
if( db->xAuth ) sqlite3ExpirePreparedStatements(db, 1);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -619,8 +619,10 @@ int sqlite3_backup_finish(sqlite3_backup *p){
|
||||
}
|
||||
if( p->isAttached ){
|
||||
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc));
|
||||
assert( pp!=0 );
|
||||
while( *pp!=p ){
|
||||
pp = &(*pp)->pNext;
|
||||
assert( pp!=0 );
|
||||
}
|
||||
*pp = p->pNext;
|
||||
}
|
||||
|
||||
+30
-18
@@ -1647,9 +1647,12 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){
|
||||
u8 *pSpace = pageFindSlot(pPage, nByte, &rc);
|
||||
if( pSpace ){
|
||||
assert( pSpace>=data && (pSpace - data)<65536 );
|
||||
*pIdx = (int)(pSpace - data);
|
||||
return SQLITE_OK;
|
||||
assert( pSpace+nByte<=data+pPage->pBt->usableSize );
|
||||
if( (*pIdx = (int)(pSpace-data))<=gap ){
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}else{
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}else if( rc ){
|
||||
return rc;
|
||||
}
|
||||
@@ -4876,6 +4879,7 @@ static int accessPayload(
|
||||
assert( aWrite>=pBufStart ); /* due to (6) */
|
||||
memcpy(aSave, aWrite, 4);
|
||||
rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
|
||||
if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT;
|
||||
nextPage = get4byte(aWrite);
|
||||
memcpy(aWrite, aSave, 4);
|
||||
}else
|
||||
@@ -6664,12 +6668,7 @@ static void insertCell(
|
||||
assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
|
||||
assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
/* The cell should normally be sized correctly. However, when moving a
|
||||
** malformed cell from a leaf page to an interior page, if the cell size
|
||||
** wanted to be less than 4 but got rounded up to 4 on the leaf, then size
|
||||
** might be less than 8 (leaf-size + pointer) on the interior node. Hence
|
||||
** the term after the || in the following assert(). */
|
||||
assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) );
|
||||
assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
|
||||
assert( pPage->nFree>=0 );
|
||||
if( pPage->nOverflow || sz+2>pPage->nFree ){
|
||||
if( pTemp ){
|
||||
@@ -6901,7 +6900,7 @@ static int rebuildPage(
|
||||
|
||||
assert( i<iEnd );
|
||||
j = get2byte(&aData[hdr+5]);
|
||||
if( NEVER(j>(u32)usableSize) ){ j = 0; }
|
||||
if( j>(u32)usableSize ){ j = 0; }
|
||||
memcpy(&pTmp[j], &aData[j], usableSize - j);
|
||||
|
||||
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
|
||||
@@ -6993,7 +6992,8 @@ static int pageInsertArray(
|
||||
while( 1 /*Exit by break*/ ){
|
||||
int sz, rc;
|
||||
u8 *pSlot;
|
||||
sz = cachedCellSize(pCArray, i);
|
||||
assert( pCArray->szCell[i]!=0 );
|
||||
sz = pCArray->szCell[i];
|
||||
if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){
|
||||
if( (pData - pBegin)<sz ) return 1;
|
||||
pData -= sz;
|
||||
@@ -7154,6 +7154,7 @@ static int editPage(
|
||||
memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2);
|
||||
}
|
||||
nCell++;
|
||||
cachedCellSize(pCArray, iCell+iNew);
|
||||
if( pageInsertArray(
|
||||
pPg, pBegin, &pData, pCellptr,
|
||||
iCell+iNew, 1, pCArray
|
||||
@@ -7676,7 +7677,7 @@ static int balance_nonroot(
|
||||
*/
|
||||
memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
|
||||
if( pOld->nOverflow>0 ){
|
||||
if( limit<pOld->aiOvfl[0] ){
|
||||
if( NEVER(limit<pOld->aiOvfl[0]) ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto balance_cleanup;
|
||||
}
|
||||
@@ -7962,6 +7963,8 @@ static int balance_nonroot(
|
||||
));
|
||||
|
||||
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
|
||||
assert( nNew>=1 && nNew<=ArraySize(apNew) );
|
||||
assert( apNew[nNew-1]!=0 );
|
||||
put4byte(pRight, apNew[nNew-1]->pgno);
|
||||
|
||||
/* If the sibling pages are not leaves, ensure that the right-child pointer
|
||||
@@ -8307,11 +8310,13 @@ static int balance(BtCursor *pCur){
|
||||
VVA_ONLY( int balance_deeper_called = 0 );
|
||||
|
||||
do {
|
||||
int iPage = pCur->iPage;
|
||||
int iPage;
|
||||
MemPage *pPage = pCur->pPage;
|
||||
|
||||
if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break;
|
||||
if( iPage==0 ){
|
||||
if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
|
||||
break;
|
||||
}else if( (iPage = pCur->iPage)==0 ){
|
||||
if( pPage->nOverflow ){
|
||||
/* The root page of the b-tree is overfull. In this case call the
|
||||
** balance_deeper() function to create a new child for the root-page
|
||||
@@ -8332,8 +8337,6 @@ static int balance(BtCursor *pCur){
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
|
||||
break;
|
||||
}else{
|
||||
MemPage * const pParent = pCur->apPage[iPage-1];
|
||||
int const iIdx = pCur->aiIdx[iPage-1];
|
||||
@@ -8475,7 +8478,9 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
|
||||
Pgno ovflPgno; /* Next overflow page to write */
|
||||
u32 ovflPageSize; /* Size to write on overflow page */
|
||||
|
||||
if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd ){
|
||||
if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
|
||||
|| pCur->info.pPayload < pPage->aData + pPage->cellOffset
|
||||
){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
/* Overwrite the local portion first */
|
||||
@@ -8716,6 +8721,8 @@ int sqlite3BtreeInsert(
|
||||
memcpy(newCell, oldCell, 4);
|
||||
}
|
||||
rc = clearCell(pPage, oldCell, &info);
|
||||
testcase( pCur->curFlags & BTCF_ValidOvfl );
|
||||
invalidateOverflowCache(pCur);
|
||||
if( info.nSize==szNew && info.nLocal==info.nPayload
|
||||
&& (!ISAUTOVACUUM || szNew<pPage->minLocal)
|
||||
){
|
||||
@@ -8729,7 +8736,12 @@ int sqlite3BtreeInsert(
|
||||
** new entry uses overflow pages, as the insertCell() call below is
|
||||
** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */
|
||||
assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */
|
||||
if( oldCell+szNew > pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
|
||||
if( oldCell < pPage->aData+pPage->hdrOffset+10 ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
if( oldCell+szNew > pPage->aDataEnd ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
memcpy(oldCell, newCell, szNew);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+93
-34
@@ -456,7 +456,7 @@ void sqlite3FreeIndex(sqlite3 *db, Index *p){
|
||||
sqlite3ExprListDelete(db, p->aColExpr);
|
||||
sqlite3DbFree(db, p->zColAff);
|
||||
if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl);
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
sqlite3_free(p->aiRowEst);
|
||||
#endif
|
||||
sqlite3DbFree(db, p);
|
||||
@@ -829,13 +829,40 @@ int sqlite3WritableSchema(sqlite3 *db){
|
||||
** trigger). All names are legal except those that begin with the string
|
||||
** "sqlite_" (in upper, lower or mixed case). This portion of the namespace
|
||||
** is reserved for internal use.
|
||||
**
|
||||
** When parsing the sqlite_master table, this routine also checks to
|
||||
** make sure the "type", "name", and "tbl_name" columns are consistent
|
||||
** with the SQL.
|
||||
*/
|
||||
int sqlite3CheckObjectName(Parse *pParse, const char *zName){
|
||||
if( !pParse->db->init.busy && pParse->nested==0
|
||||
&& sqlite3WritableSchema(pParse->db)==0
|
||||
&& 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
|
||||
sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName);
|
||||
return SQLITE_ERROR;
|
||||
int sqlite3CheckObjectName(
|
||||
Parse *pParse, /* Parsing context */
|
||||
const char *zName, /* Name of the object to check */
|
||||
const char *zType, /* Type of this object */
|
||||
const char *zTblName /* Parent table name for triggers and indexes */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( sqlite3WritableSchema(db) || db->init.imposterTable ){
|
||||
/* Skip these error checks for writable_schema=ON */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( db->init.busy ){
|
||||
if( sqlite3_stricmp(zType, db->init.azInit[0])
|
||||
|| sqlite3_stricmp(zName, db->init.azInit[1])
|
||||
|| sqlite3_stricmp(zTblName, db->init.azInit[2])
|
||||
){
|
||||
if( sqlite3Config.bExtraSchemaChecks ){
|
||||
sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if( pParse->nested==0
|
||||
&& 0==sqlite3StrNICmp(zName, "sqlite_", 7)
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s",
|
||||
zName);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -916,7 +943,7 @@ void sqlite3StartTable(
|
||||
}
|
||||
pParse->sNameToken = *pName;
|
||||
if( zName==0 ) return;
|
||||
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||
if( sqlite3CheckObjectName(pParse, zName, isView?"view":"table", zName) ){
|
||||
goto begin_table_error;
|
||||
}
|
||||
if( db->init.iDb==1 ) isTemp = 1;
|
||||
@@ -1416,7 +1443,7 @@ void sqlite3AddPrimaryKey(
|
||||
pTab->keyConf = (u8)onError;
|
||||
assert( autoInc==0 || autoInc==1 );
|
||||
pTab->tabFlags |= autoInc*TF_Autoincrement;
|
||||
if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder;
|
||||
if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags;
|
||||
}else if( autoInc ){
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
|
||||
@@ -1831,6 +1858,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
Index *pIdx;
|
||||
Index *pPk;
|
||||
int nPk;
|
||||
int nExtra;
|
||||
int i, j;
|
||||
sqlite3 *db = pParse->db;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
@@ -1866,13 +1894,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey);
|
||||
}
|
||||
pList->a[0].sortOrder = pParse->iPkSortOrder;
|
||||
pList->a[0].sortFlags = pParse->iPkSortOrder;
|
||||
assert( pParse->pNewTable==pTab );
|
||||
pTab->iPKey = -1;
|
||||
sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
|
||||
SQLITE_IDXTYPE_PRIMARYKEY);
|
||||
if( db->mallocFailed || pParse->nErr ) return;
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
assert( pPk->nKeyCol==1 );
|
||||
}else{
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
assert( pPk!=0 );
|
||||
@@ -1887,6 +1916,8 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
pPk->nColumn--;
|
||||
}else{
|
||||
testcase( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) );
|
||||
pPk->azColl[j] = pPk->azColl[i];
|
||||
pPk->aSortOrder[j] = pPk->aSortOrder[i];
|
||||
pPk->aiColumn[j++] = pPk->aiColumn[i];
|
||||
}
|
||||
}
|
||||
@@ -1895,7 +1926,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
assert( pPk!=0 );
|
||||
pPk->isCovering = 1;
|
||||
if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
|
||||
nPk = pPk->nKeyCol;
|
||||
nPk = pPk->nColumn = pPk->nKeyCol;
|
||||
|
||||
/* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
|
||||
** table entry. This is only required if currently generating VDBE
|
||||
@@ -1945,21 +1976,21 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
|
||||
/* Add all table columns to the PRIMARY KEY index
|
||||
*/
|
||||
if( nPk<pTab->nCol ){
|
||||
if( resizeIndexObject(db, pPk, pTab->nCol) ) return;
|
||||
for(i=0, j=nPk; i<pTab->nCol; i++){
|
||||
if( !hasColumn(pPk->aiColumn, j, i) ){
|
||||
assert( j<pPk->nColumn );
|
||||
pPk->aiColumn[j] = i;
|
||||
pPk->azColl[j] = sqlite3StrBINARY;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
assert( pPk->nColumn==j );
|
||||
assert( pTab->nCol==j );
|
||||
}else{
|
||||
pPk->nColumn = pTab->nCol;
|
||||
nExtra = 0;
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( !hasColumn(pPk->aiColumn, nPk, i) ) nExtra++;
|
||||
}
|
||||
if( resizeIndexObject(db, pPk, nPk+nExtra) ) return;
|
||||
for(i=0, j=nPk; i<pTab->nCol; i++){
|
||||
if( !hasColumn(pPk->aiColumn, j, i) ){
|
||||
assert( j<pPk->nColumn );
|
||||
pPk->aiColumn[j] = i;
|
||||
pPk->azColl[j] = sqlite3StrBINARY;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
assert( pPk->nColumn==j );
|
||||
assert( pTab->nCol<=j );
|
||||
recomputeColumnsNotIndexed(pPk);
|
||||
}
|
||||
|
||||
@@ -2156,7 +2187,7 @@ void sqlite3EndTable(
|
||||
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
||||
if( pParse->nErr ) return;
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect, SQLITE_AFF_BLOB);
|
||||
if( pSelTab==0 ) return;
|
||||
assert( p->aCol==0 );
|
||||
p->nCol = pSelTab->nCol;
|
||||
@@ -2420,10 +2451,10 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
xAuth = db->xAuth;
|
||||
db->xAuth = 0;
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
|
||||
db->xAuth = xAuth;
|
||||
#else
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
|
||||
#endif
|
||||
pParse->nTab = n;
|
||||
if( pTable->pCheck ){
|
||||
@@ -2439,7 +2470,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
&& pParse->nErr==0
|
||||
&& pTable->nCol==pSel->pEList->nExpr
|
||||
){
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel);
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
|
||||
SQLITE_AFF_NONE);
|
||||
}
|
||||
}else if( pSelTab ){
|
||||
/* CREATE VIEW name AS... without an argument list. Construct
|
||||
@@ -2784,7 +2816,8 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
}
|
||||
#endif
|
||||
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
||||
&& sqlite3StrNICmp(pTab->zName, "sqlite_stat", 11)!=0 ){
|
||||
&& sqlite3StrNICmp(pTab->zName+7, "stat", 4)!=0
|
||||
&& sqlite3StrNICmp(pTab->zName+7, "parameters", 10)!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
|
||||
goto exit_drop_table;
|
||||
}
|
||||
@@ -3121,6 +3154,27 @@ Index *sqlite3AllocateIndexObject(
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** If expression list pList contains an expression that was parsed with
|
||||
** an explicit "NULLS FIRST" or "NULLS LAST" clause, leave an error in
|
||||
** pParse and return non-zero. Otherwise, return zero.
|
||||
*/
|
||||
int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){
|
||||
if( pList ){
|
||||
int i;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( pList->a[i].bNulls ){
|
||||
u8 sf = pList->a[i].sortFlags;
|
||||
sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s",
|
||||
(sf==0 || sf==3) ? "FIRST" : "LAST"
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new index for an SQL table. pName1.pName2 is the name of the index
|
||||
** and pTblList is the name of the table that is to be indexed. Both will
|
||||
@@ -3172,6 +3226,9 @@ void sqlite3CreateIndex(
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( sqlite3HasExplicitNulls(pParse, pList) ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find the table that is to be indexed. Return early if not found.
|
||||
@@ -3270,7 +3327,7 @@ void sqlite3CreateIndex(
|
||||
zName = sqlite3NameFromToken(db, pName);
|
||||
if( zName==0 ) goto exit_create_index;
|
||||
assert( pName->z!=0 );
|
||||
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName,"index",pTab->zName) ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( !IN_RENAME_OBJECT ){
|
||||
@@ -3336,7 +3393,7 @@ void sqlite3CreateIndex(
|
||||
sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
|
||||
if( pList==0 ) goto exit_create_index;
|
||||
assert( pList->nExpr==1 );
|
||||
sqlite3ExprListSetSortOrder(pList, sortOrder);
|
||||
sqlite3ExprListSetSortOrder(pList, sortOrder, SQLITE_SO_UNDEFINED);
|
||||
}else{
|
||||
sqlite3ExprListCheckLength(pParse, pList, "index");
|
||||
if( pParse->nErr ) goto exit_create_index;
|
||||
@@ -3454,7 +3511,7 @@ void sqlite3CreateIndex(
|
||||
goto exit_create_index;
|
||||
}
|
||||
pIndex->azColl[i] = zColl;
|
||||
requestedSortOrder = pListItem->sortOrder & sortOrderMask;
|
||||
requestedSortOrder = pListItem->sortFlags & sortOrderMask;
|
||||
pIndex->aSortOrder[i] = (u8)requestedSortOrder;
|
||||
}
|
||||
|
||||
@@ -3629,6 +3686,7 @@ void sqlite3CreateIndex(
|
||||
/* Gather the complete text of the CREATE INDEX statement into
|
||||
** the zStmt variable
|
||||
*/
|
||||
assert( pName!=0 || pStart==0 );
|
||||
if( pStart ){
|
||||
int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
|
||||
if( pName->z[n-1]==';' ) n--;
|
||||
@@ -4671,7 +4729,8 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
|
||||
const char *zColl = pIdx->azColl[i];
|
||||
pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 :
|
||||
sqlite3LocateCollSeq(pParse, zColl);
|
||||
pKey->aSortOrder[i] = pIdx->aSortOrder[i];
|
||||
pKey->aSortFlags[i] = pIdx->aSortOrder[i];
|
||||
assert( 0==(pKey->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) );
|
||||
}
|
||||
if( pParse->nErr ){
|
||||
assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ );
|
||||
|
||||
@@ -306,8 +306,6 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_STAT4)
|
||||
"ENABLE_STAT4",
|
||||
#elif defined(SQLITE_ENABLE_STAT3)
|
||||
"ENABLE_STAT3",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_STMTVTAB
|
||||
"ENABLE_STMTVTAB",
|
||||
|
||||
+248
-138
@@ -44,7 +44,6 @@ char sqlite3TableColumnAffinity(Table *pTab, int iCol){
|
||||
*/
|
||||
char sqlite3ExprAffinity(Expr *pExpr){
|
||||
int op;
|
||||
if( pExpr->flags & EP_Generic ) return 0;
|
||||
while( ExprHasProperty(pExpr, EP_Skip) ){
|
||||
assert( pExpr->op==TK_COLLATE );
|
||||
pExpr = pExpr->pLeft;
|
||||
@@ -71,7 +70,7 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
|
||||
);
|
||||
}
|
||||
return pExpr->affinity;
|
||||
return pExpr->affExpr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -106,10 +105,22 @@ Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
|
||||
}
|
||||
|
||||
/*
|
||||
** Skip over any TK_COLLATE operators and any unlikely()
|
||||
** or likelihood() function at the root of an expression.
|
||||
** Skip over any TK_COLLATE operators.
|
||||
*/
|
||||
Expr *sqlite3ExprSkipCollate(Expr *pExpr){
|
||||
while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){
|
||||
assert( pExpr->op==TK_COLLATE );
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Skip over any TK_COLLATE operators and/or any unlikely()
|
||||
** or likelihood() or likely() functions at the root of an
|
||||
** expression.
|
||||
*/
|
||||
Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
|
||||
while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){
|
||||
if( ExprHasProperty(pExpr, EP_Unlikely) ){
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
@@ -144,7 +155,6 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
Expr *p = pExpr;
|
||||
while( p ){
|
||||
int op = p->op;
|
||||
if( p->flags & EP_Generic ) break;
|
||||
if( op==TK_REGISTER ) op = p->op2;
|
||||
if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER)
|
||||
&& p->y.pTab!=0
|
||||
@@ -230,7 +240,7 @@ int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){
|
||||
*/
|
||||
char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
||||
char aff1 = sqlite3ExprAffinity(pExpr);
|
||||
if( aff1 && aff2 ){
|
||||
if( aff1>SQLITE_AFF_NONE && aff2>SQLITE_AFF_NONE ){
|
||||
/* Both sides of the comparison are columns. If one has numeric
|
||||
** affinity, use that. Otherwise use no affinity.
|
||||
*/
|
||||
@@ -239,15 +249,10 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
||||
}else{
|
||||
return SQLITE_AFF_BLOB;
|
||||
}
|
||||
}else if( !aff1 && !aff2 ){
|
||||
/* Neither side of the comparison is a column. Compare the
|
||||
** results directly.
|
||||
*/
|
||||
return SQLITE_AFF_BLOB;
|
||||
}else{
|
||||
/* One side is a column, the other is not. Use the columns affinity. */
|
||||
assert( aff1==0 || aff2==0 );
|
||||
return (aff1 + aff2);
|
||||
assert( aff1<=SQLITE_AFF_NONE || aff2<=SQLITE_AFF_NONE );
|
||||
return (aff1<=SQLITE_AFF_NONE ? aff2 : aff1) | SQLITE_AFF_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,14 +285,13 @@ static char comparisonAffinity(Expr *pExpr){
|
||||
*/
|
||||
int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
|
||||
char aff = comparisonAffinity(pExpr);
|
||||
switch( aff ){
|
||||
case SQLITE_AFF_BLOB:
|
||||
return 1;
|
||||
case SQLITE_AFF_TEXT:
|
||||
return idx_affinity==SQLITE_AFF_TEXT;
|
||||
default:
|
||||
return sqlite3IsNumericAffinity(idx_affinity);
|
||||
if( aff<SQLITE_AFF_TEXT ){
|
||||
return 1;
|
||||
}
|
||||
if( aff==SQLITE_AFF_TEXT ){
|
||||
return idx_affinity==SQLITE_AFF_TEXT;
|
||||
}
|
||||
return sqlite3IsNumericAffinity(idx_affinity);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -901,7 +905,7 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
|
||||
}else if( ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight) ){
|
||||
sqlite3ExprUnmapAndDelete(pParse, pLeft);
|
||||
sqlite3ExprUnmapAndDelete(pParse, pRight);
|
||||
return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0);
|
||||
return sqlite3Expr(db, TK_INTEGER, "0");
|
||||
}else{
|
||||
return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
|
||||
}
|
||||
@@ -1040,15 +1044,18 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
|
||||
assert( p->x.pList==0 || p->pRight==0 );
|
||||
if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft);
|
||||
if( p->pRight ){
|
||||
assert( !ExprHasProperty(p, EP_WinFunc) );
|
||||
sqlite3ExprDeleteNN(db, p->pRight);
|
||||
}else if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||
assert( !ExprHasProperty(p, EP_WinFunc) );
|
||||
sqlite3SelectDelete(db, p->x.pSelect);
|
||||
}else{
|
||||
sqlite3ExprListDelete(db, p->x.pList);
|
||||
}
|
||||
if( ExprHasProperty(p, EP_WinFunc) ){
|
||||
assert( p->op==TK_FUNCTION );
|
||||
sqlite3WindowDelete(db, p->y.pWin);
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(p, EP_WinFunc) ){
|
||||
sqlite3WindowDelete(db, p->y.pWin);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
|
||||
@@ -1083,16 +1090,6 @@ static int exprStructSize(Expr *p){
|
||||
return EXPR_FULLSIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
** Copy the complete content of an Expr node, taking care not to read
|
||||
** past the end of the structure for a reduced-size version of the source
|
||||
** Expr.
|
||||
*/
|
||||
static void exprNodeCopy(Expr *pDest, Expr *pSrc){
|
||||
memset(pDest, 0, sizeof(Expr));
|
||||
memcpy(pDest, pSrc, exprStructSize(pSrc));
|
||||
}
|
||||
|
||||
/*
|
||||
** The dupedExpr*Size() routines each return the number of bytes required
|
||||
** to store a copy of an expression or expression tree. They differ in
|
||||
@@ -1332,10 +1329,13 @@ static With *withDup(sqlite3 *db, With *p){
|
||||
** objects found there, assembling them onto the linked list at Select->pWin.
|
||||
*/
|
||||
static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op==TK_FUNCTION && pExpr->y.pWin!=0 ){
|
||||
assert( ExprHasProperty(pExpr, EP_WinFunc) );
|
||||
pExpr->y.pWin->pNextWin = pWalker->u.pSelect->pWin;
|
||||
pWalker->u.pSelect->pWin = pExpr->y.pWin;
|
||||
if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
Select *pSelect = pWalker->u.pSelect;
|
||||
Window *pWin = pExpr->y.pWin;
|
||||
assert( pWin );
|
||||
assert( IsWindowFunc(pExpr) );
|
||||
assert( pWin->ppThis==0 );
|
||||
sqlite3WindowLink(pSelect, pWin);
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
@@ -1409,8 +1409,9 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
||||
}
|
||||
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
|
||||
pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
|
||||
pItem->sortOrder = pOldItem->sortOrder;
|
||||
pItem->sortFlags = pOldItem->sortFlags;
|
||||
pItem->done = 0;
|
||||
pItem->bNulls = pOldItem->bNulls;
|
||||
pItem->bSpanIsTab = pOldItem->bSpanIsTab;
|
||||
pItem->bSorterRef = pOldItem->bSorterRef;
|
||||
pItem->u = pOldItem->u;
|
||||
@@ -1521,7 +1522,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
pNew->pWin = 0;
|
||||
pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
|
||||
if( p->pWin ) gatherSelectWindows(pNew);
|
||||
if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew);
|
||||
#endif
|
||||
pNew->selId = p->selId;
|
||||
*pp = pNew;
|
||||
@@ -1630,6 +1631,10 @@ ExprList *sqlite3ExprListAppendVector(
|
||||
|
||||
for(i=0; i<pColumns->nId; i++){
|
||||
Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i);
|
||||
assert( pSubExpr!=0 || db->mallocFailed );
|
||||
assert( pSubExpr==0 || pSubExpr->iTable==0 );
|
||||
if( pSubExpr==0 ) continue;
|
||||
pSubExpr->iTable = pColumns->nId;
|
||||
pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
|
||||
if( pList ){
|
||||
assert( pList->nExpr==iFirst+i+1 );
|
||||
@@ -1662,15 +1667,34 @@ vector_append_error:
|
||||
/*
|
||||
** Set the sort order for the last element on the given ExprList.
|
||||
*/
|
||||
void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){
|
||||
void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){
|
||||
struct ExprList_item *pItem;
|
||||
if( p==0 ) return;
|
||||
assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 );
|
||||
assert( p->nExpr>0 );
|
||||
if( iSortOrder<0 ){
|
||||
assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC );
|
||||
return;
|
||||
|
||||
assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC==0 && SQLITE_SO_DESC>0 );
|
||||
assert( iSortOrder==SQLITE_SO_UNDEFINED
|
||||
|| iSortOrder==SQLITE_SO_ASC
|
||||
|| iSortOrder==SQLITE_SO_DESC
|
||||
);
|
||||
assert( eNulls==SQLITE_SO_UNDEFINED
|
||||
|| eNulls==SQLITE_SO_ASC
|
||||
|| eNulls==SQLITE_SO_DESC
|
||||
);
|
||||
|
||||
pItem = &p->a[p->nExpr-1];
|
||||
assert( pItem->bNulls==0 );
|
||||
if( iSortOrder==SQLITE_SO_UNDEFINED ){
|
||||
iSortOrder = SQLITE_SO_ASC;
|
||||
}
|
||||
pItem->sortFlags = (u8)iSortOrder;
|
||||
|
||||
if( eNulls!=SQLITE_SO_UNDEFINED ){
|
||||
pItem->bNulls = 1;
|
||||
if( iSortOrder!=eNulls ){
|
||||
pItem->sortFlags |= KEYINFO_ORDER_BIGNULL;
|
||||
}
|
||||
}
|
||||
p->a[p->nExpr-1].sortOrder = (u8)iSortOrder;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2169,27 +2193,30 @@ int sqlite3ExprCanBeNull(const Expr *p){
|
||||
*/
|
||||
int sqlite3ExprNeedsNoAffinityChange(const Expr *p, char aff){
|
||||
u8 op;
|
||||
int unaryMinus = 0;
|
||||
if( aff==SQLITE_AFF_BLOB ) return 1;
|
||||
while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; }
|
||||
while( p->op==TK_UPLUS || p->op==TK_UMINUS ){
|
||||
if( p->op==TK_UMINUS ) unaryMinus = 1;
|
||||
p = p->pLeft;
|
||||
}
|
||||
op = p->op;
|
||||
if( op==TK_REGISTER ) op = p->op2;
|
||||
switch( op ){
|
||||
case TK_INTEGER: {
|
||||
return aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC;
|
||||
return aff>=SQLITE_AFF_NUMERIC;
|
||||
}
|
||||
case TK_FLOAT: {
|
||||
return aff==SQLITE_AFF_REAL || aff==SQLITE_AFF_NUMERIC;
|
||||
return aff>=SQLITE_AFF_NUMERIC;
|
||||
}
|
||||
case TK_STRING: {
|
||||
return aff==SQLITE_AFF_TEXT;
|
||||
return !unaryMinus && aff==SQLITE_AFF_TEXT;
|
||||
}
|
||||
case TK_BLOB: {
|
||||
return 1;
|
||||
return !unaryMinus;
|
||||
}
|
||||
case TK_COLUMN: {
|
||||
assert( p->iTable>=0 ); /* p cannot be part of a CHECK constraint */
|
||||
return p->iColumn<0
|
||||
&& (aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC);
|
||||
return aff>=SQLITE_AFF_NUMERIC && p->iColumn<0;
|
||||
}
|
||||
default: {
|
||||
return 0;
|
||||
@@ -2372,7 +2399,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
int sqlite3FindInIndex(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pX, /* The right-hand side (RHS) of the IN operator */
|
||||
Expr *pX, /* The IN expression */
|
||||
u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */
|
||||
int *prRhsHasNull, /* Register holding NULL status. See notes */
|
||||
int *aiMap, /* Mapping from Index fields to RHS fields */
|
||||
@@ -2797,9 +2824,9 @@ void sqlite3CodeRhsOfIN(
|
||||
int i;
|
||||
ExprList *pList = pExpr->x.pList;
|
||||
struct ExprList_item *pItem;
|
||||
int r1, r2, r3;
|
||||
int r1, r2;
|
||||
affinity = sqlite3ExprAffinity(pLeft);
|
||||
if( !affinity ){
|
||||
if( affinity<=SQLITE_AFF_NONE ){
|
||||
affinity = SQLITE_AFF_BLOB;
|
||||
}
|
||||
if( pKeyInfo ){
|
||||
@@ -2825,9 +2852,9 @@ void sqlite3CodeRhsOfIN(
|
||||
}
|
||||
|
||||
/* Evaluate the expression and insert it into the temp table */
|
||||
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r3, 1);
|
||||
sqlite3ExprCode(pParse, pE2, r1);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r1, 1);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ReleaseTempReg(pParse, r2);
|
||||
@@ -2840,6 +2867,7 @@ void sqlite3CodeRhsOfIN(
|
||||
/* Subroutine return */
|
||||
sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
|
||||
sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
@@ -2853,7 +2881,7 @@ void sqlite3CodeRhsOfIN(
|
||||
**
|
||||
** The pExpr parameter is the SELECT or EXISTS operator to be coded.
|
||||
**
|
||||
** The register that holds the result. For a multi-column SELECT,
|
||||
** Return the register that holds the result. For a multi-column SELECT,
|
||||
** the result is stored in a contiguous array of registers and the
|
||||
** return value is the register of the left-most result column.
|
||||
** Return 0 if an error occurs.
|
||||
@@ -2931,11 +2959,21 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm);
|
||||
VdbeComment((v, "Init EXISTS result"));
|
||||
}
|
||||
pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[1], 0);
|
||||
if( pSel->pLimit ){
|
||||
sqlite3ExprDelete(pParse->db, pSel->pLimit->pLeft);
|
||||
/* The subquery already has a limit. If the pre-existing limit is X
|
||||
** then make the new limit X<>0 so that the new limit is either 1 or 0 */
|
||||
sqlite3 *db = pParse->db;
|
||||
pLimit = sqlite3Expr(db, TK_INTEGER, "0");
|
||||
if( pLimit ){
|
||||
pLimit->affExpr = SQLITE_AFF_NUMERIC;
|
||||
pLimit = sqlite3PExpr(pParse, TK_NE,
|
||||
sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit);
|
||||
}
|
||||
sqlite3ExprDelete(db, pSel->pLimit->pLeft);
|
||||
pSel->pLimit->pLeft = pLimit;
|
||||
}else{
|
||||
/* If there is no pre-existing limit add a limit of 1 */
|
||||
pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1");
|
||||
pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
|
||||
}
|
||||
pSel->iLimit = 0;
|
||||
@@ -2950,6 +2988,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
/* Subroutine return */
|
||||
sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
|
||||
sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}
|
||||
|
||||
return rReg;
|
||||
@@ -3097,13 +3136,21 @@ static void sqlite3ExprCodeIN(
|
||||
int r2, regToFree;
|
||||
int regCkNull = 0;
|
||||
int ii;
|
||||
int bLhsReal; /* True if the LHS of the IN has REAL affinity */
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
if( destIfNull!=destIfFalse ){
|
||||
regCkNull = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull);
|
||||
}
|
||||
bLhsReal = sqlite3ExprAffinity(pExpr->pLeft)==SQLITE_AFF_REAL;
|
||||
for(ii=0; ii<pList->nExpr; ii++){
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree);
|
||||
if( bLhsReal ){
|
||||
r2 = regToFree = sqlite3GetTempReg(pParse);
|
||||
sqlite3ExprCode(pParse, pList->a[ii].pExpr, r2);
|
||||
sqlite3VdbeAddOp4(v, OP_Affinity, r2, 1, 0, "E", P4_STATIC);
|
||||
}else{
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree);
|
||||
}
|
||||
if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){
|
||||
sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
|
||||
}
|
||||
@@ -3388,7 +3435,7 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
|
||||
** the correct value for the expression.
|
||||
*/
|
||||
static void exprToRegister(Expr *pExpr, int iReg){
|
||||
Expr *p = sqlite3ExprSkipCollate(pExpr);
|
||||
Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr);
|
||||
p->op2 = p->op;
|
||||
p->op = TK_REGISTER;
|
||||
p->iTable = iReg;
|
||||
@@ -3489,7 +3536,7 @@ expr_code_doover:
|
||||
*/
|
||||
int iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
|
||||
int aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
|
||||
if( aff!=SQLITE_AFF_BLOB ){
|
||||
if( aff>SQLITE_AFF_BLOB ){
|
||||
static const char zAff[] = "B\000C\000D\000E";
|
||||
assert( SQLITE_AFF_BLOB=='A' );
|
||||
assert( SQLITE_AFF_TEXT=='B' );
|
||||
@@ -3505,7 +3552,19 @@ expr_code_doover:
|
||||
if( iTab<0 ){
|
||||
if( pParse->iSelfTab<0 ){
|
||||
/* Generating CHECK constraints or inserting into partial index */
|
||||
return pExpr->iColumn - pParse->iSelfTab;
|
||||
assert( pExpr->y.pTab!=0 );
|
||||
assert( pExpr->iColumn>=XN_ROWID );
|
||||
assert( pExpr->iColumn<pExpr->y.pTab->nCol );
|
||||
if( pExpr->iColumn>=0
|
||||
&& pExpr->y.pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL
|
||||
){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, pExpr->iColumn - pParse->iSelfTab,
|
||||
target);
|
||||
sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
|
||||
return target;
|
||||
}else{
|
||||
return pExpr->iColumn - pParse->iSelfTab;
|
||||
}
|
||||
}else{
|
||||
/* Coding an expression that is part of an index where column names
|
||||
** in the index refer to the table to which the index belongs */
|
||||
@@ -3792,7 +3851,7 @@ expr_code_doover:
|
||||
assert( nFarg==1 );
|
||||
aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
|
||||
sqlite3VdbeLoadString(v, target,
|
||||
aff ? azAff[aff-SQLITE_AFF_BLOB] : "none");
|
||||
(aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
|
||||
return target;
|
||||
}
|
||||
#endif
|
||||
@@ -3900,8 +3959,8 @@ expr_code_doover:
|
||||
pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft);
|
||||
}
|
||||
assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT );
|
||||
if( pExpr->iTable
|
||||
&& pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft))
|
||||
if( pExpr->iTable!=0
|
||||
&& pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft))
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
|
||||
pExpr->iTable, n);
|
||||
@@ -4004,10 +4063,23 @@ expr_code_doover:
|
||||
break;
|
||||
}
|
||||
|
||||
/* TK_IF_NULL_ROW Expr nodes are inserted ahead of expressions
|
||||
** that derive from the right-hand table of a LEFT JOIN. The
|
||||
** Expr.iTable value is the table number for the right-hand table.
|
||||
** The expression is only evaluated if that table is not currently
|
||||
** on a LEFT JOIN NULL row.
|
||||
*/
|
||||
case TK_IF_NULL_ROW: {
|
||||
int addrINR;
|
||||
u8 okConstFactor = pParse->okConstFactor;
|
||||
addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
|
||||
/* Temporarily disable factoring of constant expressions, since
|
||||
** even though expressions may appear to be constant, they are not
|
||||
** really constant because they originate from the right-hand side
|
||||
** of a LEFT JOIN. */
|
||||
pParse->okConstFactor = 0;
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||
pParse->okConstFactor = okConstFactor;
|
||||
sqlite3VdbeJumpHere(v, addrINR);
|
||||
sqlite3VdbeChangeP3(v, addrINR, inReg);
|
||||
break;
|
||||
@@ -4044,6 +4116,8 @@ expr_code_doover:
|
||||
Expr opCompare; /* The X==Ei expression */
|
||||
Expr *pX; /* The X expression */
|
||||
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
|
||||
Expr *pDel = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
|
||||
assert(pExpr->x.pList->nExpr > 0);
|
||||
@@ -4052,13 +4126,17 @@ expr_code_doover:
|
||||
nExpr = pEList->nExpr;
|
||||
endLabel = sqlite3VdbeMakeLabel(pParse);
|
||||
if( (pX = pExpr->pLeft)!=0 ){
|
||||
exprNodeCopy(&tempX, pX);
|
||||
pDel = sqlite3ExprDup(db, pX, 0);
|
||||
if( db->mallocFailed ){
|
||||
sqlite3ExprDelete(db, pDel);
|
||||
break;
|
||||
}
|
||||
testcase( pX->op==TK_COLUMN );
|
||||
exprToRegister(&tempX, exprCodeVector(pParse, &tempX, ®Free1));
|
||||
exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1));
|
||||
testcase( regFree1==0 );
|
||||
memset(&opCompare, 0, sizeof(opCompare));
|
||||
opCompare.op = TK_EQ;
|
||||
opCompare.pLeft = &tempX;
|
||||
opCompare.pLeft = pDel;
|
||||
pTest = &opCompare;
|
||||
/* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001:
|
||||
** The value in regFree1 might get SCopy-ed into the file result.
|
||||
@@ -4086,32 +4164,33 @@ expr_code_doover:
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||
}
|
||||
sqlite3ExprDelete(db, pDel);
|
||||
sqlite3VdbeResolveLabel(v, endLabel);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
case TK_RAISE: {
|
||||
assert( pExpr->affinity==OE_Rollback
|
||||
|| pExpr->affinity==OE_Abort
|
||||
|| pExpr->affinity==OE_Fail
|
||||
|| pExpr->affinity==OE_Ignore
|
||||
assert( pExpr->affExpr==OE_Rollback
|
||||
|| pExpr->affExpr==OE_Abort
|
||||
|| pExpr->affExpr==OE_Fail
|
||||
|| pExpr->affExpr==OE_Ignore
|
||||
);
|
||||
if( !pParse->pTriggerTab ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"RAISE() may only be used within a trigger-program");
|
||||
return 0;
|
||||
}
|
||||
if( pExpr->affinity==OE_Abort ){
|
||||
if( pExpr->affExpr==OE_Abort ){
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
if( pExpr->affinity==OE_Ignore ){
|
||||
if( pExpr->affExpr==OE_Ignore ){
|
||||
sqlite3VdbeAddOp4(
|
||||
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
|
||||
pExpr->affinity, pExpr->u.zToken, 0, 0);
|
||||
pExpr->affExpr, pExpr->u.zToken, 0, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -4176,7 +4255,7 @@ int sqlite3ExprCodeAtInit(
|
||||
*/
|
||||
int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
|
||||
int r2;
|
||||
pExpr = sqlite3ExprSkipCollate(pExpr);
|
||||
pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
|
||||
if( ConstFactorOk(pParse)
|
||||
&& pExpr->op!=TK_REGISTER
|
||||
&& sqlite3ExprIsConstantNotJoin(pExpr)
|
||||
@@ -4367,40 +4446,44 @@ static void exprCodeBetween(
|
||||
void (*xJump)(Parse*,Expr*,int,int), /* Action to take */
|
||||
int jumpIfNull /* Take the jump if the BETWEEN is NULL */
|
||||
){
|
||||
Expr exprAnd; /* The AND operator in x>=y AND x<=z */
|
||||
Expr exprAnd; /* The AND operator in x>=y AND x<=z */
|
||||
Expr compLeft; /* The x>=y term */
|
||||
Expr compRight; /* The x<=z term */
|
||||
Expr exprX; /* The x subexpression */
|
||||
int regFree1 = 0; /* Temporary use register */
|
||||
Expr *pDel = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
memset(&compLeft, 0, sizeof(Expr));
|
||||
memset(&compRight, 0, sizeof(Expr));
|
||||
memset(&exprAnd, 0, sizeof(Expr));
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
exprNodeCopy(&exprX, pExpr->pLeft);
|
||||
exprAnd.op = TK_AND;
|
||||
exprAnd.pLeft = &compLeft;
|
||||
exprAnd.pRight = &compRight;
|
||||
compLeft.op = TK_GE;
|
||||
compLeft.pLeft = &exprX;
|
||||
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
|
||||
compRight.op = TK_LE;
|
||||
compRight.pLeft = &exprX;
|
||||
compRight.pRight = pExpr->x.pList->a[1].pExpr;
|
||||
exprToRegister(&exprX, exprCodeVector(pParse, &exprX, ®Free1));
|
||||
if( xJump ){
|
||||
xJump(pParse, &exprAnd, dest, jumpIfNull);
|
||||
}else{
|
||||
/* Mark the expression is being from the ON or USING clause of a join
|
||||
** so that the sqlite3ExprCodeTarget() routine will not attempt to move
|
||||
** it into the Parse.pConstExpr list. We should use a new bit for this,
|
||||
** for clarity, but we are out of bits in the Expr.flags field so we
|
||||
** have to reuse the EP_FromJoin bit. Bummer. */
|
||||
exprX.flags |= EP_FromJoin;
|
||||
sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
|
||||
pDel = sqlite3ExprDup(db, pExpr->pLeft, 0);
|
||||
if( db->mallocFailed==0 ){
|
||||
exprAnd.op = TK_AND;
|
||||
exprAnd.pLeft = &compLeft;
|
||||
exprAnd.pRight = &compRight;
|
||||
compLeft.op = TK_GE;
|
||||
compLeft.pLeft = pDel;
|
||||
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
|
||||
compRight.op = TK_LE;
|
||||
compRight.pLeft = pDel;
|
||||
compRight.pRight = pExpr->x.pList->a[1].pExpr;
|
||||
exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1));
|
||||
if( xJump ){
|
||||
xJump(pParse, &exprAnd, dest, jumpIfNull);
|
||||
}else{
|
||||
/* Mark the expression is being from the ON or USING clause of a join
|
||||
** so that the sqlite3ExprCodeTarget() routine will not attempt to move
|
||||
** it into the Parse.pConstExpr list. We should use a new bit for this,
|
||||
** for clarity, but we are out of bits in the Expr.flags field so we
|
||||
** have to reuse the EP_FromJoin bit. Bummer. */
|
||||
pDel->flags |= EP_FromJoin;
|
||||
sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regFree1);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regFree1);
|
||||
sqlite3ExprDelete(db, pDel);
|
||||
|
||||
/* Ensure adequate test coverage */
|
||||
testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 );
|
||||
@@ -4839,20 +4922,17 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
|
||||
return 2;
|
||||
}
|
||||
if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
|
||||
if( pA->op==TK_FUNCTION ){
|
||||
if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){
|
||||
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/* Justification for the assert():
|
||||
** window functions have p->op==TK_FUNCTION but aggregate functions
|
||||
** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate
|
||||
** function and a window function should have failed before reaching
|
||||
** this point. And, it is not possible to have a window function and
|
||||
** a scalar function with the same name and number of arguments. So
|
||||
** if we reach this point, either A and B both window functions or
|
||||
** neither are a window functions. */
|
||||
assert( ExprHasProperty(pA,EP_WinFunc)==ExprHasProperty(pB,EP_WinFunc) );
|
||||
assert( pA->op==pB->op );
|
||||
if( ExprHasProperty(pA,EP_WinFunc)!=ExprHasProperty(pB,EP_WinFunc) ){
|
||||
return 2;
|
||||
}
|
||||
if( ExprHasProperty(pA,EP_WinFunc) ){
|
||||
if( sqlite3WindowCompare(pParse,pA->y.pWin,pB->y.pWin)!=0 ) return 2;
|
||||
if( sqlite3WindowCompare(pParse, pA->y.pWin, pB->y.pWin, 1)!=0 ){
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}else if( pA->op==TK_NULL ){
|
||||
@@ -4876,7 +4956,8 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
|
||||
){
|
||||
if( pA->iColumn!=pB->iColumn ) return 2;
|
||||
if( pA->op2!=pB->op2 ) return 2;
|
||||
if( pA->iTable!=pB->iTable
|
||||
if( pA->op!=TK_IN
|
||||
&& pA->iTable!=pB->iTable
|
||||
&& (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
|
||||
}
|
||||
}
|
||||
@@ -4906,7 +4987,7 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
|
||||
for(i=0; i<pA->nExpr; i++){
|
||||
Expr *pExprA = pA->a[i].pExpr;
|
||||
Expr *pExprB = pB->a[i].pExpr;
|
||||
if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
|
||||
if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
|
||||
if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -4918,42 +4999,47 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
|
||||
*/
|
||||
int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){
|
||||
return sqlite3ExprCompare(0,
|
||||
sqlite3ExprSkipCollate(pA),
|
||||
sqlite3ExprSkipCollate(pB),
|
||||
sqlite3ExprSkipCollateAndLikely(pA),
|
||||
sqlite3ExprSkipCollateAndLikely(pB),
|
||||
iTab);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return non-zero if Expr p can only be true if pNN is not NULL.
|
||||
**
|
||||
** Or if seenNot is true, return non-zero if Expr p can only be
|
||||
** non-NULL if pNN is not NULL
|
||||
*/
|
||||
static int exprImpliesNotNull(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *p, /* The expression to be checked */
|
||||
Expr *pNN, /* The expression that is NOT NULL */
|
||||
int iTab, /* Table being evaluated */
|
||||
int seenNot /* True if p is an operand of NOT */
|
||||
int seenNot /* Return true only if p can be any non-NULL value */
|
||||
){
|
||||
assert( p );
|
||||
assert( pNN );
|
||||
if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ) return 1;
|
||||
if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ){
|
||||
return pNN->op!=TK_NULL;
|
||||
}
|
||||
switch( p->op ){
|
||||
case TK_IN: {
|
||||
if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0;
|
||||
assert( ExprHasProperty(p,EP_xIsSelect)
|
||||
|| (p->x.pList!=0 && p->x.pList->nExpr>0) );
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot);
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
|
||||
}
|
||||
case TK_BETWEEN: {
|
||||
ExprList *pList = p->x.pList;
|
||||
assert( pList!=0 );
|
||||
assert( pList->nExpr==2 );
|
||||
if( seenNot ) return 0;
|
||||
if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, seenNot)
|
||||
|| exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, seenNot)
|
||||
if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, 1)
|
||||
|| exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, 1)
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot);
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
|
||||
}
|
||||
case TK_EQ:
|
||||
case TK_NE:
|
||||
@@ -4963,20 +5049,21 @@ static int exprImpliesNotNull(
|
||||
case TK_GE:
|
||||
case TK_PLUS:
|
||||
case TK_MINUS:
|
||||
case TK_BITOR:
|
||||
case TK_LSHIFT:
|
||||
case TK_RSHIFT:
|
||||
case TK_CONCAT:
|
||||
seenNot = 1;
|
||||
/* Fall thru */
|
||||
case TK_STAR:
|
||||
case TK_REM:
|
||||
case TK_BITAND:
|
||||
case TK_BITOR:
|
||||
case TK_SLASH:
|
||||
case TK_LSHIFT:
|
||||
case TK_RSHIFT:
|
||||
case TK_CONCAT: {
|
||||
case TK_SLASH: {
|
||||
if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1;
|
||||
/* Fall thru into the next case */
|
||||
}
|
||||
case TK_SPAN:
|
||||
case TK_COLLATE:
|
||||
case TK_BITNOT:
|
||||
case TK_UPLUS:
|
||||
case TK_UMINUS: {
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot);
|
||||
@@ -4984,8 +5071,9 @@ static int exprImpliesNotNull(
|
||||
case TK_TRUTH: {
|
||||
if( seenNot ) return 0;
|
||||
if( p->op2!=TK_IS ) return 0;
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot);
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
|
||||
}
|
||||
case TK_BITNOT:
|
||||
case TK_NOT: {
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
|
||||
}
|
||||
@@ -5051,7 +5139,6 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune;
|
||||
switch( pExpr->op ){
|
||||
case TK_ISNOT:
|
||||
case TK_NOT:
|
||||
case TK_ISNULL:
|
||||
case TK_NOTNULL:
|
||||
case TK_IS:
|
||||
@@ -5059,8 +5146,8 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
case TK_CASE:
|
||||
case TK_IN:
|
||||
case TK_FUNCTION:
|
||||
case TK_TRUTH:
|
||||
testcase( pExpr->op==TK_ISNOT );
|
||||
testcase( pExpr->op==TK_NOT );
|
||||
testcase( pExpr->op==TK_ISNULL );
|
||||
testcase( pExpr->op==TK_NOTNULL );
|
||||
testcase( pExpr->op==TK_IS );
|
||||
@@ -5068,6 +5155,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
testcase( pExpr->op==TK_CASE );
|
||||
testcase( pExpr->op==TK_IN );
|
||||
testcase( pExpr->op==TK_FUNCTION );
|
||||
testcase( pExpr->op==TK_TRUTH );
|
||||
return WRC_Prune;
|
||||
case TK_COLUMN:
|
||||
if( pWalker->u.iCur==pExpr->iTable ){
|
||||
@@ -5076,6 +5164,18 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
return WRC_Prune;
|
||||
|
||||
case TK_AND:
|
||||
if( sqlite3ExprImpliesNonNullRow(pExpr->pLeft, pWalker->u.iCur)
|
||||
&& sqlite3ExprImpliesNonNullRow(pExpr->pRight, pWalker->u.iCur)
|
||||
){
|
||||
pWalker->eCode = 1;
|
||||
}
|
||||
return WRC_Prune;
|
||||
|
||||
case TK_BETWEEN:
|
||||
sqlite3WalkExpr(pWalker, pExpr->pLeft);
|
||||
return WRC_Prune;
|
||||
|
||||
/* Virtual tables are allowed to use constraints like x=NULL. So
|
||||
** a term of the form x=y does not prove that y is not null if x
|
||||
** is the column of a virtual table */
|
||||
@@ -5096,6 +5196,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
){
|
||||
return WRC_Prune;
|
||||
}
|
||||
|
||||
default:
|
||||
return WRC_Continue;
|
||||
}
|
||||
@@ -5125,7 +5226,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
*/
|
||||
int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
|
||||
Walker w;
|
||||
p = sqlite3ExprSkipCollate(p);
|
||||
p = sqlite3ExprSkipCollateAndLikely(p);
|
||||
while( p ){
|
||||
if( p->op==TK_NOTNULL ){
|
||||
p = p->pLeft;
|
||||
@@ -5231,7 +5332,10 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
if( i<nSrc ){
|
||||
p->nThis++;
|
||||
}else{
|
||||
}else if( nSrc==0 || pExpr->iTable<pSrc->a[0].iCursor ){
|
||||
/* In a well-formed parse tree (no name resolution errors),
|
||||
** TK_COLUMN nodes with smaller Expr.iTable values are in an
|
||||
** outer context. Those are the only ones to count as "other" */
|
||||
p->nOther++;
|
||||
}
|
||||
}
|
||||
@@ -5248,8 +5352,9 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
|
||||
Walker w;
|
||||
struct SrcCount cnt;
|
||||
assert( pExpr->op==TK_AGG_FUNCTION );
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = exprSrcCount;
|
||||
w.xSelectCallback = 0;
|
||||
w.xSelectCallback = sqlite3SelectWalkNoop;
|
||||
w.u.pSrcCount = &cnt;
|
||||
cnt.pSrc = pSrcList;
|
||||
cnt.nThis = 0;
|
||||
@@ -5518,6 +5623,11 @@ void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
|
||||
|
||||
/*
|
||||
** Mark all temporary registers as being unavailable for reuse.
|
||||
**
|
||||
** Always invoke this procedure after coding a subroutine or co-routine
|
||||
** that might be invoked from other parts of the code, to ensure that
|
||||
** the sub/co-routine does not use registers in common with the code that
|
||||
** invokes the sub/co-routine.
|
||||
*/
|
||||
void sqlite3ClearTempRegCache(Parse *pParse){
|
||||
pParse->nTempReg = 0;
|
||||
|
||||
+4
-3
@@ -478,13 +478,13 @@ static Expr *exprTableRegister(
|
||||
if( iCol>=0 && iCol!=pTab->iPKey ){
|
||||
pCol = &pTab->aCol[iCol];
|
||||
pExpr->iTable = regBase + iCol + 1;
|
||||
pExpr->affinity = pCol->affinity;
|
||||
pExpr->affExpr = pCol->affinity;
|
||||
zColl = pCol->zColl;
|
||||
if( zColl==0 ) zColl = db->pDfltColl->zName;
|
||||
pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl);
|
||||
}else{
|
||||
pExpr->iTable = regBase;
|
||||
pExpr->affinity = SQLITE_AFF_INTEGER;
|
||||
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
||||
}
|
||||
}
|
||||
return pExpr;
|
||||
@@ -1287,7 +1287,7 @@ static Trigger *fkActionTrigger(
|
||||
tFrom.n = nFrom;
|
||||
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
|
||||
if( pRaise ){
|
||||
pRaise->affinity = OE_Abort;
|
||||
pRaise->affExpr = OE_Abort;
|
||||
}
|
||||
pSelect = sqlite3SelectNew(pParse,
|
||||
sqlite3ExprListAppend(pParse, 0, pRaise),
|
||||
@@ -1332,6 +1332,7 @@ static Trigger *fkActionTrigger(
|
||||
return 0;
|
||||
}
|
||||
assert( pStep!=0 );
|
||||
assert( pTrigger!=0 );
|
||||
|
||||
switch( action ){
|
||||
case OE_Restrict:
|
||||
|
||||
+21
-5
@@ -203,6 +203,8 @@ static void instrFunc(
|
||||
int N = 1;
|
||||
int isText;
|
||||
unsigned char firstChar;
|
||||
sqlite3_value *pC1 = 0;
|
||||
sqlite3_value *pC2 = 0;
|
||||
|
||||
UNUSED_PARAMETER(argc);
|
||||
typeHaystack = sqlite3_value_type(argv[0]);
|
||||
@@ -215,12 +217,22 @@ static void instrFunc(
|
||||
zHaystack = sqlite3_value_blob(argv[0]);
|
||||
zNeedle = sqlite3_value_blob(argv[1]);
|
||||
isText = 0;
|
||||
}else{
|
||||
}else if( typeHaystack!=SQLITE_BLOB && typeNeedle!=SQLITE_BLOB ){
|
||||
zHaystack = sqlite3_value_text(argv[0]);
|
||||
zNeedle = sqlite3_value_text(argv[1]);
|
||||
isText = 1;
|
||||
}else{
|
||||
pC1 = sqlite3_value_dup(argv[0]);
|
||||
zHaystack = sqlite3_value_text(pC1);
|
||||
if( zHaystack==0 ) goto endInstrOOM;
|
||||
nHaystack = sqlite3_value_bytes(pC1);
|
||||
pC2 = sqlite3_value_dup(argv[1]);
|
||||
zNeedle = sqlite3_value_text(pC2);
|
||||
if( zNeedle==0 ) goto endInstrOOM;
|
||||
nNeedle = sqlite3_value_bytes(pC2);
|
||||
isText = 1;
|
||||
}
|
||||
if( zNeedle==0 || (nHaystack && zHaystack==0) ) return;
|
||||
if( zNeedle==0 || (nHaystack && zHaystack==0) ) goto endInstrOOM;
|
||||
firstChar = zNeedle[0];
|
||||
while( nNeedle<=nHaystack
|
||||
&& (zHaystack[0]!=firstChar || memcmp(zHaystack, zNeedle, nNeedle)!=0)
|
||||
@@ -234,6 +246,13 @@ static void instrFunc(
|
||||
if( nNeedle>nHaystack ) N = 0;
|
||||
}
|
||||
sqlite3_result_int(context, N);
|
||||
endInstr:
|
||||
sqlite3_value_free(pC1);
|
||||
sqlite3_value_free(pC2);
|
||||
return;
|
||||
endInstrOOM:
|
||||
sqlite3_result_error_nomem(context);
|
||||
goto endInstr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1986,9 +2005,6 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
sqlite3AlterFunctions();
|
||||
#endif
|
||||
sqlite3WindowFunctions();
|
||||
#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
|
||||
sqlite3AnalyzeFunctions();
|
||||
#endif
|
||||
sqlite3RegisterDateTimeFunctions();
|
||||
sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
|
||||
|
||||
|
||||
+2
-8
@@ -214,6 +214,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
SQLITE_USE_URI, /* bOpenUri */
|
||||
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
|
||||
0, /* bSmallMalloc */
|
||||
1, /* bExtraSchemaChecks */
|
||||
0x7ffffffe, /* mxStrlen */
|
||||
0, /* neverCorrupt */
|
||||
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
|
||||
@@ -260,6 +261,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
0, /* bInternalFunctions */
|
||||
0x7ffffffe, /* iOnceResetThreshold */
|
||||
SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
|
||||
0, /* iPrngSeed */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -269,14 +271,6 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
*/
|
||||
FuncDefHash sqlite3BuiltinFunctions;
|
||||
|
||||
/*
|
||||
** Constant tokens for values 0 and 1.
|
||||
*/
|
||||
const Token sqlite3IntTokens[] = {
|
||||
{ "0", 1 },
|
||||
{ "1", 1 }
|
||||
};
|
||||
|
||||
#ifdef VDBE_PROFILE
|
||||
/*
|
||||
** The following performance counter can be used in place of
|
||||
|
||||
+11
-6
@@ -88,18 +88,19 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
|
||||
}
|
||||
for(n=0; n<pIdx->nColumn; n++){
|
||||
i16 x = pIdx->aiColumn[n];
|
||||
char aff;
|
||||
if( x>=0 ){
|
||||
pIdx->zColAff[n] = pTab->aCol[x].affinity;
|
||||
aff = pTab->aCol[x].affinity;
|
||||
}else if( x==XN_ROWID ){
|
||||
pIdx->zColAff[n] = SQLITE_AFF_INTEGER;
|
||||
aff = SQLITE_AFF_INTEGER;
|
||||
}else{
|
||||
char aff;
|
||||
assert( x==XN_EXPR );
|
||||
assert( pIdx->aColExpr!=0 );
|
||||
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
|
||||
if( aff==0 ) aff = SQLITE_AFF_BLOB;
|
||||
pIdx->zColAff[n] = aff;
|
||||
}
|
||||
if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
|
||||
if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
|
||||
pIdx->zColAff[n] = aff;
|
||||
}
|
||||
pIdx->zColAff[n] = 0;
|
||||
}
|
||||
@@ -139,11 +140,12 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
||||
}
|
||||
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
assert( pTab->aCol[i].affinity!=0 );
|
||||
zColAff[i] = pTab->aCol[i].affinity;
|
||||
}
|
||||
do{
|
||||
zColAff[i--] = 0;
|
||||
}while( i>=0 && zColAff[i]==SQLITE_AFF_BLOB );
|
||||
}while( i>=0 && zColAff[i]<=SQLITE_AFF_BLOB );
|
||||
pTab->zColAff = zColAff;
|
||||
}
|
||||
assert( zColAff!=0 );
|
||||
@@ -832,6 +834,9 @@ void sqlite3Insert(
|
||||
pTab->zName);
|
||||
goto insert_cleanup;
|
||||
}
|
||||
if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
pTabList->a[0].iCursor = iDataCur;
|
||||
pUpsert->pUpsertSrc = pTabList;
|
||||
pUpsert->regData = regData;
|
||||
|
||||
+7
-1
@@ -461,7 +461,13 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
#endif
|
||||
/* Version 3.28.0 and later */
|
||||
sqlite3_stmt_isexplain,
|
||||
sqlite3_value_frombind
|
||||
sqlite3_value_frombind,
|
||||
/* Version 3.30.0 and later */
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
sqlite3_drop_modules,
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+43
-10
@@ -836,6 +836,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
|
||||
} aFlagOp[] = {
|
||||
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
|
||||
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
|
||||
{ SQLITE_DBCONFIG_ENABLE_VIEW, SQLITE_EnableView },
|
||||
{ SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
|
||||
{ SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
|
||||
{ SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose },
|
||||
@@ -1235,11 +1236,8 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){
|
||||
Module *pMod = (Module *)sqliteHashData(i);
|
||||
if( pMod->xDestroy ){
|
||||
pMod->xDestroy(pMod->pAux);
|
||||
}
|
||||
sqlite3VtabEponymousTableClear(db, pMod);
|
||||
sqlite3DbFree(db, pMod);
|
||||
sqlite3VtabModuleUnref(db, pMod);
|
||||
}
|
||||
sqlite3HashClear(&db->aModule);
|
||||
#endif
|
||||
@@ -1720,7 +1718,8 @@ int sqlite3CreateFunc(
|
||||
}
|
||||
|
||||
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
|
||||
extraFlags = enc & SQLITE_DETERMINISTIC;
|
||||
assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
|
||||
extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|SQLITE_SUBTYPE);
|
||||
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
@@ -1783,6 +1782,7 @@ int sqlite3CreateFunc(
|
||||
p->u.pDestructor = pDestructor;
|
||||
p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
|
||||
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
|
||||
testcase( p->funcFlags & SQLITE_DIRECTONLY );
|
||||
p->xSFunc = xSFunc ? xSFunc : xStep;
|
||||
p->xFinalize = xFinal;
|
||||
p->xValue = xValue;
|
||||
@@ -3075,6 +3075,7 @@ static int openDatabase(
|
||||
db->nMaxSorterMmap = 0x7FFFFFFF;
|
||||
db->flags |= SQLITE_ShortColNames
|
||||
| SQLITE_EnableTrigger
|
||||
| SQLITE_EnableView
|
||||
| SQLITE_CacheSpill
|
||||
|
||||
/* The SQLITE_DQS compile-time option determines the default settings
|
||||
@@ -3824,12 +3825,33 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Reset the PRNG back to its uninitialized state. The next call
|
||||
** to sqlite3_randomness() will reseed the PRNG using a single call
|
||||
** to the xRandomness method of the default VFS.
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, int x, sqlite3 *db);
|
||||
**
|
||||
** Control the seed for the pseudo-random number generator (PRNG) that
|
||||
** is built into SQLite. Cases:
|
||||
**
|
||||
** x!=0 && db!=0 Seed the PRNG to the current value of the
|
||||
** schema cookie in the main database for db, or
|
||||
** x if the schema cookie is zero. This case
|
||||
** is convenient to use with database fuzzers
|
||||
** as it allows the fuzzer some control over the
|
||||
** the PRNG seed.
|
||||
**
|
||||
** x!=0 && db==0 Seed the PRNG to the value of x.
|
||||
**
|
||||
** x==0 && db==0 Revert to default behavior of using the
|
||||
** xRandomness method on the primary VFS.
|
||||
**
|
||||
** This test-control also resets the PRNG so that the new seed will
|
||||
** be used for the next call to sqlite3_randomness().
|
||||
*/
|
||||
case SQLITE_TESTCTRL_PRNG_RESET: {
|
||||
case SQLITE_TESTCTRL_PRNG_SEED: {
|
||||
int x = va_arg(ap, int);
|
||||
int y;
|
||||
sqlite3 *db = va_arg(ap, sqlite3*);
|
||||
assert( db==0 || db->aDb[0].pSchema!=0 );
|
||||
if( db && (y = db->aDb[0].pSchema->schema_cookie)!=0 ){ x = y; }
|
||||
sqlite3Config.iPrngSeed = x;
|
||||
sqlite3_randomness(0,0);
|
||||
break;
|
||||
}
|
||||
@@ -4042,6 +4064,17 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int);
|
||||
**
|
||||
** Set or clear a flag that causes SQLite to verify that type, name,
|
||||
** and tbl_name fields of the sqlite_master table. This is normally
|
||||
** on, but it is sometimes useful to turn it off for testing.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
|
||||
sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the threshold at which OP_Once counters reset back to zero.
|
||||
** By default this is 0x7ffffffe (over 2 billion), but that value is
|
||||
** too big to test in a reasonable amount of time, so this control is
|
||||
|
||||
@@ -96,14 +96,9 @@ static int memjrnlRead(
|
||||
int iChunkOffset;
|
||||
FileChunk *pChunk;
|
||||
|
||||
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|
||||
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
if( (iAmt+iOfst)>p->endpoint.iOffset ){
|
||||
return SQLITE_IOERR_SHORT_READ;
|
||||
}
|
||||
#endif
|
||||
|
||||
assert( (iAmt+iOfst)<=p->endpoint.iOffset );
|
||||
assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
|
||||
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
|
||||
sqlite3_int64 iOff = 0;
|
||||
|
||||
@@ -67,4 +67,5 @@
|
||||
#define MUTEX_LOGIC(X)
|
||||
#else
|
||||
#define MUTEX_LOGIC(X) X
|
||||
int sqlite3_mutex_held(sqlite3_mutex*);
|
||||
#endif /* defined(SQLITE_MUTEX_OMIT) */
|
||||
|
||||
@@ -258,7 +258,15 @@ void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
}
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
return pVfs->xRandomness(pVfs, nByte, zBufOut);
|
||||
if( sqlite3Config.iPrngSeed ){
|
||||
memset(zBufOut, 0, nByte);
|
||||
if( ALWAYS(nByte>(signed)sizeof(unsigned)) ) nByte = sizeof(unsigned int);
|
||||
memcpy(zBufOut, &sqlite3Config.iPrngSeed, nByte);
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
return pVfs->xRandomness(pVfs, nByte, zBufOut);
|
||||
}
|
||||
|
||||
}
|
||||
int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
return pVfs->xSleep(pVfs, nMicro);
|
||||
|
||||
+44
-17
@@ -105,13 +105,29 @@
|
||||
# include <sys/param.h>
|
||||
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
|
||||
|
||||
#if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
|
||||
(__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
|
||||
# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \
|
||||
&& (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))
|
||||
# define HAVE_GETHOSTUUID 1
|
||||
# else
|
||||
# warning "gethostuuid() is disabled."
|
||||
/*
|
||||
** Try to determine if gethostuuid() is available based on standard
|
||||
** macros. This might sometimes compute the wrong value for some
|
||||
** obscure platforms. For those cases, simply compile with one of
|
||||
** the following:
|
||||
**
|
||||
** -DHAVE_GETHOSTUUID=0
|
||||
** -DHAVE_GETHOSTUUID=1
|
||||
**
|
||||
** None if this matters except when building on Apple products with
|
||||
** -DSQLITE_ENABLE_LOCKING_STYLE.
|
||||
*/
|
||||
#ifndef HAVE_GETHOSTUUID
|
||||
# define HAVE_GETHOSTUUID 0
|
||||
# if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
|
||||
(__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
|
||||
# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \
|
||||
&& (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))
|
||||
# undef HAVE_GETHOSTUUID
|
||||
# define HAVE_GETHOSTUUID 1
|
||||
# else
|
||||
# warning "gethostuuid() is disabled."
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -521,13 +537,14 @@ static struct unix_syscall {
|
||||
#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
# ifdef __ANDROID__
|
||||
{ "ioctl", (sqlite3_syscall_ptr)(int(*)(int, int, ...))ioctl, 0 },
|
||||
#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent)
|
||||
# else
|
||||
{ "ioctl", (sqlite3_syscall_ptr)ioctl, 0 },
|
||||
#define osIoctl ((int(*)(int,unsigned long,...))aSyscall[28].pCurrent)
|
||||
# endif
|
||||
#else
|
||||
{ "ioctl", (sqlite3_syscall_ptr)0, 0 },
|
||||
#endif
|
||||
#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent)
|
||||
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
@@ -5769,6 +5786,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
|
||||
UnixUnusedFd **pp;
|
||||
assert( sqlite3_mutex_notheld(pInode->pLockMutex) );
|
||||
sqlite3_mutex_enter(pInode->pLockMutex);
|
||||
flags &= (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE);
|
||||
for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
|
||||
pUnused = *pp;
|
||||
if( pUnused ){
|
||||
@@ -5822,7 +5840,7 @@ static int getFileMode(
|
||||
** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
|
||||
** original filename is unavailable. But 8_3_NAMES is only used for
|
||||
** FAT filesystems and permissions do not matter there, so just use
|
||||
** the default permissions.
|
||||
** the default permissions. In 8_3_NAMES mode, leave *pMode set to zero.
|
||||
*/
|
||||
static int findCreateFileMode(
|
||||
const char *zPath, /* Path of file (possibly) being created */
|
||||
@@ -6057,11 +6075,19 @@ static int unixOpen(
|
||||
goto open_finished;
|
||||
}
|
||||
|
||||
/* If this process is running as root and if creating a new rollback
|
||||
** journal or WAL file, set the ownership of the journal or WAL to be
|
||||
** the same as the original database.
|
||||
/* The owner of the rollback journal or WAL file should always be the
|
||||
** same as the owner of the database file. Try to ensure that this is
|
||||
** the case. The chown() system call will be a no-op if the current
|
||||
** process lacks root privileges, be we should at least try. Without
|
||||
** this step, if a root process opens a database file, it can leave
|
||||
** behinds a journal/WAL that is owned by root and hence make the
|
||||
** database inaccessible to unprivileged processes.
|
||||
**
|
||||
** If openMode==0, then that means uid and gid are not set correctly
|
||||
** (probably because SQLite is configured to use 8+3 filename mode) and
|
||||
** in that case we do not want to attempt the chown().
|
||||
*/
|
||||
if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
|
||||
if( openMode && (flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL))!=0 ){
|
||||
robustFchown(fd, uid, gid);
|
||||
}
|
||||
}
|
||||
@@ -6072,7 +6098,8 @@ static int unixOpen(
|
||||
|
||||
if( p->pPreallocatedUnused ){
|
||||
p->pPreallocatedUnused->fd = fd;
|
||||
p->pPreallocatedUnused->flags = flags;
|
||||
p->pPreallocatedUnused->flags =
|
||||
flags & (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE);
|
||||
}
|
||||
|
||||
if( isDelete ){
|
||||
@@ -6918,7 +6945,7 @@ int sqlite3_hostid_num = 0;
|
||||
|
||||
#define PROXY_HOSTIDLEN 16 /* conch file host id length */
|
||||
|
||||
#ifdef HAVE_GETHOSTUUID
|
||||
#if HAVE_GETHOSTUUID
|
||||
/* Not always defined in the headers as it ought to be */
|
||||
extern int gethostuuid(uuid_t id, const struct timespec *wait);
|
||||
#endif
|
||||
@@ -6929,7 +6956,7 @@ extern int gethostuuid(uuid_t id, const struct timespec *wait);
|
||||
static int proxyGetHostID(unsigned char *pHostID, int *pError){
|
||||
assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
|
||||
memset(pHostID, 0, PROXY_HOSTIDLEN);
|
||||
#ifdef HAVE_GETHOSTUUID
|
||||
#if HAVE_GETHOSTUUID
|
||||
{
|
||||
struct timespec timeout = {1, 0}; /* 1 sec timeout */
|
||||
if( gethostuuid(pHostID, &timeout) ){
|
||||
@@ -7603,7 +7630,7 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
assert( 0 ); /* The call assures that only valid opcodes are sent */
|
||||
}
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
/*NOTREACHED*/ assert(0);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -4215,6 +4215,7 @@ static int winShmMap(
|
||||
rc = winOpenSharedMemory(pDbFd);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
pShm = pDbFd->pShm;
|
||||
assert( pShm!=0 );
|
||||
}
|
||||
pShmNode = pShm->pShmNode;
|
||||
|
||||
@@ -4517,6 +4518,7 @@ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
|
||||
}
|
||||
}
|
||||
if( pFd->mmapSize >= iOff+nAmt ){
|
||||
assert( pFd->pMapRegion!=0 );
|
||||
*pp = &((u8 *)pFd->pMapRegion)[iOff];
|
||||
pFd->nFetchOut++;
|
||||
}
|
||||
|
||||
+50
-54
@@ -211,6 +211,7 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN
|
||||
QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW ROWS
|
||||
ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
|
||||
NULLS FIRST LAST
|
||||
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
EXCEPT INTERSECT UNION
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
@@ -458,6 +459,7 @@ cmd ::= select(X). {
|
||||
** SQLITE_LIMIT_COMPOUND_SELECT.
|
||||
*/
|
||||
static void parserDoubleLinkSelect(Parse *pParse, Select *p){
|
||||
assert( p!=0 );
|
||||
if( p->pPrior ){
|
||||
Select *pNext = 0, *pLoop;
|
||||
int mxSelect, cnt = 0;
|
||||
@@ -780,13 +782,13 @@ using_opt(U) ::= . {U = 0;}
|
||||
|
||||
orderby_opt(A) ::= . {A = 0;}
|
||||
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
|
||||
sortlist(A) ::= sortlist(A) COMMA expr(Y) sortorder(Z). {
|
||||
sortlist(A) ::= sortlist(A) COMMA expr(Y) sortorder(Z) nulls(X). {
|
||||
A = sqlite3ExprListAppend(pParse,A,Y);
|
||||
sqlite3ExprListSetSortOrder(A,Z);
|
||||
sqlite3ExprListSetSortOrder(A,Z,X);
|
||||
}
|
||||
sortlist(A) ::= expr(Y) sortorder(Z). {
|
||||
sortlist(A) ::= expr(Y) sortorder(Z) nulls(X). {
|
||||
A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/
|
||||
sqlite3ExprListSetSortOrder(A,Z);
|
||||
sqlite3ExprListSetSortOrder(A,Z,X);
|
||||
}
|
||||
|
||||
%type sortorder {int}
|
||||
@@ -795,6 +797,11 @@ sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;}
|
||||
sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;}
|
||||
sortorder(A) ::= . {A = SQLITE_SO_UNDEFINED;}
|
||||
|
||||
%type nulls {int}
|
||||
nulls(A) ::= NULLS FIRST. {A = SQLITE_SO_ASC;}
|
||||
nulls(A) ::= NULLS LAST. {A = SQLITE_SO_DESC;}
|
||||
nulls(A) ::= . {A = SQLITE_SO_UNDEFINED;}
|
||||
|
||||
%type groupby_opt {ExprList*}
|
||||
%destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);}
|
||||
groupby_opt(A) ::= . {A = 0;}
|
||||
@@ -948,7 +955,7 @@ idlist(A) ::= nm(Y).
|
||||
if( p ){
|
||||
/* memset(p, 0, sizeof(Expr)); */
|
||||
p->op = (u8)op;
|
||||
p->affinity = 0;
|
||||
p->affExpr = 0;
|
||||
p->flags = EP_Leaf;
|
||||
p->iAgg = -1;
|
||||
p->pLeft = p->pRight = 0;
|
||||
@@ -1044,11 +1051,11 @@ expr(A) ::= id(X) LP STAR RP. {
|
||||
}
|
||||
|
||||
%ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP over_clause(Z). {
|
||||
expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP filter_over(Z). {
|
||||
A = sqlite3ExprFunction(pParse, Y, &X, D);
|
||||
sqlite3WindowAttach(pParse, A, Z);
|
||||
}
|
||||
expr(A) ::= id(X) LP STAR RP over_clause(Z). {
|
||||
expr(A) ::= id(X) LP STAR RP filter_over(Z). {
|
||||
A = sqlite3ExprFunction(pParse, 0, &X, 0);
|
||||
sqlite3WindowAttach(pParse, A, Z);
|
||||
}
|
||||
@@ -1174,34 +1181,7 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
** regardless of the value of expr1.
|
||||
*/
|
||||
sqlite3ExprUnmapAndDelete(pParse, A);
|
||||
A = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[N],1);
|
||||
}else if( Y->nExpr==1 ){
|
||||
/* Expressions of the form:
|
||||
**
|
||||
** expr1 IN (?1)
|
||||
** expr1 NOT IN (?2)
|
||||
**
|
||||
** with exactly one value on the RHS can be simplified to something
|
||||
** like this:
|
||||
**
|
||||
** expr1 == ?1
|
||||
** expr1 <> ?2
|
||||
**
|
||||
** But, the RHS of the == or <> is marked with the EP_Generic flag
|
||||
** so that it may not contribute to the computation of comparison
|
||||
** affinity or the collating sequence to use for comparison. Otherwise,
|
||||
** the semantics would be subtly different from IN or NOT IN.
|
||||
*/
|
||||
Expr *pRHS = Y->a[0].pExpr;
|
||||
Y->a[0].pExpr = 0;
|
||||
sqlite3ExprListDelete(pParse->db, Y);
|
||||
/* pRHS cannot be NULL because a malloc error would have been detected
|
||||
** before now and control would have never reached this point */
|
||||
if( ALWAYS(pRHS) ){
|
||||
pRHS->flags &= ~EP_Collate;
|
||||
pRHS->flags |= EP_Generic;
|
||||
}
|
||||
A = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, A, pRHS);
|
||||
A = sqlite3Expr(pParse->db, TK_INTEGER, N ? "1" : "0");
|
||||
}else{
|
||||
A = sqlite3PExpr(pParse, TK_IN, A, 0);
|
||||
if( A ){
|
||||
@@ -1507,13 +1487,13 @@ trigger_cmd(A) ::= scanpt(B) select(X) scanpt(E).
|
||||
expr(A) ::= RAISE LP IGNORE RP. {
|
||||
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
|
||||
if( A ){
|
||||
A->affinity = OE_Ignore;
|
||||
A->affExpr = OE_Ignore;
|
||||
}
|
||||
}
|
||||
expr(A) ::= RAISE LP raisetype(T) COMMA nm(Z) RP. {
|
||||
A = sqlite3ExprAlloc(pParse->db, TK_RAISE, &Z, 1);
|
||||
if( A ) {
|
||||
A->affinity = (char)T;
|
||||
A->affExpr = (char)T;
|
||||
}
|
||||
}
|
||||
%endif !SQLITE_OMIT_TRIGGER
|
||||
@@ -1657,8 +1637,14 @@ windowdefn(A) ::= nm(X) AS LP window(Y) RP. {
|
||||
%type part_opt {ExprList*}
|
||||
%destructor part_opt {sqlite3ExprListDelete(pParse->db, $$);}
|
||||
|
||||
%type filter_opt {Expr*}
|
||||
%destructor filter_opt {sqlite3ExprDelete(pParse->db, $$);}
|
||||
%type filter_clause {Expr*}
|
||||
%destructor filter_clause {sqlite3ExprDelete(pParse->db, $$);}
|
||||
|
||||
%type over_clause {Window*}
|
||||
%destructor over_clause {sqlite3WindowDelete(pParse->db, $$);}
|
||||
|
||||
%type filter_over {Window*}
|
||||
%destructor filter_over {sqlite3WindowDelete(pParse->db, $$);}
|
||||
|
||||
%type range_or_rows {int}
|
||||
|
||||
@@ -1724,25 +1710,35 @@ frame_exclude(A) ::= GROUP|TIES(X). {A = @X; /*A-overwrites-X*/}
|
||||
%destructor window_clause {sqlite3WindowListDelete(pParse->db, $$);}
|
||||
window_clause(A) ::= WINDOW windowdefn_list(B). { A = B; }
|
||||
|
||||
%type over_clause {Window*}
|
||||
%destructor over_clause {sqlite3WindowDelete(pParse->db, $$);}
|
||||
over_clause(A) ::= filter_opt(W) OVER LP window(Z) RP. {
|
||||
A = Z;
|
||||
assert( A!=0 );
|
||||
A->pFilter = W;
|
||||
filter_over(A) ::= filter_clause(F) over_clause(O). {
|
||||
O->pFilter = F;
|
||||
A = O;
|
||||
}
|
||||
over_clause(A) ::= filter_opt(W) OVER nm(Z). {
|
||||
filter_over(A) ::= over_clause(O). {
|
||||
A = O;
|
||||
}
|
||||
filter_over(A) ::= filter_clause(F). {
|
||||
A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
||||
if( A ){
|
||||
A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n);
|
||||
A->pFilter = W;
|
||||
A->eFrmType = TK_FILTER;
|
||||
A->pFilter = F;
|
||||
}else{
|
||||
sqlite3ExprDelete(pParse->db, W);
|
||||
sqlite3ExprDelete(pParse->db, F);
|
||||
}
|
||||
}
|
||||
|
||||
filter_opt(A) ::= . { A = 0; }
|
||||
filter_opt(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
|
||||
over_clause(A) ::= OVER LP window(Z) RP. {
|
||||
A = Z;
|
||||
assert( A!=0 );
|
||||
}
|
||||
over_clause(A) ::= OVER nm(Z). {
|
||||
A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
||||
if( A ){
|
||||
A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n);
|
||||
}
|
||||
}
|
||||
|
||||
filter_clause(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
|
||||
%endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
/*
|
||||
@@ -1750,12 +1746,12 @@ filter_opt(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
|
||||
** are synthesized and do not actually appear in the grammar:
|
||||
*/
|
||||
%token
|
||||
TRUEFALSE /* True or false keyword */
|
||||
ISNOT /* Combination of IS and NOT */
|
||||
FUNCTION /* A function invocation */
|
||||
COLUMN /* Reference to a table column */
|
||||
AGG_FUNCTION /* An aggregate function */
|
||||
AGG_COLUMN /* An aggregated column */
|
||||
TRUEFALSE /* True or false keyword */
|
||||
ISNOT /* Combination of IS and NOT */
|
||||
FUNCTION /* A function invocation */
|
||||
UMINUS /* Unary minus */
|
||||
UPLUS /* Unary plus */
|
||||
TRUTH /* IS TRUE or IS FALSE or IS NOT TRUE or IS NOT FALSE */
|
||||
|
||||
@@ -262,6 +262,7 @@ int sqlite3PcacheInitialize(void){
|
||||
** built-in default page cache is used instead of the application defined
|
||||
** page cache. */
|
||||
sqlite3PCacheSetDefault();
|
||||
assert( sqlite3GlobalConfig.pcache2.xInit!=0 );
|
||||
}
|
||||
return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg);
|
||||
}
|
||||
|
||||
@@ -424,6 +424,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
|
||||
|
||||
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
|
||||
if( pCache->pFree || (pCache->nPage==0 && pcache1InitBulk(pCache)) ){
|
||||
assert( pCache->pFree!=0 );
|
||||
p = pCache->pFree;
|
||||
pCache->pFree = p->pNext;
|
||||
p->pNext = 0;
|
||||
|
||||
+10
-1
@@ -1157,6 +1157,15 @@ void sqlite3Pragma(
|
||||
Index *pIdx;
|
||||
Table *pTab;
|
||||
pIdx = sqlite3FindIndex(db, zRight, zDb);
|
||||
if( pIdx==0 ){
|
||||
/* If there is no index named zRight, check to see if there is a
|
||||
** WITHOUT ROWID table named zRight, and if there is, show the
|
||||
** structure of the PRIMARY KEY index for that table. */
|
||||
pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
|
||||
if( pTab && !HasRowid(pTab) ){
|
||||
pIdx = sqlite3PrimaryKeyIndex(pTab);
|
||||
}
|
||||
}
|
||||
if( pIdx ){
|
||||
int iIdxDb = sqlite3SchemaToIndex(db, pIdx->pSchema);
|
||||
int i;
|
||||
@@ -1236,7 +1245,7 @@ void sqlite3Pragma(
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef SQLITE_INTROSPECTION_PRAGMAS
|
||||
#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
|
||||
case PragTyp_FUNCTION_LIST: {
|
||||
int i;
|
||||
HashElem *j;
|
||||
|
||||
+4
-4
@@ -311,7 +311,7 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ SQLITE_FullFSync },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
#if defined(SQLITE_INTROSPECTION_PRAGMAS)
|
||||
#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
|
||||
{/* zName: */ "function_list",
|
||||
/* ePragTyp: */ PragTyp_FUNCTION_LIST,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
@@ -435,7 +435,7 @@ static const PragmaName aPragmaName[] = {
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
#if defined(SQLITE_INTROSPECTION_PRAGMAS)
|
||||
#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
|
||||
{/* zName: */ "module_list",
|
||||
/* ePragTyp: */ PragTyp_MODULE_LIST,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
@@ -470,7 +470,7 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ SQLITE_ParserTrace },
|
||||
#endif
|
||||
#endif
|
||||
#if defined(SQLITE_INTROSPECTION_PRAGMAS)
|
||||
#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
|
||||
{/* zName: */ "pragma_list",
|
||||
/* ePragTyp: */ PragTyp_PRAGMA_LIST,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
@@ -668,4 +668,4 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
|
||||
#endif
|
||||
};
|
||||
/* Number of pragmas: 62 on by default, 81 total. */
|
||||
/* Number of pragmas: 65 on by default, 81 total. */
|
||||
|
||||
+35
-27
@@ -64,9 +64,11 @@ int sqlite3IndexHasDuplicateRootPage(Index *pIndex){
|
||||
**
|
||||
** Each callback contains the following information:
|
||||
**
|
||||
** argv[0] = name of thing being created
|
||||
** argv[1] = root page number for table or index. 0 for trigger or view.
|
||||
** argv[2] = SQL text for the CREATE statement.
|
||||
** argv[0] = type of object: "table", "index", "trigger", or "view".
|
||||
** argv[1] = name of thing being created
|
||||
** argv[2] = associated table if an index or trigger
|
||||
** argv[3] = root page number for table or index. 0 for trigger or view.
|
||||
** argv[4] = SQL text for the CREATE statement.
|
||||
**
|
||||
*/
|
||||
int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
@@ -74,21 +76,21 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
sqlite3 *db = pData->db;
|
||||
int iDb = pData->iDb;
|
||||
|
||||
assert( argc==3 );
|
||||
assert( argc==5 );
|
||||
UNUSED_PARAMETER2(NotUsed, argc);
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
DbClearProperty(db, iDb, DB_Empty);
|
||||
pData->nInitRow++;
|
||||
if( db->mallocFailed ){
|
||||
corruptSchema(pData, argv[0], 0);
|
||||
corruptSchema(pData, argv[1], 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
|
||||
if( argv[1]==0 ){
|
||||
corruptSchema(pData, argv[0], 0);
|
||||
}else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){
|
||||
if( argv[3]==0 ){
|
||||
corruptSchema(pData, argv[1], 0);
|
||||
}else if( sqlite3_strnicmp(argv[4],"create ",7)==0 ){
|
||||
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
|
||||
** But because db->init.busy is set to 1, no VDBE code is generated
|
||||
** or executed. All the parser does is build the internal data
|
||||
@@ -101,9 +103,10 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
|
||||
assert( db->init.busy );
|
||||
db->init.iDb = iDb;
|
||||
db->init.newTnum = sqlite3Atoi(argv[1]);
|
||||
db->init.newTnum = sqlite3Atoi(argv[3]);
|
||||
db->init.orphanTrigger = 0;
|
||||
TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
|
||||
db->init.azInit = argv;
|
||||
TESTONLY(rcp = ) sqlite3_prepare(db, argv[4], -1, &pStmt, 0);
|
||||
rc = db->errCode;
|
||||
assert( (rc&0xFF)==(rcp&0xFF) );
|
||||
db->init.iDb = saved_iDb;
|
||||
@@ -112,17 +115,17 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
if( db->init.orphanTrigger ){
|
||||
assert( iDb==1 );
|
||||
}else{
|
||||
pData->rc = rc;
|
||||
if( rc > pData->rc ) pData->rc = rc;
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
sqlite3OomFault(db);
|
||||
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
|
||||
corruptSchema(pData, argv[0], sqlite3_errmsg(db));
|
||||
corruptSchema(pData, argv[1], sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){
|
||||
corruptSchema(pData, argv[0], 0);
|
||||
}else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
|
||||
corruptSchema(pData, argv[1], 0);
|
||||
}else{
|
||||
/* If the SQL column is blank it means this is an index that
|
||||
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
|
||||
@@ -131,13 +134,13 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
** to do here is record the root page number for that index.
|
||||
*/
|
||||
Index *pIndex;
|
||||
pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName);
|
||||
pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
|
||||
if( pIndex==0
|
||||
|| sqlite3GetInt32(argv[1],&pIndex->tnum)==0
|
||||
|| sqlite3GetInt32(argv[3],&pIndex->tnum)==0
|
||||
|| pIndex->tnum<2
|
||||
|| sqlite3IndexHasDuplicateRootPage(pIndex)
|
||||
){
|
||||
corruptSchema(pData, argv[0], pIndex?"invalid rootpage":"orphan index");
|
||||
corruptSchema(pData, argv[1], pIndex?"invalid rootpage":"orphan index");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -158,7 +161,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
int size;
|
||||
#endif
|
||||
Db *pDb;
|
||||
char const *azArg[4];
|
||||
char const *azArg[6];
|
||||
int meta[5];
|
||||
InitData initData;
|
||||
const char *zMasterName;
|
||||
@@ -177,18 +180,20 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
** table name will be inserted automatically by the parser so we can just
|
||||
** use the abbreviation "x" here. The parser will also automatically tag
|
||||
** the schema table as read-only. */
|
||||
azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
|
||||
azArg[1] = "1";
|
||||
azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
|
||||
azArg[0] = "table";
|
||||
azArg[1] = zMasterName = SCHEMA_TABLE(iDb);
|
||||
azArg[2] = azArg[1];
|
||||
azArg[3] = "1";
|
||||
azArg[4] = "CREATE TABLE x(type text,name text,tbl_name text,"
|
||||
"rootpage int,sql text)";
|
||||
azArg[3] = 0;
|
||||
azArg[5] = 0;
|
||||
initData.db = db;
|
||||
initData.iDb = iDb;
|
||||
initData.rc = SQLITE_OK;
|
||||
initData.pzErrMsg = pzErrMsg;
|
||||
initData.mInitFlags = mFlags;
|
||||
initData.nInitRow = 0;
|
||||
sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
|
||||
sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
|
||||
if( initData.rc ){
|
||||
rc = initData.rc;
|
||||
goto error_out;
|
||||
@@ -314,7 +319,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
{
|
||||
char *zSql;
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid",
|
||||
"SELECT*FROM\"%w\".%s ORDER BY rowid",
|
||||
db->aDb[iDb].zDbSName, zMasterName);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
@@ -635,7 +640,10 @@ static int sqlite3Prepare(
|
||||
rc = sParse.rc;
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
|
||||
/* Justification for the ALWAYS(): The only way for rc to be SQLITE_OK and
|
||||
** sParse.pVdbe to be NULL is if the input SQL is an empty string, but in
|
||||
** that case, sParse.explain will be false. */
|
||||
if( sParse.explain && rc==SQLITE_OK && ALWAYS(sParse.pVdbe) ){
|
||||
static const char * const azColName[] = {
|
||||
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
|
||||
"id", "parent", "notused", "detail"
|
||||
@@ -660,8 +668,8 @@ static int sqlite3Prepare(
|
||||
if( db->init.busy==0 ){
|
||||
sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags);
|
||||
}
|
||||
if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
|
||||
sqlite3VdbeFinalize(sParse.pVdbe);
|
||||
if( rc!=SQLITE_OK || db->mallocFailed ){
|
||||
if( sParse.pVdbe ) sqlite3VdbeFinalize(sParse.pVdbe);
|
||||
assert(!(*ppStmt));
|
||||
}else{
|
||||
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
|
||||
|
||||
+74
-43
@@ -96,6 +96,13 @@ static void resolveAlias(
|
||||
pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
|
||||
pExpr->flags |= EP_MemToken;
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
if( pExpr->y.pWin!=0 ){
|
||||
pExpr->y.pWin->pOwner = pExpr;
|
||||
}else{
|
||||
assert( db->mallocFailed );
|
||||
}
|
||||
}
|
||||
sqlite3DbFree(db, pDup);
|
||||
}
|
||||
ExprSetProperty(pExpr, EP_Alias);
|
||||
@@ -381,7 +388,7 @@ static int lookupName(
|
||||
{
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( iCol<0 ){
|
||||
pExpr->affinity = SQLITE_AFF_INTEGER;
|
||||
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
||||
}else if( pExpr->iTable==0 ){
|
||||
testcase( iCol==31 );
|
||||
testcase( iCol==32 );
|
||||
@@ -413,7 +420,7 @@ static int lookupName(
|
||||
){
|
||||
cnt = 1;
|
||||
pExpr->iColumn = -1;
|
||||
pExpr->affinity = SQLITE_AFF_INTEGER;
|
||||
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -689,7 +696,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
pExpr->y.pTab = pItem->pTab;
|
||||
pExpr->iTable = pItem->iCursor;
|
||||
pExpr->iColumn = -1;
|
||||
pExpr->affinity = SQLITE_AFF_INTEGER;
|
||||
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
||||
break;
|
||||
}
|
||||
#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
|
||||
@@ -749,7 +756,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
FuncDef *pDef; /* Information about the function */
|
||||
u8 enc = ENC(pParse->db); /* The database encoding */
|
||||
int savedAllowFlags = (pNC->ncFlags & (NC_AllowAgg | NC_AllowWin));
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
|
||||
#endif
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
zId = pExpr->u.zToken;
|
||||
nId = sqlite3Strlen30(zId);
|
||||
@@ -821,6 +830,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
** SQL is being compiled using sqlite3NestedParse() */
|
||||
no_such_func = 1;
|
||||
pDef = 0;
|
||||
}else
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
|
||||
&& ExprHasProperty(pExpr, EP_Indirect)
|
||||
&& !IN_RENAME_OBJECT
|
||||
){
|
||||
/* Functions tagged with SQLITE_DIRECTONLY may not be used
|
||||
** inside of triggers and views */
|
||||
sqlite3ErrorMsg(pParse, "%s() prohibited in triggers and views",
|
||||
pDef->zName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,18 +848,18 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
|| (pDef->xValue==0 && pDef->xInverse==0)
|
||||
|| (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize)
|
||||
);
|
||||
if( pDef && pDef->xValue==0 && ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
if( pDef && pDef->xValue==0 && pWin ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"%.*s() may not be used as a window function", nId, zId
|
||||
);
|
||||
pNC->nErr++;
|
||||
}else if(
|
||||
(is_agg && (pNC->ncFlags & NC_AllowAgg)==0)
|
||||
|| (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pExpr->y.pWin)
|
||||
|| (is_agg && pExpr->y.pWin && (pNC->ncFlags & NC_AllowWin)==0)
|
||||
|| (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pWin)
|
||||
|| (is_agg && pWin && (pNC->ncFlags & NC_AllowWin)==0)
|
||||
){
|
||||
const char *zType;
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->y.pWin ){
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pWin ){
|
||||
zType = "window";
|
||||
}else{
|
||||
zType = "aggregate";
|
||||
@@ -869,34 +887,44 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
nId, zId);
|
||||
pNC->nErr++;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
else if( is_agg==0 && ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"FILTER may not be used with non-aggregate %.*s()",
|
||||
nId, zId
|
||||
);
|
||||
pNC->nErr++;
|
||||
}
|
||||
#endif
|
||||
if( is_agg ){
|
||||
/* Window functions may not be arguments of aggregate functions.
|
||||
** Or arguments of other window functions. But aggregate functions
|
||||
** may be arguments for window functions. */
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
pNC->ncFlags &= ~(NC_AllowWin | (!pExpr->y.pWin ? NC_AllowAgg : 0));
|
||||
pNC->ncFlags &= ~(NC_AllowWin | (!pWin ? NC_AllowAgg : 0));
|
||||
#else
|
||||
pNC->ncFlags &= ~NC_AllowAgg;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
else if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
is_agg = 1;
|
||||
}
|
||||
#endif
|
||||
sqlite3WalkExprList(pWalker, pList);
|
||||
if( is_agg ){
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( pExpr->y.pWin ){
|
||||
if( pWin ){
|
||||
Select *pSel = pNC->pWinSelect;
|
||||
assert( pWin==pExpr->y.pWin );
|
||||
if( IN_RENAME_OBJECT==0 ){
|
||||
sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->y.pWin, pDef);
|
||||
}
|
||||
sqlite3WalkExprList(pWalker, pExpr->y.pWin->pPartition);
|
||||
sqlite3WalkExprList(pWalker, pExpr->y.pWin->pOrderBy);
|
||||
sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter);
|
||||
if( 0==pSel->pWin
|
||||
|| 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->y.pWin)
|
||||
){
|
||||
pExpr->y.pWin->pNextWin = pSel->pWin;
|
||||
pSel->pWin = pExpr->y.pWin;
|
||||
sqlite3WindowUpdate(pParse, pSel->pWinDefn, pWin, pDef);
|
||||
}
|
||||
sqlite3WalkExprList(pWalker, pWin->pPartition);
|
||||
sqlite3WalkExprList(pWalker, pWin->pOrderBy);
|
||||
sqlite3WalkExpr(pWalker, pWin->pFilter);
|
||||
sqlite3WindowLink(pSel, pWin);
|
||||
pNC->ncFlags |= NC_HasWin;
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
@@ -904,12 +932,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
NameContext *pNC2 = pNC;
|
||||
pExpr->op = TK_AGG_FUNCTION;
|
||||
pExpr->op2 = 0;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter);
|
||||
}
|
||||
#endif
|
||||
while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
|
||||
pExpr->op2++;
|
||||
pNC2 = pNC2->pNext;
|
||||
}
|
||||
assert( pDef!=0 );
|
||||
if( pNC2 ){
|
||||
assert( pDef!=0 || IN_RENAME_OBJECT );
|
||||
if( pNC2 && pDef ){
|
||||
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
|
||||
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
|
||||
pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);
|
||||
@@ -947,7 +980,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
case TK_IS:
|
||||
case TK_ISNOT: {
|
||||
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
|
||||
Expr *pRight = sqlite3ExprSkipCollateAndLikely(pExpr->pRight);
|
||||
assert( !ExprHasProperty(pExpr, EP_Reduced) );
|
||||
/* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE",
|
||||
** and "x IS NOT FALSE". */
|
||||
@@ -1158,7 +1191,7 @@ static int resolveCompoundOrderBy(
|
||||
int iCol = -1;
|
||||
Expr *pE, *pDup;
|
||||
if( pItem->done ) continue;
|
||||
pE = sqlite3ExprSkipCollate(pItem->pExpr);
|
||||
pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
|
||||
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
||||
if( iCol<=0 || iCol>pEList->nExpr ){
|
||||
resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
|
||||
@@ -1252,7 +1285,7 @@ int sqlite3ResolveOrderGroupBy(
|
||||
ExprList *pEList;
|
||||
struct ExprList_item *pItem;
|
||||
|
||||
if( pOrderBy==0 || pParse->db->mallocFailed ) return 0;
|
||||
if( pOrderBy==0 || pParse->db->mallocFailed || IN_RENAME_OBJECT ) return 0;
|
||||
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
||||
sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
|
||||
return 1;
|
||||
@@ -1274,17 +1307,13 @@ int sqlite3ResolveOrderGroupBy(
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/*
|
||||
** Walker callback for resolveRemoveWindows().
|
||||
** Walker callback for windowRemoveExprFromSelect().
|
||||
*/
|
||||
static int resolveRemoveWindowsCb(Walker *pWalker, Expr *pExpr){
|
||||
UNUSED_PARAMETER(pWalker);
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
Window **pp;
|
||||
for(pp=&pWalker->u.pSelect->pWin; *pp; pp=&(*pp)->pNextWin){
|
||||
if( *pp==pExpr->y.pWin ){
|
||||
*pp = (*pp)->pNextWin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Window *pWin = pExpr->y.pWin;
|
||||
sqlite3WindowUnlinkFromSelect(pWin);
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
@@ -1293,16 +1322,18 @@ static int resolveRemoveWindowsCb(Walker *pWalker, Expr *pExpr){
|
||||
** Remove any Window objects owned by the expression pExpr from the
|
||||
** Select.pWin list of Select object pSelect.
|
||||
*/
|
||||
static void resolveRemoveWindows(Select *pSelect, Expr *pExpr){
|
||||
Walker sWalker;
|
||||
memset(&sWalker, 0, sizeof(Walker));
|
||||
sWalker.xExprCallback = resolveRemoveWindowsCb;
|
||||
sWalker.u.pSelect = pSelect;
|
||||
sqlite3WalkExpr(&sWalker, pExpr);
|
||||
static void windowRemoveExprFromSelect(Select *pSelect, Expr *pExpr){
|
||||
if( pSelect->pWin ){
|
||||
Walker sWalker;
|
||||
memset(&sWalker, 0, sizeof(Walker));
|
||||
sWalker.xExprCallback = resolveRemoveWindowsCb;
|
||||
sWalker.u.pSelect = pSelect;
|
||||
sqlite3WalkExpr(&sWalker, pExpr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define resolveRemoveWindows(x,y)
|
||||
#endif
|
||||
# define windowRemoveExprFromSelect(a, b)
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
/*
|
||||
** pOrderBy is an ORDER BY or GROUP BY clause in SELECT statement pSelect.
|
||||
@@ -1339,7 +1370,7 @@ static int resolveOrderGroupBy(
|
||||
pParse = pNC->pParse;
|
||||
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
|
||||
Expr *pE = pItem->pExpr;
|
||||
Expr *pE2 = sqlite3ExprSkipCollate(pE);
|
||||
Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE);
|
||||
if( zType[0]!='G' ){
|
||||
iCol = resolveAsName(pParse, pSelect->pEList, pE2);
|
||||
if( iCol>0 ){
|
||||
@@ -1373,7 +1404,7 @@ static int resolveOrderGroupBy(
|
||||
/* Since this expresion is being changed into a reference
|
||||
** to an identical expression in the result set, remove all Window
|
||||
** objects belonging to the expression from the Select.pWin list. */
|
||||
resolveRemoveWindows(pSelect, pE);
|
||||
windowRemoveExprFromSelect(pSelect, pE);
|
||||
pItem->u.x.iOrderByCol = j+1;
|
||||
}
|
||||
}
|
||||
|
||||
+132
-48
@@ -100,6 +100,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
||||
if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
|
||||
sqlite3WindowListDelete(db, p->pWinDefn);
|
||||
}
|
||||
assert( p->pWin==0 );
|
||||
#endif
|
||||
if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
|
||||
if( bFree ) sqlite3DbFreeNN(db, p);
|
||||
@@ -663,7 +664,7 @@ static void pushOntoSorter(
|
||||
if( pParse->db->mallocFailed ) return;
|
||||
pOp->p2 = nKey + nData;
|
||||
pKI = pOp->p4.pKeyInfo;
|
||||
memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */
|
||||
memset(pKI->aSortFlags, 0, pKI->nKeyField); /* Makes OP_Jump testable */
|
||||
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
|
||||
testcase( pKI->nAllField > pKI->nKeyField+2 );
|
||||
pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat,
|
||||
@@ -1274,7 +1275,7 @@ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
|
||||
int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*);
|
||||
KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
|
||||
if( p ){
|
||||
p->aSortOrder = (u8*)&p->aColl[N+X];
|
||||
p->aSortFlags = (u8*)&p->aColl[N+X];
|
||||
p->nKeyField = (u16)N;
|
||||
p->nAllField = (u16)(N+X);
|
||||
p->enc = ENC(db);
|
||||
@@ -1351,7 +1352,7 @@ KeyInfo *sqlite3KeyInfoFromExprList(
|
||||
assert( sqlite3KeyInfoIsWriteable(pInfo) );
|
||||
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
|
||||
pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr);
|
||||
pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
|
||||
pInfo->aSortFlags[i-iStart] = pItem->sortFlags;
|
||||
}
|
||||
}
|
||||
return pInfo;
|
||||
@@ -1643,8 +1644,6 @@ static const char *columnTypeImpl(
|
||||
|
||||
assert( pExpr!=0 );
|
||||
assert( pNC->pSrcList!=0 );
|
||||
assert( pExpr->op!=TK_AGG_COLUMN ); /* This routine runes before aggregates
|
||||
** are processed */
|
||||
switch( pExpr->op ){
|
||||
case TK_COLUMN: {
|
||||
/* The expression is a column. Locate the table the column is being
|
||||
@@ -1961,12 +1960,11 @@ int sqlite3ColumnsFromExprList(
|
||||
if( (zName = pEList->a[i].zName)!=0 ){
|
||||
/* If the column contains an "AS <name>" phrase, use <name> as the name */
|
||||
}else{
|
||||
Expr *pColExpr = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
|
||||
Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr);
|
||||
while( pColExpr->op==TK_DOT ){
|
||||
pColExpr = pColExpr->pRight;
|
||||
assert( pColExpr!=0 );
|
||||
}
|
||||
assert( pColExpr->op!=TK_AGG_COLUMN );
|
||||
if( pColExpr->op==TK_COLUMN ){
|
||||
/* For columns use the column name name */
|
||||
int iCol = pColExpr->iColumn;
|
||||
@@ -2034,7 +2032,8 @@ int sqlite3ColumnsFromExprList(
|
||||
void sqlite3SelectAddColumnTypeAndCollation(
|
||||
Parse *pParse, /* Parsing contexts */
|
||||
Table *pTab, /* Add column type information to this table */
|
||||
Select *pSelect /* SELECT used to determine types and collations */
|
||||
Select *pSelect, /* SELECT used to determine types and collations */
|
||||
char aff /* Default affinity for columns */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
NameContext sNC;
|
||||
@@ -2067,7 +2066,7 @@ void sqlite3SelectAddColumnTypeAndCollation(
|
||||
pCol->colFlags |= COLFLAG_HASTYPE;
|
||||
}
|
||||
}
|
||||
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
|
||||
if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff;
|
||||
pColl = sqlite3ExprCollSeq(pParse, p);
|
||||
if( pColl && pCol->zColl==0 ){
|
||||
pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
|
||||
@@ -2080,7 +2079,7 @@ void sqlite3SelectAddColumnTypeAndCollation(
|
||||
** Given a SELECT statement, generate a Table structure that describes
|
||||
** the result set of that SELECT.
|
||||
*/
|
||||
Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
||||
Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, char aff){
|
||||
Table *pTab;
|
||||
sqlite3 *db = pParse->db;
|
||||
u64 savedFlags;
|
||||
@@ -2100,7 +2099,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
||||
pTab->zName = 0;
|
||||
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
||||
sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect, aff);
|
||||
pTab->iPKey = -1;
|
||||
if( db->mallocFailed ){
|
||||
sqlite3DeleteTable(db, pTab);
|
||||
@@ -2254,7 +2253,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
|
||||
}
|
||||
assert( sqlite3KeyInfoIsWriteable(pRet) );
|
||||
pRet->aColl[i] = pColl;
|
||||
pRet->aSortOrder[i] = pOrderBy->a[i].sortOrder;
|
||||
pRet->aSortFlags[i] = pOrderBy->a[i].sortFlags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2965,11 +2964,14 @@ static int generateOutputSubroutine(
|
||||
|
||||
/* If this is a scalar select that is part of an expression, then
|
||||
** store the results in the appropriate memory cell and break out
|
||||
** of the scan loop.
|
||||
** of the scan loop. Note that the select might return multiple columns
|
||||
** if it is the RHS of a row-value IN operator.
|
||||
*/
|
||||
case SRT_Mem: {
|
||||
assert( pIn->nSdst==1 || pParse->nErr>0 ); testcase( pIn->nSdst!=1 );
|
||||
sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, 1);
|
||||
if( pParse->nErr==0 ){
|
||||
testcase( pIn->nSdst>1 );
|
||||
sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, pIn->nSdst);
|
||||
}
|
||||
/* The LIMIT clause will jump out of the loop for us */
|
||||
break;
|
||||
}
|
||||
@@ -3226,7 +3228,7 @@ static int multiSelectOrderBy(
|
||||
assert( sqlite3KeyInfoIsWriteable(pKeyDup) );
|
||||
for(i=0; i<nExpr; i++){
|
||||
pKeyDup->aColl[i] = multiSelectCollSeq(pParse, p, i);
|
||||
pKeyDup->aSortOrder[i] = 0;
|
||||
pKeyDup->aSortFlags[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3476,6 +3478,18 @@ static Expr *substExpr(
|
||||
}
|
||||
sqlite3ExprDelete(db, pExpr);
|
||||
pExpr = pNew;
|
||||
|
||||
/* Ensure that the expression now has an implicit collation sequence,
|
||||
** just as it did when it was a column of a view or sub-query. */
|
||||
if( pExpr ){
|
||||
if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
|
||||
pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
|
||||
(pColl ? pColl->zName : "BINARY")
|
||||
);
|
||||
}
|
||||
ExprClearProperty(pExpr, EP_Collate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@@ -3489,6 +3503,14 @@ static Expr *substExpr(
|
||||
}else{
|
||||
substExprList(pSubst, pExpr->x.pList);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
Window *pWin = pExpr->y.pWin;
|
||||
pWin->pFilter = substExpr(pSubst, pWin->pFilter);
|
||||
substExprList(pSubst, pWin->pPartition);
|
||||
substExprList(pSubst, pWin->pOrderBy);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
@@ -3949,6 +3971,7 @@ static int flattenSubquery(
|
||||
for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){
|
||||
int nSubSrc;
|
||||
u8 jointype = 0;
|
||||
assert( pSub!=0 );
|
||||
pSubSrc = pSub->pSrc; /* FROM clause of subquery */
|
||||
nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */
|
||||
pSrc = pParent->pSrc; /* FROM clause of the outer query */
|
||||
@@ -4399,24 +4422,27 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
|
||||
ExprList *pEList = pFunc->x.pList; /* Arguments to agg function */
|
||||
const char *zFunc; /* Name of aggregate function pFunc */
|
||||
ExprList *pOrderBy;
|
||||
u8 sortOrder;
|
||||
u8 sortFlags;
|
||||
|
||||
assert( *ppMinMax==0 );
|
||||
assert( pFunc->op==TK_AGG_FUNCTION );
|
||||
if( pEList==0 || pEList->nExpr!=1 ) return eRet;
|
||||
assert( !IsWindowFunc(pFunc) );
|
||||
if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_WinFunc) ){
|
||||
return eRet;
|
||||
}
|
||||
zFunc = pFunc->u.zToken;
|
||||
if( sqlite3StrICmp(zFunc, "min")==0 ){
|
||||
eRet = WHERE_ORDERBY_MIN;
|
||||
sortOrder = SQLITE_SO_ASC;
|
||||
sortFlags = KEYINFO_ORDER_BIGNULL;
|
||||
}else if( sqlite3StrICmp(zFunc, "max")==0 ){
|
||||
eRet = WHERE_ORDERBY_MAX;
|
||||
sortOrder = SQLITE_SO_DESC;
|
||||
sortFlags = KEYINFO_ORDER_DESC;
|
||||
}else{
|
||||
return eRet;
|
||||
}
|
||||
*ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0);
|
||||
assert( pOrderBy!=0 || db->mallocFailed );
|
||||
if( pOrderBy ) pOrderBy->a[0].sortOrder = sortOrder;
|
||||
if( pOrderBy ) pOrderBy->a[0].sortFlags = sortFlags;
|
||||
return eRet;
|
||||
}
|
||||
|
||||
@@ -4450,7 +4476,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
||||
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
|
||||
if( NEVER(pAggInfo->nFunc==0) ) return 0;
|
||||
if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0;
|
||||
if( pExpr->flags&EP_Distinct ) return 0;
|
||||
if( ExprHasProperty(pExpr, EP_Distinct|EP_WinFunc) ) return 0;
|
||||
|
||||
return pTab;
|
||||
}
|
||||
@@ -4897,6 +4923,10 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
u8 eCodeOrig = pWalker->eCode;
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
|
||||
assert( pFrom->pSelect==0 );
|
||||
if( pTab->pSelect && (db->flags & SQLITE_EnableView)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
|
||||
pTab->zName);
|
||||
}
|
||||
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
|
||||
nCol = pTab->nCol;
|
||||
pTab->nCol = -1;
|
||||
@@ -5190,7 +5220,8 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
|
||||
Select *pSel = pFrom->pSelect;
|
||||
if( pSel ){
|
||||
while( pSel->pPrior ) pSel = pSel->pPrior;
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel);
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel,
|
||||
SQLITE_AFF_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5330,6 +5361,25 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
||||
int regAgg;
|
||||
ExprList *pList = pF->pExpr->x.pList;
|
||||
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
|
||||
assert( !IsWindowFunc(pF->pExpr) );
|
||||
if( ExprHasProperty(pF->pExpr, EP_WinFunc) ){
|
||||
Expr *pFilter = pF->pExpr->y.pWin->pFilter;
|
||||
if( pAggInfo->nAccumulator
|
||||
&& (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
|
||||
){
|
||||
if( regHit==0 ) regHit = ++pParse->nMem;
|
||||
/* If this is the first row of the group (regAcc==0), clear the
|
||||
** "magnet" register regHit so that the accumulator registers
|
||||
** are populated if the FILTER clause jumps over the the
|
||||
** invocation of min() or max() altogether. Or, if this is not
|
||||
** the first row (regAcc==1), set the magnet register so that the
|
||||
** accumulators are not populated unless the min()/max() is invoked and
|
||||
** indicates that they should be. */
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, regAcc, regHit);
|
||||
}
|
||||
addrNext = sqlite3VdbeMakeLabel(pParse);
|
||||
sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL);
|
||||
}
|
||||
if( pList ){
|
||||
nArg = pList->nExpr;
|
||||
regAgg = sqlite3GetTempRange(pParse, nArg);
|
||||
@@ -5339,7 +5389,9 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
||||
regAgg = 0;
|
||||
}
|
||||
if( pF->iDistinct>=0 ){
|
||||
addrNext = sqlite3VdbeMakeLabel(pParse);
|
||||
if( addrNext==0 ){
|
||||
addrNext = sqlite3VdbeMakeLabel(pParse);
|
||||
}
|
||||
testcase( nArg==0 ); /* Error condition */
|
||||
testcase( nArg>1 ); /* Also an error */
|
||||
codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
|
||||
@@ -5375,6 +5427,7 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
||||
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
|
||||
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
|
||||
}
|
||||
|
||||
pAggInfo->directMode = 0;
|
||||
if( addrHitTest ){
|
||||
sqlite3VdbeJumpHere(v, addrHitTest);
|
||||
@@ -5420,7 +5473,7 @@ static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
|
||||
Select *pS = pWalker->u.pSelect;
|
||||
if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) ){
|
||||
sqlite3 *db = pWalker->pParse->db;
|
||||
Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0);
|
||||
Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1");
|
||||
if( pNew ){
|
||||
Expr *pWhere = pS->pWhere;
|
||||
SWAP(Expr, *pNew, *pExpr);
|
||||
@@ -5842,7 +5895,7 @@ int sqlite3Select(
|
||||
** assume the column name is non-NULL and segfault. The use of an empty
|
||||
** string for the fake column name seems safer.
|
||||
*/
|
||||
if( pItem->colUsed==0 ){
|
||||
if( pItem->colUsed==0 && pItem->zName!=0 ){
|
||||
sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
|
||||
}
|
||||
|
||||
@@ -5856,8 +5909,15 @@ int sqlite3Select(
|
||||
** technically harmless for it to be generated multiple times. The
|
||||
** following assert() will detect if something changes to cause
|
||||
** the same subquery to be coded multiple times, as a signal to the
|
||||
** developers to try to optimize the situation. */
|
||||
assert( pItem->addrFillSub==0 );
|
||||
** developers to try to optimize the situation.
|
||||
**
|
||||
** Update 2019-07-24:
|
||||
** See ticket https://sqlite.org/src/tktview/c52b09c7f38903b1311cec40.
|
||||
** The dbsqlfuzz fuzzer found a case where the same subquery gets
|
||||
** coded twice. So this assert() now becomes a testcase(). It should
|
||||
** be very rare, though.
|
||||
*/
|
||||
testcase( pItem->addrFillSub!=0 );
|
||||
|
||||
/* Increment Parse.nHeight by the height of the largest expression
|
||||
** tree referred to by this, the parent select. The child select
|
||||
@@ -5931,7 +5991,7 @@ int sqlite3Select(
|
||||
int retAddr;
|
||||
struct SrcList_item *pPrior;
|
||||
|
||||
assert( pItem->addrFillSub==0 );
|
||||
testcase( pItem->addrFillSub==0 ); /* Ticket c52b09c7f38903b1311 */
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||
pItem->addrFillSub = topAddr+1;
|
||||
@@ -6171,23 +6231,35 @@ int sqlite3Select(
|
||||
}
|
||||
assert( 66==sqlite3LogEst(100) );
|
||||
if( p->nSelectRow>66 ) p->nSelectRow = 66;
|
||||
|
||||
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
||||
** identical, then it may be possible to disable the ORDER BY clause
|
||||
** on the grounds that the GROUP BY will cause elements to come out
|
||||
** in the correct order. It also may not - the GROUP BY might use a
|
||||
** database index that causes rows to be grouped together as required
|
||||
** but not actually sorted. Either way, record the fact that the
|
||||
** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
|
||||
** variable. */
|
||||
if( sSort.pOrderBy && pGroupBy->nExpr==sSort.pOrderBy->nExpr ){
|
||||
int ii;
|
||||
/* The GROUP BY processing doesn't care whether rows are delivered in
|
||||
** ASC or DESC order - only that each group is returned contiguously.
|
||||
** So set the ASC/DESC flags in the GROUP BY to match those in the
|
||||
** ORDER BY to maximize the chances of rows being delivered in an
|
||||
** order that makes the ORDER BY redundant. */
|
||||
for(ii=0; ii<pGroupBy->nExpr; ii++){
|
||||
u8 sortFlags = sSort.pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_DESC;
|
||||
pGroupBy->a[ii].sortFlags = sortFlags;
|
||||
}
|
||||
if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){
|
||||
orderByGrp = 1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
assert( 0==sqlite3LogEst(1) );
|
||||
p->nSelectRow = 0;
|
||||
}
|
||||
|
||||
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
||||
** identical, then it may be possible to disable the ORDER BY clause
|
||||
** on the grounds that the GROUP BY will cause elements to come out
|
||||
** in the correct order. It also may not - the GROUP BY might use a
|
||||
** database index that causes rows to be grouped together as required
|
||||
** but not actually sorted. Either way, record the fact that the
|
||||
** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
|
||||
** variable. */
|
||||
if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){
|
||||
orderByGrp = 1;
|
||||
}
|
||||
|
||||
/* Create a label to jump to when we want to abort the query */
|
||||
addrEnd = sqlite3VdbeMakeLabel(pParse);
|
||||
|
||||
@@ -6222,9 +6294,16 @@ int sqlite3Select(
|
||||
minMaxFlag = WHERE_ORDERBY_NORMAL;
|
||||
}
|
||||
for(i=0; i<sAggInfo.nFunc; i++){
|
||||
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
|
||||
Expr *pExpr = sAggInfo.aFunc[i].pExpr;
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
sNC.ncFlags |= NC_InAggFunc;
|
||||
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
|
||||
sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
assert( !IsWindowFunc(pExpr) );
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
sqlite3ExprAnalyzeAggregates(&sNC, pExpr->y.pWin->pFilter);
|
||||
}
|
||||
#endif
|
||||
sNC.ncFlags &= ~NC_InAggFunc;
|
||||
}
|
||||
sAggInfo.mxReg = pParse->nMem;
|
||||
@@ -6536,13 +6615,18 @@ int sqlite3Select(
|
||||
{
|
||||
int regAcc = 0; /* "populate accumulators" flag */
|
||||
|
||||
/* If there are accumulator registers but no min() or max() functions,
|
||||
** allocate register regAcc. Register regAcc will contain 0 the first
|
||||
** time the inner loop runs, and 1 thereafter. The code generated
|
||||
** by updateAccumulator() only updates the accumulator registers if
|
||||
** regAcc contains 0. */
|
||||
/* If there are accumulator registers but no min() or max() functions
|
||||
** without FILTER clauses, allocate register regAcc. Register regAcc
|
||||
** will contain 0 the first time the inner loop runs, and 1 thereafter.
|
||||
** The code generated by updateAccumulator() uses this to ensure
|
||||
** that the accumulator registers are (a) updated only once if
|
||||
** there are no min() or max functions or (b) always updated for the
|
||||
** first row visited by the aggregate, so that they are updated at
|
||||
** least once even if the FILTER clause means the min() or max()
|
||||
** function visits zero rows. */
|
||||
if( sAggInfo.nAccumulator ){
|
||||
for(i=0; i<sAggInfo.nFunc; i++){
|
||||
if( ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_WinFunc) ) continue;
|
||||
if( sAggInfo.aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ) break;
|
||||
}
|
||||
if( i==sAggInfo.nFunc ){
|
||||
|
||||
+207
-85
@@ -1256,12 +1256,12 @@ static void editFunc(
|
||||
}
|
||||
sz = sqlite3_value_bytes(argv[0]);
|
||||
if( bBin ){
|
||||
x = fwrite(sqlite3_value_blob(argv[0]), 1, sz, f);
|
||||
x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f);
|
||||
}else{
|
||||
const char *z = (const char*)sqlite3_value_text(argv[0]);
|
||||
/* Remember whether or not the value originally contained \r\n */
|
||||
if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1;
|
||||
x = fwrite(sqlite3_value_text(argv[0]), 1, sz, f);
|
||||
x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
|
||||
}
|
||||
fclose(f);
|
||||
f = 0;
|
||||
@@ -1289,12 +1289,12 @@ static void editFunc(
|
||||
fseek(f, 0, SEEK_END);
|
||||
sz = ftell(f);
|
||||
rewind(f);
|
||||
p = sqlite3_malloc64( sz+(bBin==0) );
|
||||
p = sqlite3_malloc64( sz+1 );
|
||||
if( p==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
goto edit_func_end;
|
||||
}
|
||||
x = fread(p, 1, sz, f);
|
||||
x = fread(p, 1, (size_t)sz, f);
|
||||
fclose(f);
|
||||
f = 0;
|
||||
if( x!=sz ){
|
||||
@@ -1766,7 +1766,8 @@ static void eqp_render_level(ShellState *p, int iEqpId){
|
||||
for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
|
||||
pNext = eqp_next_row(p, iEqpId, pRow);
|
||||
z = pRow->zText;
|
||||
utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix, pNext ? "|--" : "`--", z);
|
||||
utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix,
|
||||
pNext ? "|--" : "`--", z);
|
||||
if( n<(int)sizeof(p->sGraph.zPrefix)-7 ){
|
||||
memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
|
||||
eqp_render_level(p, pRow->iEqpId);
|
||||
@@ -1957,7 +1958,7 @@ static int shell_callback(
|
||||
while( j>0 && IsSpace(z[j-1]) ){ j--; }
|
||||
z[j] = 0;
|
||||
if( strlen30(z)>=79 ){
|
||||
for(i=j=0; (c = z[i])!=0; i++){ /* Copy changes from z[i] back to z[j] */
|
||||
for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */
|
||||
if( c==cEnd ){
|
||||
cEnd = 0;
|
||||
}else if( c=='"' || c=='\'' || c=='`' ){
|
||||
@@ -2536,7 +2537,7 @@ static int display_stats(
|
||||
raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
|
||||
raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE, bReset);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
|
||||
raw_printf(pArg->out, "Reprepare operations: %d\n", iCur);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
|
||||
raw_printf(pArg->out, "Number of times run: %d\n", iCur);
|
||||
@@ -3459,20 +3460,20 @@ static const char *(azHelp[]) = {
|
||||
".archive ... Manage SQL archives",
|
||||
" Each command must have exactly one of the following options:",
|
||||
" -c, --create Create a new archive",
|
||||
" -u, --update Add files or update files with changed mtime",
|
||||
" -i, --insert Like -u but always add even if mtime unchanged",
|
||||
" -u, --update Add or update files with changed mtime",
|
||||
" -i, --insert Like -u but always add even if unchanged",
|
||||
" -t, --list List contents of archive",
|
||||
" -x, --extract Extract files from archive",
|
||||
" Optional arguments:",
|
||||
" -v, --verbose Print each filename as it is processed",
|
||||
" -f FILE, --file FILE Operate on archive FILE (default is current db)",
|
||||
" -a FILE, --append FILE Operate on FILE opened using the apndvfs VFS",
|
||||
" -C DIR, --directory DIR Change to directory DIR to read/extract files",
|
||||
" -f FILE, --file FILE Use archive FILE (default is current db)",
|
||||
" -a FILE, --append FILE Open FILE using the apndvfs VFS",
|
||||
" -C DIR, --directory DIR Read/extract files from directory DIR",
|
||||
" -n, --dryrun Show the SQL that would have occurred",
|
||||
" Examples:",
|
||||
" .ar -cf archive.sar foo bar # Create archive.sar from files foo and bar",
|
||||
" .ar -tf archive.sar # List members of archive.sar",
|
||||
" .ar -xvf archive.sar # Verbosely extract files from archive.sar",
|
||||
" .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar",
|
||||
" .ar -tf ARCHIVE # List members of ARCHIVE",
|
||||
" .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE",
|
||||
" See also:",
|
||||
" http://sqlite.org/cli.html#sqlar_archive_support",
|
||||
#endif
|
||||
@@ -3481,7 +3482,7 @@ static const char *(azHelp[]) = {
|
||||
#endif
|
||||
".backup ?DB? FILE Backup DB (default \"main\") to FILE",
|
||||
" --append Use the appendvfs",
|
||||
" --async Write to FILE without a journal and without fsync()",
|
||||
" --async Write to FILE without journal and fsync()",
|
||||
".bail on|off Stop after hitting an error. Default OFF",
|
||||
".binary on|off Turn binary output on or off. Default OFF",
|
||||
".cd DIRECTORY Change the working directory to DIRECTORY",
|
||||
@@ -3501,15 +3502,15 @@ static const char *(azHelp[]) = {
|
||||
" Other Modes:",
|
||||
#ifdef SQLITE_DEBUG
|
||||
" test Show raw EXPLAIN QUERY PLAN output",
|
||||
" trace Like \"full\" but also enable \"PRAGMA vdbe_trace\"",
|
||||
" trace Like \"full\" but enable \"PRAGMA vdbe_trace\"",
|
||||
#endif
|
||||
" trigger Like \"full\" but also show trigger bytecode",
|
||||
".excel Display the output of next command in a spreadsheet",
|
||||
".excel Display the output of next command in spreadsheet",
|
||||
".exit ?CODE? Exit this program with return-code CODE",
|
||||
".expert EXPERIMENTAL. Suggest indexes for specified queries",
|
||||
".expert EXPERIMENTAL. Suggest indexes for queries",
|
||||
/* Because explain mode comes on automatically now, the ".explain" mode
|
||||
** is removed from the help screen. It is still supported for legacy, however */
|
||||
/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic",*/
|
||||
** is removed from the help screen. It is still supported for legacy, however */
|
||||
/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off",*/
|
||||
".filectrl CMD ... Run various sqlite3_file_control() operations",
|
||||
" Run \".filectrl\" with no arguments for details",
|
||||
".fullschema ?--indent? Show schema and the content of sqlite_stat tables",
|
||||
@@ -3556,7 +3557,7 @@ static const char *(azHelp[]) = {
|
||||
" --append Use appendvfs to append database to the end of FILE",
|
||||
#ifdef SQLITE_ENABLE_DESERIALIZE
|
||||
" --deserialize Load into memory useing sqlite3_deserialize()",
|
||||
" --hexdb Load the output of \"dbtotxt\" as an in-memory database",
|
||||
" --hexdb Load the output of \"dbtotxt\" as an in-memory db",
|
||||
" --maxsize N Maximum size for --hexdb or --deserialized database",
|
||||
#endif
|
||||
" --new Initialize FILE to an empty database",
|
||||
@@ -3569,7 +3570,7 @@ static const char *(azHelp[]) = {
|
||||
" init Initialize the TEMP table that holds bindings",
|
||||
" list List the current parameter bindings",
|
||||
" set PARAMETER VALUE Given SQL parameter PARAMETER a value of VALUE",
|
||||
" PARAMETER should start with '$', ':', '@', or '?'",
|
||||
" PARAMETER should start with one of: $ : @ ?",
|
||||
" unset PARAMETER Remove PARAMETER from the binding table",
|
||||
".print STRING... Print literal STRING",
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
@@ -3584,6 +3585,11 @@ static const char *(azHelp[]) = {
|
||||
".read FILE Read input from FILE",
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
|
||||
".recover Recover as much data as possible from corrupt db.",
|
||||
" --freelist-corrupt Assume the freelist is corrupt",
|
||||
" --recovery-db NAME Store recovery metadata in database file NAME",
|
||||
" --lost-and-found TABLE Alternative name for the lost-and-found table",
|
||||
" --no-rowids Do not attempt to recover rowid values",
|
||||
" that are not also INTEGER PRIMARY KEYs",
|
||||
#endif
|
||||
".restore ?DB? FILE Restore content of DB (default \"main\") from FILE",
|
||||
".save FILE Write in-memory database into FILE",
|
||||
@@ -3615,7 +3621,7 @@ static const char *(azHelp[]) = {
|
||||
" Options:",
|
||||
" --schema Also hash the sqlite_master table",
|
||||
" --sha3-224 Use the sha3-224 algorithm",
|
||||
" --sha3-256 Use the sha3-256 algorithm. This is the default.",
|
||||
" --sha3-256 Use the sha3-256 algorithm (default)",
|
||||
" --sha3-384 Use the sha3-384 algorithm",
|
||||
" --sha3-512 Use the sha3-512 algorithm",
|
||||
" Any other argument is a LIKE pattern for tables to hash",
|
||||
@@ -3649,6 +3655,10 @@ static const char *(azHelp[]) = {
|
||||
" --row Trace each row (SQLITE_TRACE_ROW)",
|
||||
" --close Trace connection close (SQLITE_TRACE_CLOSE)",
|
||||
#endif /* SQLITE_OMIT_TRACE */
|
||||
#ifdef SQLITE_DEBUG
|
||||
".unmodule NAME ... Unregister virtual table modules",
|
||||
" --allexcept Unregister everything except those named",
|
||||
#endif
|
||||
".vfsinfo ?AUX? Information about the top-level VFS",
|
||||
".vfslist List all available VFSes",
|
||||
".vfsname ?AUX? Print the name of the VFS stack",
|
||||
@@ -3891,6 +3901,8 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
|
||||
rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
|
||||
if( rc!=2 ) goto readHexDb_error;
|
||||
if( n<0 ) goto readHexDb_error;
|
||||
if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error;
|
||||
n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */
|
||||
a = sqlite3_malloc( n ? n : 1 );
|
||||
if( a==0 ){
|
||||
utf8_printf(stderr, "Out of memory!\n");
|
||||
@@ -3975,6 +3987,23 @@ static void shellInt32(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Scalar function "shell_idquote(X)" returns string X quoted as an identifier,
|
||||
** using "..." with internal double-quote characters doubled.
|
||||
*/
|
||||
static void shellIdQuote(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zName = (const char*)sqlite3_value_text(argv[0]);
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( zName ){
|
||||
char *z = sqlite3_mprintf("\"%w\"", zName);
|
||||
sqlite3_result_text(context, z, -1, sqlite3_free);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Scalar function "shell_escape_crnl" used by the .recover command.
|
||||
** The argument passed to this function is the output of built-in
|
||||
@@ -4151,6 +4180,8 @@ static void open_db(ShellState *p, int openFlags){
|
||||
shellEscapeCrnl, 0, 0);
|
||||
sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0,
|
||||
shellInt32, 0, 0);
|
||||
sqlite3_create_function(p->db, "shell_idquote", 1, SQLITE_UTF8, 0,
|
||||
shellIdQuote, 0, 0);
|
||||
#ifndef SQLITE_NOHAVE_SYSTEM
|
||||
sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
|
||||
editFunc, 0, 0);
|
||||
@@ -5498,7 +5529,7 @@ void shellReset(
|
||||
#endif /* !defined SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
|
||||
/*********************************************************************************
|
||||
/******************************************************************************
|
||||
** The ".archive" or ".ar" command.
|
||||
*/
|
||||
/*
|
||||
@@ -5696,7 +5727,8 @@ static int arParseCommand(
|
||||
i = n;
|
||||
}else{
|
||||
if( iArg>=(nArg-1) ){
|
||||
return arErrorMsg(pAr, "option requires an argument: %c",z[i]);
|
||||
return arErrorMsg(pAr, "option requires an argument: %c",
|
||||
z[i]);
|
||||
}
|
||||
zArg = azArg[++iArg];
|
||||
}
|
||||
@@ -6084,10 +6116,10 @@ end_ar_transaction:
|
||||
** Implementation of ".ar" dot command.
|
||||
*/
|
||||
static int arDotCommand(
|
||||
ShellState *pState, /* Current shell tool state */
|
||||
int fromCmdLine, /* True if -A command-line option, not .ar cmd */
|
||||
char **azArg, /* Array of arguments passed to dot command */
|
||||
int nArg /* Number of entries in azArg[] */
|
||||
ShellState *pState, /* Current shell tool state */
|
||||
int fromCmdLine, /* True if -A command-line option, not .ar cmd */
|
||||
char **azArg, /* Array of arguments passed to dot command */
|
||||
int nArg /* Number of entries in azArg[] */
|
||||
){
|
||||
ArCommand cmd;
|
||||
int rc;
|
||||
@@ -6187,7 +6219,7 @@ end_ar_command:
|
||||
return rc;
|
||||
}
|
||||
/* End of the ".archive" or ".ar" command logic
|
||||
**********************************************************************************/
|
||||
*******************************************************************************/
|
||||
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
|
||||
@@ -6328,6 +6360,10 @@ static RecoverTable *recoverNewTable(
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
|
||||
rc = sqlite3_open("", &dbtmp);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_create_function(dbtmp, "shell_idquote", 1, SQLITE_UTF8, 0,
|
||||
shellIdQuote, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_exec(dbtmp, "PRAGMA writable_schema = on", 0, 0, 0);
|
||||
}
|
||||
@@ -6384,18 +6420,18 @@ static RecoverTable *recoverNewTable(
|
||||
}
|
||||
}
|
||||
|
||||
pTab->zQuoted = shellMPrintf(&rc, "%Q", zName);
|
||||
pTab->zQuoted = shellMPrintf(&rc, "\"%w\"", zName);
|
||||
pTab->azlCol = (char**)shellMalloc(&rc, sizeof(char*) * (nSqlCol+1));
|
||||
pTab->nCol = nSqlCol;
|
||||
|
||||
if( bIntkey ){
|
||||
pTab->azlCol[0] = shellMPrintf(&rc, "%Q", zPk);
|
||||
pTab->azlCol[0] = shellMPrintf(&rc, "\"%w\"", zPk);
|
||||
}else{
|
||||
pTab->azlCol[0] = shellMPrintf(&rc, "");
|
||||
}
|
||||
i = 1;
|
||||
shellPreparePrintf(dbtmp, &rc, &pStmt,
|
||||
"SELECT %Q || group_concat(name, ', ') "
|
||||
"SELECT %Q || group_concat(shell_idquote(name), ', ') "
|
||||
" FILTER (WHERE cid!=%d) OVER (ORDER BY %s cid) "
|
||||
"FROM pragma_table_info(%Q)",
|
||||
bIntkey ? ", " : "", pTab->iPk,
|
||||
@@ -6509,7 +6545,7 @@ static RecoverTable *recoverOrphanTable(
|
||||
|
||||
pTab = (RecoverTable*)shellMalloc(pRc, sizeof(RecoverTable));
|
||||
if( pTab ){
|
||||
pTab->zQuoted = shellMPrintf(pRc, "%Q", zTab);
|
||||
pTab->zQuoted = shellMPrintf(pRc, "\"%w\"", zTab);
|
||||
pTab->nCol = nCol;
|
||||
pTab->iPk = -2;
|
||||
if( nCol>0 ){
|
||||
@@ -6558,6 +6594,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
RecoverTable *pOrphan = 0;
|
||||
|
||||
int bFreelist = 1; /* 0 if --freelist-corrupt is specified */
|
||||
int bRowids = 1; /* 0 if --no-rowids */
|
||||
for(i=1; i<nArg; i++){
|
||||
char *z = azArg[i];
|
||||
int n;
|
||||
@@ -6573,13 +6610,13 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
if( n<=15 && memcmp("-lost-and-found", z, n)==0 && i<(nArg-1) ){
|
||||
i++;
|
||||
zLostAndFound = azArg[i];
|
||||
}else
|
||||
if( n<=10 && memcmp("-no-rowids", z, n)==0 ){
|
||||
bRowids = 0;
|
||||
}
|
||||
else{
|
||||
raw_printf(stderr, "unexpected option: %s\n", azArg[i]);
|
||||
raw_printf(stderr, "options are:\n");
|
||||
raw_printf(stderr, " --freelist-corrupt\n");
|
||||
raw_printf(stderr, " --recovery-db DATABASE\n");
|
||||
raw_printf(stderr, " --lost-and-found TABLE-NAME\n");
|
||||
utf8_printf(stderr, "unexpected option: %s\n", azArg[i]);
|
||||
showHelp(pState->out, azArg[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -6587,6 +6624,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
shellExecPrintf(pState->db, &rc,
|
||||
/* Attach an in-memory database named 'recovery'. Create an indexed
|
||||
** cache of the sqlite_dbptr virtual table. */
|
||||
"PRAGMA writable_schema = on;"
|
||||
"ATTACH %Q AS recovery;"
|
||||
"DROP TABLE IF EXISTS recovery.dbptr;"
|
||||
"DROP TABLE IF EXISTS recovery.freelist;"
|
||||
@@ -6617,6 +6655,21 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
);
|
||||
}
|
||||
|
||||
/* If this is an auto-vacuum database, add all pointer-map pages to
|
||||
** the freelist table. Do this regardless of whether or not
|
||||
** --freelist-corrupt was specified. */
|
||||
shellExec(pState->db, &rc,
|
||||
"WITH ptrmap(pgno) AS ("
|
||||
" SELECT 2 WHERE shell_int32("
|
||||
" (SELECT data FROM sqlite_dbpage WHERE pgno=1), 13"
|
||||
" )"
|
||||
" UNION ALL "
|
||||
" SELECT pgno+1+(SELECT page_size FROM pragma_page_size)/5 AS pp "
|
||||
" FROM ptrmap WHERE pp<=(SELECT page_count FROM pragma_page_count)"
|
||||
")"
|
||||
"REPLACE INTO recovery.freelist SELECT pgno FROM ptrmap"
|
||||
);
|
||||
|
||||
shellExec(pState->db, &rc,
|
||||
"CREATE TABLE recovery.dbptr("
|
||||
" pgno, child, PRIMARY KEY(child, pgno)"
|
||||
@@ -6665,7 +6718,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
" )"
|
||||
" SELECT pgno FROM p WHERE (parent IS NULL OR pgno = orig)"
|
||||
") "
|
||||
"FROM pages WHERE maxlen > 0 AND i NOT IN freelist;"
|
||||
"FROM pages WHERE maxlen IS NOT NULL AND i NOT IN freelist;"
|
||||
"UPDATE recovery.map AS o SET intkey = ("
|
||||
" SELECT substr(data, 1, 1)==X'0D' FROM sqlite_dbpage WHERE pgno=o.pgno"
|
||||
");"
|
||||
@@ -6690,6 +6743,11 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
** CREATE TABLE statements that extracted from the existing schema. */
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
/* ".recover" might output content in an order which causes immediate
|
||||
** foreign key constraints to be violated. So disable foreign-key
|
||||
** constraint enforcement to prevent problems when running the output
|
||||
** script. */
|
||||
raw_printf(pState->out, "PRAGMA foreign_keys=OFF;\n");
|
||||
raw_printf(pState->out, "BEGIN;\n");
|
||||
raw_printf(pState->out, "PRAGMA writable_schema = on;\n");
|
||||
shellPrepare(pState->db, &rc,
|
||||
@@ -6720,8 +6778,12 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
shellPrepare(pState->db, &rc,
|
||||
"SELECT pgno FROM recovery.map WHERE root=?", &pPages
|
||||
);
|
||||
|
||||
shellPrepare(pState->db, &rc,
|
||||
"SELECT max(field), group_concat(shell_escape_crnl(quote(value)), ', ')"
|
||||
"SELECT max(field), group_concat(shell_escape_crnl(quote"
|
||||
"(case when (? AND field<0) then NULL else value end)"
|
||||
"), ', ')"
|
||||
", min(field) "
|
||||
"FROM sqlite_dbdata WHERE pgno = ? AND field != ?"
|
||||
"GROUP BY cell", &pCells
|
||||
);
|
||||
@@ -6740,6 +6802,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
int bNoop = 0;
|
||||
RecoverTable *pTab;
|
||||
|
||||
assert( bIntkey==0 || bIntkey==1 );
|
||||
pTab = recoverFindTable(pState, &rc, iRoot, bIntkey, nCol, &bNoop);
|
||||
if( bNoop || rc ) continue;
|
||||
if( pTab==0 ){
|
||||
@@ -6750,29 +6813,44 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
if( pTab==0 ) break;
|
||||
}
|
||||
|
||||
if( 0==sqlite3_stricmp(pTab->zQuoted, "'sqlite_sequence'") ){
|
||||
if( 0==sqlite3_stricmp(pTab->zQuoted, "\"sqlite_sequence\"") ){
|
||||
raw_printf(pState->out, "DELETE FROM sqlite_sequence;\n");
|
||||
}
|
||||
sqlite3_bind_int(pPages, 1, iRoot);
|
||||
sqlite3_bind_int(pCells, 2, pTab->iPk);
|
||||
if( bRowids==0 && pTab->iPk<0 ){
|
||||
sqlite3_bind_int(pCells, 1, 1);
|
||||
}else{
|
||||
sqlite3_bind_int(pCells, 1, 0);
|
||||
}
|
||||
sqlite3_bind_int(pCells, 3, pTab->iPk);
|
||||
|
||||
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPages) ){
|
||||
int iPgno = sqlite3_column_int(pPages, 0);
|
||||
sqlite3_bind_int(pCells, 1, iPgno);
|
||||
sqlite3_bind_int(pCells, 2, iPgno);
|
||||
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pCells) ){
|
||||
int nField = sqlite3_column_int(pCells, 0);
|
||||
int iMin = sqlite3_column_int(pCells, 2);
|
||||
const char *zVal = (const char*)sqlite3_column_text(pCells, 1);
|
||||
|
||||
RecoverTable *pTab2 = pTab;
|
||||
if( pTab!=pOrphan && (iMin<0)!=bIntkey ){
|
||||
if( pOrphan==0 ){
|
||||
pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan);
|
||||
}
|
||||
pTab2 = pOrphan;
|
||||
if( pTab2==0 ) break;
|
||||
}
|
||||
|
||||
nField = nField+1;
|
||||
if( pTab==pOrphan ){
|
||||
if( pTab2==pOrphan ){
|
||||
raw_printf(pState->out,
|
||||
"INSERT INTO %s VALUES(%d, %d, %d, %s%s%s);\n",
|
||||
pTab->zQuoted, iRoot, iPgno, nField,
|
||||
bIntkey ? "" : "NULL, ", zVal, pTab->azlCol[nField]
|
||||
pTab2->zQuoted, iRoot, iPgno, nField,
|
||||
iMin<0 ? "" : "NULL, ", zVal, pTab2->azlCol[nField]
|
||||
);
|
||||
}else{
|
||||
raw_printf(pState->out, "INSERT INTO %s(%s) VALUES( %s );\n",
|
||||
pTab->zQuoted, pTab->azlCol[nField], zVal
|
||||
pTab2->zQuoted, pTab2->azlCol[nField], zVal
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6831,7 +6909,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int nArg = 0;
|
||||
int n, c;
|
||||
int rc = 0;
|
||||
char *azArg[50];
|
||||
char *azArg[52];
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( p->expert.pExpert ){
|
||||
@@ -6841,7 +6919,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
/* Parse the input line into tokens.
|
||||
*/
|
||||
while( zLine[h] && nArg<ArraySize(azArg) ){
|
||||
while( zLine[h] && nArg<ArraySize(azArg)-1 ){
|
||||
while( IsSpace(zLine[h]) ){ h++; }
|
||||
if( zLine[h]==0 ) break;
|
||||
if( zLine[h]=='\'' || zLine[h]=='"' ){
|
||||
@@ -6862,6 +6940,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
resolve_backslashes(azArg[nArg-1]);
|
||||
}
|
||||
}
|
||||
azArg[nArg] = 0;
|
||||
|
||||
/* Process the input line.
|
||||
*/
|
||||
@@ -7077,6 +7156,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
} aDbConfig[] = {
|
||||
{ "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
|
||||
{ "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
|
||||
{ "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
|
||||
{ "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
|
||||
{ "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
|
||||
{ "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
|
||||
@@ -7450,8 +7530,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
data.cMode = data.mode = MODE_Insert;
|
||||
data.zDestTable = "sqlite_stat1";
|
||||
shell_exec(&data, "SELECT * FROM sqlite_stat1", &zErrMsg);
|
||||
data.zDestTable = "sqlite_stat3";
|
||||
shell_exec(&data, "SELECT * FROM sqlite_stat3", &zErrMsg);
|
||||
data.zDestTable = "sqlite_stat4";
|
||||
shell_exec(&data, "SELECT * FROM sqlite_stat4", &zErrMsg);
|
||||
raw_printf(p->out, "ANALYZE sqlite_master;\n");
|
||||
@@ -8070,12 +8148,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
** Clear all bind parameters by dropping the TEMP table that holds them.
|
||||
*/
|
||||
if( nArg==2 && strcmp(azArg[1],"clear")==0 ){
|
||||
int wrSchema = 0;
|
||||
sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema);
|
||||
sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0);
|
||||
sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;",
|
||||
0, 0, 0);
|
||||
sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0);
|
||||
}else
|
||||
|
||||
/* .parameter list
|
||||
@@ -8388,7 +8462,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
zDiv = " UNION ALL ";
|
||||
appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
|
||||
if( sqlite3_stricmp(zDb, "main")!=0 ){
|
||||
appendText(&sSelect, zDb, '"');
|
||||
appendText(&sSelect, zDb, '\'');
|
||||
}else{
|
||||
appendText(&sSelect, "NULL", 0);
|
||||
}
|
||||
@@ -8397,15 +8471,16 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
appendText(&sSelect, " AS snum, ", 0);
|
||||
appendText(&sSelect, zDb, '\'');
|
||||
appendText(&sSelect, " AS sname FROM ", 0);
|
||||
appendText(&sSelect, zDb, '"');
|
||||
appendText(&sSelect, zDb, quoteChar(zDb));
|
||||
appendText(&sSelect, ".sqlite_master", 0);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
#ifdef SQLITE_INTROSPECTION_PRAGMAS
|
||||
#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
|
||||
if( zName ){
|
||||
appendText(&sSelect,
|
||||
" UNION ALL SELECT shell_module_schema(name),"
|
||||
" 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list", 0);
|
||||
" 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list",
|
||||
0);
|
||||
}
|
||||
#endif
|
||||
appendText(&sSelect, ") WHERE ", 0);
|
||||
@@ -8504,7 +8579,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
if( pSession->p==0 ) goto session_not_open;
|
||||
out = fopen(azCmd[1], "wb");
|
||||
if( out==0 ){
|
||||
utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", azCmd[1]);
|
||||
utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n",
|
||||
azCmd[1]);
|
||||
}else{
|
||||
int szChng;
|
||||
void *pChng;
|
||||
@@ -8825,8 +8901,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
{
|
||||
utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
|
||||
azArg[i], azArg[0]);
|
||||
raw_printf(stderr, "Should be one of: --schema"
|
||||
" --sha3-224 --sha3-256 --sha3-384 --sha3-512\n");
|
||||
showHelp(p->out, azArg[0]);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
@@ -8872,8 +8947,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else if( strcmp(zTab, "sqlite_stat1")==0 ){
|
||||
appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1"
|
||||
" ORDER BY tbl,idx;", 0);
|
||||
}else if( strcmp(zTab, "sqlite_stat3")==0
|
||||
|| strcmp(zTab, "sqlite_stat4")==0 ){
|
||||
}else if( strcmp(zTab, "sqlite_stat4")==0 ){
|
||||
appendText(&sQuery, "SELECT * FROM ", 0);
|
||||
appendText(&sQuery, zTab, 0);
|
||||
appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0);
|
||||
@@ -9105,25 +9179,26 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int ctrlCode; /* Integer code for that option */
|
||||
const char *zUsage; /* Usage notes */
|
||||
} aCtrl[] = {
|
||||
{ "always", SQLITE_TESTCTRL_ALWAYS, "BOOLEAN" },
|
||||
{ "assert", SQLITE_TESTCTRL_ASSERT, "BOOLEAN" },
|
||||
/*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, "" },*/
|
||||
/*{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, "" },*/
|
||||
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER, "" },
|
||||
/*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, "" }, */
|
||||
{ "imposter", SQLITE_TESTCTRL_IMPOSTER, "SCHEMA ON/OFF ROOTPAGE"},
|
||||
{ "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, "BOOLEAN" },
|
||||
{ "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN" },
|
||||
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN" },
|
||||
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK" },
|
||||
{ "always", SQLITE_TESTCTRL_ALWAYS, "BOOLEAN" },
|
||||
{ "assert", SQLITE_TESTCTRL_ASSERT, "BOOLEAN" },
|
||||
/*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, "" },*/
|
||||
/*{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, "" },*/
|
||||
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER, "" },
|
||||
{ "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,"BOOLEAN" },
|
||||
/*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, "" },*/
|
||||
{ "imposter", SQLITE_TESTCTRL_IMPOSTER, "SCHEMA ON/OFF ROOTPAGE"},
|
||||
{ "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, "BOOLEAN" },
|
||||
{ "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN" },
|
||||
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN" },
|
||||
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK" },
|
||||
#ifdef YYCOVERAGE
|
||||
{ "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE, "" },
|
||||
{ "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE, "" },
|
||||
#endif
|
||||
{ "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE, "OFFSET " },
|
||||
{ "prng_reset", SQLITE_TESTCTRL_PRNG_RESET, "" },
|
||||
{ "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" },
|
||||
{ "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, "" },
|
||||
{ "reserve", SQLITE_TESTCTRL_RESERVE, "BYTES-OF-RESERVE" },
|
||||
{ "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE, "OFFSET " },
|
||||
{ "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" },
|
||||
{ "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, "" },
|
||||
{ "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, "SEED ?db?" },
|
||||
{ "reserve", SQLITE_TESTCTRL_RESERVE, "BYTES-OF-RESERVE"},
|
||||
};
|
||||
int testctrl = -1;
|
||||
int iCtrl = -1;
|
||||
@@ -9204,6 +9279,27 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
break;
|
||||
|
||||
/* sqlite3_test_control(int, int, sqlite3*) */
|
||||
case SQLITE_TESTCTRL_PRNG_SEED:
|
||||
if( nArg==3 || nArg==4 ){
|
||||
int ii = (int)integerValue(azArg[2]);
|
||||
sqlite3 *db;
|
||||
if( ii==0 && strcmp(azArg[2],"random")==0 ){
|
||||
sqlite3_randomness(sizeof(ii),&ii);
|
||||
printf("-- random seed: %d\n", ii);
|
||||
}
|
||||
if( nArg==3 ){
|
||||
db = 0;
|
||||
}else{
|
||||
db = p->db;
|
||||
/* Make sure the schema has been loaded */
|
||||
sqlite3_table_column_metadata(db, 0, "x", 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
rc2 = sqlite3_test_control(testctrl, ii, db);
|
||||
isOk = 3;
|
||||
}
|
||||
break;
|
||||
|
||||
/* sqlite3_test_control(int, int) */
|
||||
case SQLITE_TESTCTRL_ASSERT:
|
||||
case SQLITE_TESTCTRL_ALWAYS:
|
||||
@@ -9245,7 +9341,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}
|
||||
if( isOk==0 && iCtrl>=0 ){
|
||||
utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd, aCtrl[iCtrl].zUsage);
|
||||
utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
|
||||
rc = 1;
|
||||
}else if( isOk==1 ){
|
||||
raw_printf(p->out, "%d\n", rc2);
|
||||
@@ -9323,6 +9419,31 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else
|
||||
#endif /* !defined(SQLITE_OMIT_TRACE) */
|
||||
|
||||
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
if( c=='u' && strncmp(azArg[0], "unmodule", n)==0 ){
|
||||
int ii;
|
||||
int lenOpt;
|
||||
char *zOpt;
|
||||
if( nArg<2 ){
|
||||
raw_printf(stderr, "Usage: .unmodule [--allexcept] NAME ...\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
open_db(p, 0);
|
||||
zOpt = azArg[1];
|
||||
if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++;
|
||||
lenOpt = (int)strlen(zOpt);
|
||||
if( lenOpt>=3 && strncmp(zOpt, "-allexcept",lenOpt)==0 ){
|
||||
assert( azArg[nArg]==0 );
|
||||
sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0);
|
||||
}else{
|
||||
for(ii=1; ii<nArg; ii++){
|
||||
sqlite3_create_module(p->db, azArg[ii], 0, 0);
|
||||
}
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
|
||||
if( nArg<2 ){
|
||||
@@ -9337,7 +9458,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], strlen30(azArg[3]));
|
||||
rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
|
||||
strlen30(azArg[3]));
|
||||
if( rc ){
|
||||
utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
|
||||
rc = 1;
|
||||
|
||||
+70
-5
@@ -2093,6 +2093,17 @@ struct sqlite3_mem_methods {
|
||||
** following this call. The second parameter may be a NULL pointer, in
|
||||
** which case the trigger setting is not reported back. </dd>
|
||||
**
|
||||
** [[SQLITE_DBCONFIG_ENABLE_VIEW]]
|
||||
** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt>
|
||||
** <dd> ^This option is used to enable or disable [CREATE VIEW | views].
|
||||
** There should be two additional arguments.
|
||||
** The first argument is an integer which is 0 to disable views,
|
||||
** positive to enable views or negative to leave the setting unchanged.
|
||||
** The second parameter is a pointer to an integer into which
|
||||
** is written 0 or 1 to indicate whether views are disabled or enabled
|
||||
** following this call. The second parameter may be a NULL pointer, in
|
||||
** which case the view setting is not reported back. </dd>
|
||||
**
|
||||
** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
|
||||
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
|
||||
** <dd> ^This option is used to enable or disable the
|
||||
@@ -2265,7 +2276,8 @@ struct sqlite3_mem_methods {
|
||||
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */
|
||||
#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */
|
||||
#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */
|
||||
#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */
|
||||
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
|
||||
#define SQLITE_DBCONFIG_MAX 1015 /* Largest DBCONFIG */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Enable Or Disable Extended Result Codes
|
||||
@@ -3814,7 +3826,7 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
** ^The specific value of WHERE-clause [parameter] might influence the
|
||||
** choice of query plan if the parameter is the left-hand side of a [LIKE]
|
||||
** or [GLOB] operator or if the parameter is compared to an indexed column
|
||||
** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
|
||||
** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
|
||||
** </li>
|
||||
** </ol>
|
||||
**
|
||||
@@ -4849,6 +4861,12 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
** perform additional optimizations on deterministic functions, so use
|
||||
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
|
||||
**
|
||||
** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY]
|
||||
** flag, which if present prevents the function from being invoked from
|
||||
** within VIEWs or TRIGGERs. For security reasons, the [SQLITE_DIRECTONLY]
|
||||
** flag is recommended for any application-defined SQL function that has
|
||||
** side-effects.
|
||||
**
|
||||
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
|
||||
** function can gain access to this pointer using [sqlite3_user_data()].)^
|
||||
**
|
||||
@@ -4965,8 +4983,30 @@ int sqlite3_create_window_function(
|
||||
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
|
||||
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
|
||||
** [sqlite3_create_function_v2()].
|
||||
**
|
||||
** The SQLITE_DETERMINISTIC flag means that the new function will always
|
||||
** maps the same inputs into the same output. The abs() function is
|
||||
** deterministic, for example, but randomblob() is not.
|
||||
**
|
||||
** The SQLITE_DIRECTONLY flag means that the function may only be invoked
|
||||
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs. This is
|
||||
** a security feature which is recommended for all
|
||||
** [application-defined SQL functions] that have side-effects. This flag
|
||||
** prevents an attacker from adding triggers and views to a schema then
|
||||
** tricking a high-privilege application into causing unintended side-effects
|
||||
** while performing ordinary queries.
|
||||
**
|
||||
** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
|
||||
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
|
||||
** Specifying this flag makes no difference for scalar or aggregate user
|
||||
** functions. However, if it is not specified for a user-defined window
|
||||
** function, then any sub-types belonging to arguments passed to the window
|
||||
** function may be discarded before the window function is called (i.e.
|
||||
** sqlite3_value_subtype() will always return 0).
|
||||
*/
|
||||
#define SQLITE_DETERMINISTIC 0x800
|
||||
#define SQLITE_DETERMINISTIC 0x000000800
|
||||
#define SQLITE_DIRECTONLY 0x000080000
|
||||
#define SQLITE_SUBTYPE 0x000100000
|
||||
|
||||
/*
|
||||
** CAPI3REF: Deprecated Functions
|
||||
@@ -6612,6 +6652,12 @@ struct sqlite3_index_info {
|
||||
** ^The sqlite3_create_module()
|
||||
** interface is equivalent to sqlite3_create_module_v2() with a NULL
|
||||
** destructor.
|
||||
**
|
||||
** ^If the third parameter (the pointer to the sqlite3_module object) is
|
||||
** NULL then no new module is create and any existing modules with the
|
||||
** same name are dropped.
|
||||
**
|
||||
** See also: [sqlite3_drop_modules()]
|
||||
*/
|
||||
int sqlite3_create_module(
|
||||
sqlite3 *db, /* SQLite connection to register module with */
|
||||
@@ -6627,6 +6673,23 @@ int sqlite3_create_module_v2(
|
||||
void(*xDestroy)(void*) /* Module destructor function */
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Remove Unnecessary Virtual Table Implementations
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_drop_modules(D,L) interface removes all virtual
|
||||
** table modules from database connection D except those named on list L.
|
||||
** The L parameter must be either NULL or a pointer to an array of pointers
|
||||
** to strings where the array is terminated by a single NULL pointer.
|
||||
** ^If the L parameter is NULL, then all virtual table modules are removed.
|
||||
**
|
||||
** See also: [sqlite3_create_module()]
|
||||
*/
|
||||
int sqlite3_drop_modules(
|
||||
sqlite3 *db, /* Remove modules from this connection */
|
||||
const char **azKeep /* Except, do not remove the ones named here */
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Virtual Table Instance Object
|
||||
** KEYWORDS: sqlite3_vtab
|
||||
@@ -7335,7 +7398,7 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_FIRST 5
|
||||
#define SQLITE_TESTCTRL_PRNG_SAVE 5
|
||||
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
|
||||
#define SQLITE_TESTCTRL_PRNG_RESET 7
|
||||
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
|
||||
#define SQLITE_TESTCTRL_BITVEC_TEST 8
|
||||
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
|
||||
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
|
||||
@@ -7358,7 +7421,9 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_IMPOSTER 25
|
||||
#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
|
||||
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
|
||||
#define SQLITE_TESTCTRL_LAST 27 /* Largest TESTCTRL */
|
||||
#define SQLITE_TESTCTRL_PRNG_SEED 28
|
||||
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
|
||||
#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQL Keyword Checking
|
||||
|
||||
@@ -322,6 +322,8 @@ struct sqlite3_api_routines {
|
||||
/* Version 3.28.0 and later */
|
||||
int (*stmt_isexplain)(sqlite3_stmt*);
|
||||
int (*value_frombind)(sqlite3_value*);
|
||||
/* Version 3.30.0 and later */
|
||||
int (*drop_modules)(sqlite3*,const char**);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -614,6 +616,8 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
/* Version 3.28.0 and later */
|
||||
#define sqlite3_stmt_isexplain sqlite3_api->isexplain
|
||||
#define sqlite3_value_frombind sqlite3_api->frombind
|
||||
/* Version 3.30.0 and later */
|
||||
#define sqlite3_drop_modules sqlite3_api->drop_modules
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
+115
-85
@@ -212,15 +212,15 @@
|
||||
** So we have to define the macros in different ways depending on the
|
||||
** compiler.
|
||||
*/
|
||||
#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
|
||||
#if defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
|
||||
#elif defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
|
||||
#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
|
||||
#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
|
||||
#else /* Generates a warning - but it always works */
|
||||
# define SQLITE_INT_TO_PTR(X) ((void*)(X))
|
||||
# define SQLITE_PTR_TO_INT(X) ((int)(X))
|
||||
@@ -935,20 +935,6 @@ typedef INT16_TYPE LogEst;
|
||||
# define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Only one of SQLITE_ENABLE_STAT3 or SQLITE_ENABLE_STAT4 can be defined.
|
||||
** Priority is given to SQLITE_ENABLE_STAT4. If either are defined, also
|
||||
** define SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
# undef SQLITE_ENABLE_STAT3
|
||||
# define SQLITE_ENABLE_STAT3_OR_STAT4 1
|
||||
#elif SQLITE_ENABLE_STAT3
|
||||
# define SQLITE_ENABLE_STAT3_OR_STAT4 1
|
||||
#elif SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
# undef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#endif
|
||||
|
||||
/*
|
||||
** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
|
||||
** the Select query generator tracing logic is turned on.
|
||||
@@ -1412,6 +1398,7 @@ struct sqlite3 {
|
||||
unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
|
||||
unsigned imposterTable : 1; /* Building an imposter table */
|
||||
unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */
|
||||
char **azInit; /* "type", "name", and "tbl_name" columns */
|
||||
} init;
|
||||
int nVdbeActive; /* Number of VDBEs currently running */
|
||||
int nVdbeRead; /* Number of active VDBEs that read or write */
|
||||
@@ -1550,16 +1537,17 @@ struct sqlite3 {
|
||||
#define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */
|
||||
#define SQLITE_DqsDDL 0x20000000 /* dbl-quoted strings allowed in DDL*/
|
||||
#define SQLITE_DqsDML 0x40000000 /* dbl-quoted strings allowed in DML*/
|
||||
#define SQLITE_EnableView 0x80000000 /* Enable the use of views */
|
||||
|
||||
/* Flags used only if debugging */
|
||||
#define HI(X) ((u64)(X)<<32)
|
||||
#ifdef SQLITE_DEBUG
|
||||
#define SQLITE_SqlTrace HI(0x0001) /* Debug print SQL as it executes */
|
||||
#define SQLITE_VdbeListing HI(0x0002) /* Debug listings of VDBE progs */
|
||||
#define SQLITE_VdbeTrace HI(0x0004) /* True to trace VDBE execution */
|
||||
#define SQLITE_VdbeAddopTrace HI(0x0008) /* Trace sqlite3VdbeAddOp() calls */
|
||||
#define SQLITE_VdbeEQP HI(0x0010) /* Debug EXPLAIN QUERY PLAN */
|
||||
#define SQLITE_ParserTrace HI(0x0020) /* PRAGMA parser_trace=ON */
|
||||
#define SQLITE_SqlTrace HI(0x0100000) /* Debug print SQL as it executes */
|
||||
#define SQLITE_VdbeListing HI(0x0200000) /* Debug listings of VDBE progs */
|
||||
#define SQLITE_VdbeTrace HI(0x0400000) /* True to trace VDBE execution */
|
||||
#define SQLITE_VdbeAddopTrace HI(0x0800000) /* Trace sqlite3VdbeAddOp() calls */
|
||||
#define SQLITE_VdbeEQP HI(0x1000000) /* Debug EXPLAIN QUERY PLAN */
|
||||
#define SQLITE_ParserTrace HI(0x2000000) /* PRAGMA parser_trace=ON */
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1587,8 +1575,8 @@ struct sqlite3 {
|
||||
#define SQLITE_OmitNoopJoin 0x0100 /* Omit unused tables in joins */
|
||||
#define SQLITE_CountOfView 0x0200 /* The count-of-view optimization */
|
||||
#define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */
|
||||
#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */
|
||||
/* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */
|
||||
#define SQLITE_Stat4 0x0800 /* Use STAT4 data */
|
||||
/* TH3 expects the Stat4 ^^^^^^ value to be 0x0800. Don't change it */
|
||||
#define SQLITE_PushDown 0x1000 /* The push-down optimization */
|
||||
#define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */
|
||||
#define SQLITE_SkipScan 0x4000 /* Skip-scans */
|
||||
@@ -1676,6 +1664,7 @@ struct FuncDestructor {
|
||||
** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
|
||||
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
|
||||
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
|
||||
** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
|
||||
** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API
|
||||
*/
|
||||
#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
|
||||
@@ -1696,6 +1685,8 @@ struct FuncDestructor {
|
||||
#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */
|
||||
#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
|
||||
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
|
||||
#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
|
||||
#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */
|
||||
|
||||
/*
|
||||
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
|
||||
@@ -1809,6 +1800,7 @@ struct Savepoint {
|
||||
struct Module {
|
||||
const sqlite3_module *pModule; /* Callback pointers */
|
||||
const char *zName; /* Name passed to create_module() */
|
||||
int nRefModule; /* Number of pointers to this object */
|
||||
void *pAux; /* pAux passed to create_module() */
|
||||
void (*xDestroy)(void *); /* Module destructor function */
|
||||
Table *pEpoTab; /* Eponymous table for this module */
|
||||
@@ -1874,11 +1866,12 @@ struct CollSeq {
|
||||
** Note also that the numeric types are grouped together so that testing
|
||||
** for a numeric type is a single comparison. And the BLOB type is first.
|
||||
*/
|
||||
#define SQLITE_AFF_BLOB 'A'
|
||||
#define SQLITE_AFF_TEXT 'B'
|
||||
#define SQLITE_AFF_NUMERIC 'C'
|
||||
#define SQLITE_AFF_INTEGER 'D'
|
||||
#define SQLITE_AFF_REAL 'E'
|
||||
#define SQLITE_AFF_NONE 0x40 /* '@' */
|
||||
#define SQLITE_AFF_BLOB 0x41 /* 'A' */
|
||||
#define SQLITE_AFF_TEXT 0x42 /* 'B' */
|
||||
#define SQLITE_AFF_NUMERIC 0x43 /* 'C' */
|
||||
#define SQLITE_AFF_INTEGER 0x44 /* 'D' */
|
||||
#define SQLITE_AFF_REAL 0x45 /* 'E' */
|
||||
|
||||
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
|
||||
|
||||
@@ -2146,10 +2139,16 @@ struct KeyInfo {
|
||||
u16 nKeyField; /* Number of key columns in the index */
|
||||
u16 nAllField; /* Total columns, including key plus others */
|
||||
sqlite3 *db; /* The database connection */
|
||||
u8 *aSortOrder; /* Sort order for each column. */
|
||||
u8 *aSortFlags; /* Sort order for each column. */
|
||||
CollSeq *aColl[1]; /* Collating sequence for each term of the key */
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed bit values for entries in the KeyInfo.aSortFlags[] array.
|
||||
*/
|
||||
#define KEYINFO_ORDER_DESC 0x01 /* DESC sort order */
|
||||
#define KEYINFO_ORDER_BIGNULL 0x02 /* NULL is larger than any other value */
|
||||
|
||||
/*
|
||||
** This object holds a record which has been parsed out into individual
|
||||
** fields, for the purposes of doing a comparison.
|
||||
@@ -2257,7 +2256,7 @@ struct Index {
|
||||
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
|
||||
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
|
||||
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int nSample; /* Number of elements in aSample[] */
|
||||
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
|
||||
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
|
||||
@@ -2289,7 +2288,7 @@ struct Index {
|
||||
#define XN_EXPR (-2) /* Indexed column is an expression */
|
||||
|
||||
/*
|
||||
** Each sample stored in the sqlite_stat3 table is represented in memory
|
||||
** Each sample stored in the sqlite_stat4 table is represented in memory
|
||||
** using a structure of this type. See documentation at the top of the
|
||||
** analyze.c source file for additional information.
|
||||
*/
|
||||
@@ -2447,7 +2446,7 @@ typedef int ynVar;
|
||||
*/
|
||||
struct Expr {
|
||||
u8 op; /* Operation performed by this node */
|
||||
char affinity; /* The affinity of the column or 0 if not a column */
|
||||
char affExpr; /* affinity, or RAISE type */
|
||||
u32 flags; /* Various flags. EP_* See below */
|
||||
union {
|
||||
char *zToken; /* Token value. Zero terminated and dequoted */
|
||||
@@ -2478,6 +2477,8 @@ struct Expr {
|
||||
** TK_REGISTER: register number
|
||||
** TK_TRIGGER: 1 -> new, 0 -> old
|
||||
** EP_Unlikely: 134217728 times likelihood
|
||||
** TK_IN: ephemerial table holding RHS
|
||||
** TK_SELECT_COLUMN: Number of columns on the LHS
|
||||
** TK_SELECT: 1st register of result vector */
|
||||
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
|
||||
** TK_VARIABLE: variable number (always >= 1).
|
||||
@@ -2491,7 +2492,7 @@ struct Expr {
|
||||
union {
|
||||
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
|
||||
** for a column of an index on an expression */
|
||||
Window *pWin; /* TK_FUNCTION: Window definition for the func */
|
||||
Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */
|
||||
struct { /* TK_IN, TK_SELECT, and TK_EXISTS */
|
||||
int iAddr; /* Subroutine entry address */
|
||||
int regReturn; /* Register used to hold return address */
|
||||
@@ -2506,36 +2507,37 @@ struct Expr {
|
||||
** EP_Agg == NC_HasAgg == SF_HasAgg
|
||||
** EP_Win == NC_HasWin
|
||||
*/
|
||||
#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
|
||||
#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */
|
||||
#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */
|
||||
#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */
|
||||
#define EP_Agg 0x000010 /* Contains one or more aggregate functions */
|
||||
#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
|
||||
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
|
||||
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
|
||||
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
|
||||
#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
|
||||
#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
|
||||
#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
|
||||
#define EP_Skip 0x001000 /* Operator does not contribute to affinity */
|
||||
#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
|
||||
#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
|
||||
#define EP_Win 0x008000 /* Contains window functions */
|
||||
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
|
||||
#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
|
||||
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
|
||||
#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
|
||||
#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
|
||||
#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
|
||||
#define EP_Alias 0x400000 /* Is an alias for a result set column */
|
||||
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
|
||||
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
|
||||
#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
|
||||
#define EP_Quoted 0x4000000 /* TK_ID was originally quoted */
|
||||
#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
|
||||
#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
|
||||
#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
|
||||
#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
|
||||
#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */
|
||||
#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */
|
||||
#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */
|
||||
#define EP_Agg 0x000010 /* Contains one or more aggregate functions */
|
||||
#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
|
||||
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
|
||||
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
|
||||
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
|
||||
/* 0x000200 Available for reuse */
|
||||
#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
|
||||
#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
|
||||
#define EP_Skip 0x001000 /* Operator does not contribute to affinity */
|
||||
#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
|
||||
#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
|
||||
#define EP_Win 0x008000 /* Contains window functions */
|
||||
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
|
||||
#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
|
||||
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
|
||||
#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
|
||||
#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
|
||||
#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
|
||||
#define EP_Alias 0x400000 /* Is an alias for a result set column */
|
||||
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
|
||||
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
|
||||
#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
|
||||
#define EP_Quoted 0x4000000 /* TK_ID was originally quoted */
|
||||
#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
|
||||
#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
|
||||
#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
|
||||
#define EP_Indirect 0x40000000 /* Contained within a TRIGGER or a VIEW */
|
||||
|
||||
/*
|
||||
** The EP_Propagate mask is a set of properties that automatically propagate
|
||||
@@ -2579,6 +2581,18 @@ struct Expr {
|
||||
*/
|
||||
#define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */
|
||||
|
||||
/*
|
||||
** True if the expression passed as an argument was a function with
|
||||
** an OVER() clause (a window function).
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_WINDOWFUNC
|
||||
# define IsWindowFunc(p) 0
|
||||
#else
|
||||
# define IsWindowFunc(p) ( \
|
||||
ExprHasProperty((p), EP_WinFunc) && p->y.pWin->eFrmType!=TK_FILTER \
|
||||
)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A list of expressions. Each expression may optionally have a
|
||||
** name. An expr/name combination can be used in several ways, such
|
||||
@@ -2601,11 +2615,12 @@ struct ExprList {
|
||||
Expr *pExpr; /* The parse tree for this expression */
|
||||
char *zName; /* Token associated with this expression */
|
||||
char *zSpan; /* Original text of the expression */
|
||||
u8 sortOrder; /* 1 for DESC or 0 for ASC */
|
||||
u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */
|
||||
unsigned done :1; /* A flag to indicate when processing is finished */
|
||||
unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
|
||||
unsigned reusable :1; /* Constant expression is reusable */
|
||||
unsigned bSorterRef :1; /* Defer evaluation until after sorting */
|
||||
unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */
|
||||
union {
|
||||
struct {
|
||||
u16 iOrderByCol; /* For ORDER BY, column number in result set */
|
||||
@@ -2896,6 +2911,7 @@ struct Select {
|
||||
#define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */
|
||||
#define SF_IncludeHidden 0x20000 /* Include hidden columns in output */
|
||||
#define SF_ComplexResult 0x40000 /* Result contains subquery or function */
|
||||
#define SF_WhereBegin 0x80000 /* Really a WhereBegin() call. Debug Only */
|
||||
|
||||
/*
|
||||
** The results of a SELECT can be distributed in several ways, as defined
|
||||
@@ -3400,11 +3416,12 @@ typedef struct {
|
||||
*/
|
||||
struct Sqlite3Config {
|
||||
int bMemstat; /* True to enable memory status */
|
||||
int bCoreMutex; /* True to enable core mutexing */
|
||||
int bFullMutex; /* True to enable full mutexing */
|
||||
int bOpenUri; /* True to interpret filenames as URIs */
|
||||
int bUseCis; /* Use covering indices for full-scans */
|
||||
int bSmallMalloc; /* Avoid large memory allocations if true */
|
||||
u8 bCoreMutex; /* True to enable core mutexing */
|
||||
u8 bFullMutex; /* True to enable full mutexing */
|
||||
u8 bOpenUri; /* True to interpret filenames as URIs */
|
||||
u8 bUseCis; /* Use covering indices for full-scans */
|
||||
u8 bSmallMalloc; /* Avoid large memory allocations if true */
|
||||
u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
|
||||
int mxStrlen; /* Maximum string length */
|
||||
int neverCorrupt; /* Database is always well-formed */
|
||||
int szLookaside; /* Default lookaside buffer size */
|
||||
@@ -3456,6 +3473,7 @@ struct Sqlite3Config {
|
||||
int bInternalFunctions; /* Internal SQL functions are visible */
|
||||
int iOnceResetThreshold; /* When to reset OP_Once counters */
|
||||
u32 szSorterRef; /* Min size in bytes to use sorter-refs */
|
||||
unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3552,10 +3570,11 @@ struct TreeView {
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** This object is used in various ways, all related to window functions
|
||||
** This object is used in various ways, most (but not all) related to window
|
||||
** functions.
|
||||
**
|
||||
** (1) A single instance of this structure is attached to the
|
||||
** the Expr.pWin field for each window function in an expression tree.
|
||||
** the Expr.y.pWin field for each window function in an expression tree.
|
||||
** This object holds the information contained in the OVER clause,
|
||||
** plus additional fields used during code generation.
|
||||
**
|
||||
@@ -3566,6 +3585,10 @@ struct TreeView {
|
||||
** (3) The terms of the WINDOW clause of a SELECT are instances of this
|
||||
** object on a linked list attached to Select.pWinDefn.
|
||||
**
|
||||
** (4) For an aggregate function with a FILTER clause, an instance
|
||||
** of this object is stored in Expr.y.pWin with eFrmType set to
|
||||
** TK_FILTER. In this case the only field used is Window.pFilter.
|
||||
**
|
||||
** The uses (1) and (2) are really the same Window object that just happens
|
||||
** to be accessible in two different ways. Use case (3) are separate objects.
|
||||
*/
|
||||
@@ -3581,12 +3604,13 @@ struct Window {
|
||||
u8 eExclude; /* TK_NO, TK_CURRENT, TK_TIES, TK_GROUP, or 0 */
|
||||
Expr *pStart; /* Expression for "<expr> PRECEDING" */
|
||||
Expr *pEnd; /* Expression for "<expr> FOLLOWING" */
|
||||
Window **ppThis; /* Pointer to this object in Select.pWin list */
|
||||
Window *pNextWin; /* Next window function belonging to this SELECT */
|
||||
Expr *pFilter; /* The FILTER expression */
|
||||
FuncDef *pFunc; /* The function */
|
||||
int iEphCsr; /* Partition buffer or Peer buffer */
|
||||
int regAccum;
|
||||
int regResult;
|
||||
int regAccum; /* Accumulator */
|
||||
int regResult; /* Interim result */
|
||||
int csrApp; /* Function cursor (used by min/max) */
|
||||
int regApp; /* Function register (also used by min/max) */
|
||||
int regPart; /* Array of registers for PARTITION BY values */
|
||||
@@ -3596,14 +3620,18 @@ struct Window {
|
||||
int regOne; /* Register containing constant value 1 */
|
||||
int regStartRowid;
|
||||
int regEndRowid;
|
||||
u8 bExprArgs; /* Defer evaluation of window function arguments
|
||||
** due to the SQLITE_SUBTYPE flag */
|
||||
};
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
void sqlite3WindowDelete(sqlite3*, Window*);
|
||||
void sqlite3WindowUnlinkFromSelect(Window*);
|
||||
void sqlite3WindowListDelete(sqlite3 *db, Window *p);
|
||||
Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
|
||||
void sqlite3WindowAttach(Parse*, Expr*, Window*);
|
||||
int sqlite3WindowCompare(Parse*, Window*, Window*);
|
||||
void sqlite3WindowLink(Select *pSel, Window *pWin);
|
||||
int sqlite3WindowCompare(Parse*, Window*, Window*, int);
|
||||
void sqlite3WindowCodeInit(Parse*, Window*);
|
||||
void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
|
||||
int sqlite3WindowRewrite(Parse*, Select*);
|
||||
@@ -3875,7 +3903,7 @@ void sqlite3ExprDelete(sqlite3*, Expr*);
|
||||
void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
|
||||
ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
|
||||
ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
|
||||
void sqlite3ExprListSetSortOrder(ExprList*,int);
|
||||
void sqlite3ExprListSetSortOrder(ExprList*,int,int);
|
||||
void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
|
||||
void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
|
||||
void sqlite3ExprListDelete(sqlite3*, ExprList*);
|
||||
@@ -3894,8 +3922,8 @@ void sqlite3CollapseDatabaseArray(sqlite3*);
|
||||
void sqlite3CommitInternalChanges(sqlite3*);
|
||||
void sqlite3DeleteColumnNames(sqlite3*,Table*);
|
||||
int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
|
||||
void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*);
|
||||
Table *sqlite3ResultSetOfSelect(Parse*,Select*);
|
||||
void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char);
|
||||
Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
|
||||
void sqlite3OpenMasterTable(Parse *, int);
|
||||
Index *sqlite3PrimaryKeyIndex(Table*);
|
||||
i16 sqlite3ColumnOfIndex(Index*, i16);
|
||||
@@ -4196,7 +4224,7 @@ LogEst sqlite3LogEstAdd(LogEst,LogEst);
|
||||
LogEst sqlite3LogEstFromDouble(double);
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
|
||||
defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
|
||||
defined(SQLITE_ENABLE_STAT4) || \
|
||||
defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
|
||||
u64 sqlite3LogEstToInt(LogEst);
|
||||
#endif
|
||||
@@ -4262,9 +4290,10 @@ int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*);
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
|
||||
Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
|
||||
Expr *sqlite3ExprSkipCollate(Expr*);
|
||||
Expr *sqlite3ExprSkipCollateAndLikely(Expr*);
|
||||
int sqlite3CheckCollSeq(Parse *, CollSeq *);
|
||||
int sqlite3WritableSchema(sqlite3*);
|
||||
int sqlite3CheckObjectName(Parse *, const char *);
|
||||
int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*);
|
||||
void sqlite3VdbeSetChanges(sqlite3 *, int);
|
||||
int sqlite3AddInt64(i64*,i64);
|
||||
int sqlite3SubInt64(i64*,i64);
|
||||
@@ -4297,7 +4326,6 @@ extern const unsigned char sqlite3OpcodeProperty[];
|
||||
extern const char sqlite3StrBINARY[];
|
||||
extern const unsigned char sqlite3UpperToLower[];
|
||||
extern const unsigned char sqlite3CtypeMap[];
|
||||
extern const Token sqlite3IntTokens[];
|
||||
extern SQLITE_WSD struct Sqlite3Config sqlite3Config;
|
||||
extern FuncDefHash sqlite3BuiltinFunctions;
|
||||
#ifndef SQLITE_OMIT_WSD
|
||||
@@ -4351,6 +4379,7 @@ void sqlite3KeyInfoUnref(KeyInfo*);
|
||||
KeyInfo *sqlite3KeyInfoRef(KeyInfo*);
|
||||
KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
|
||||
KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int);
|
||||
int sqlite3HasExplicitNulls(Parse*, ExprList*);
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3KeyInfoIsWriteable(KeyInfo*);
|
||||
@@ -4383,8 +4412,7 @@ int sqlite3ExprCheckIN(Parse*, Expr*);
|
||||
# define sqlite3ExprCheckIN(x,y) SQLITE_OK
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
void sqlite3AnalyzeFunctions(void);
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int sqlite3Stat4ProbeSetValue(
|
||||
Parse*,Index*,UnpackedRecord**,Expr*,int,int,int*);
|
||||
int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**);
|
||||
@@ -4431,6 +4459,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
# define sqlite3VtabInSync(db) 0
|
||||
# define sqlite3VtabLock(X)
|
||||
# define sqlite3VtabUnlock(X)
|
||||
# define sqlite3VtabModuleUnref(D,X)
|
||||
# define sqlite3VtabUnlockList(X)
|
||||
# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
|
||||
# define sqlite3GetVTable(X,Y) ((VTable*)0)
|
||||
@@ -4442,6 +4471,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
int sqlite3VtabCommit(sqlite3 *db);
|
||||
void sqlite3VtabLock(VTable *);
|
||||
void sqlite3VtabUnlock(VTable *);
|
||||
void sqlite3VtabModuleUnref(sqlite3*,Module*);
|
||||
void sqlite3VtabUnlockList(sqlite3*);
|
||||
int sqlite3VtabSavepoint(sqlite3 *, int, int);
|
||||
void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
|
||||
|
||||
+102
-24
@@ -1917,33 +1917,33 @@ static int SQLITE_TCLAPI DbObjCmd(
|
||||
"authorizer", "backup", "bind_fallback",
|
||||
"busy", "cache", "changes",
|
||||
"close", "collate", "collation_needed",
|
||||
"commit_hook", "complete", "copy",
|
||||
"deserialize", "enable_load_extension", "errorcode",
|
||||
"eval", "exists", "function",
|
||||
"incrblob", "interrupt", "last_insert_rowid",
|
||||
"nullvalue", "onecolumn", "preupdate",
|
||||
"profile", "progress", "rekey",
|
||||
"restore", "rollback_hook", "serialize",
|
||||
"status", "timeout", "total_changes",
|
||||
"trace", "trace_v2", "transaction",
|
||||
"unlock_notify", "update_hook", "version",
|
||||
"wal_hook", 0
|
||||
"commit_hook", "complete", "config",
|
||||
"copy", "deserialize", "enable_load_extension",
|
||||
"errorcode", "eval", "exists",
|
||||
"function", "incrblob", "interrupt",
|
||||
"last_insert_rowid", "nullvalue", "onecolumn",
|
||||
"preupdate", "profile", "progress",
|
||||
"rekey", "restore", "rollback_hook",
|
||||
"serialize", "status", "timeout",
|
||||
"total_changes", "trace", "trace_v2",
|
||||
"transaction", "unlock_notify", "update_hook",
|
||||
"version", "wal_hook", 0
|
||||
};
|
||||
enum DB_enum {
|
||||
DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK,
|
||||
DB_BUSY, DB_CACHE, DB_CHANGES,
|
||||
DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED,
|
||||
DB_COMMIT_HOOK, DB_COMPLETE, DB_COPY,
|
||||
DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,DB_ERRORCODE,
|
||||
DB_EVAL, DB_EXISTS, DB_FUNCTION,
|
||||
DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID,
|
||||
DB_NULLVALUE, DB_ONECOLUMN, DB_PREUPDATE,
|
||||
DB_PROFILE, DB_PROGRESS, DB_REKEY,
|
||||
DB_RESTORE, DB_ROLLBACK_HOOK, DB_SERIALIZE,
|
||||
DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
|
||||
DB_TRACE, DB_TRACE_V2, DB_TRANSACTION,
|
||||
DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION,
|
||||
DB_WAL_HOOK
|
||||
DB_COMMIT_HOOK, DB_COMPLETE, DB_CONFIG,
|
||||
DB_COPY, DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,
|
||||
DB_ERRORCODE, DB_EVAL, DB_EXISTS,
|
||||
DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT,
|
||||
DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN,
|
||||
DB_PREUPDATE, DB_PROFILE, DB_PROGRESS,
|
||||
DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK,
|
||||
DB_SERIALIZE, DB_STATUS, DB_TIMEOUT,
|
||||
DB_TOTAL_CHANGES, DB_TRACE, DB_TRACE_V2,
|
||||
DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK,
|
||||
DB_VERSION, DB_WAL_HOOK
|
||||
};
|
||||
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
|
||||
|
||||
@@ -2331,6 +2331,74 @@ static int SQLITE_TCLAPI DbObjCmd(
|
||||
break;
|
||||
}
|
||||
|
||||
/* $db config ?OPTION? ?BOOLEAN?
|
||||
**
|
||||
** Configure the database connection using the sqlite3_db_config()
|
||||
** interface.
|
||||
*/
|
||||
case DB_CONFIG: {
|
||||
static const struct DbConfigChoices {
|
||||
const char *zName;
|
||||
int op;
|
||||
} aDbConfig[] = {
|
||||
{ "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
|
||||
{ "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
|
||||
{ "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
|
||||
{ "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
|
||||
{ "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
|
||||
{ "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
|
||||
{ "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
|
||||
{ "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
|
||||
{ "reset_database", SQLITE_DBCONFIG_RESET_DATABASE },
|
||||
{ "defensive", SQLITE_DBCONFIG_DEFENSIVE },
|
||||
{ "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
|
||||
{ "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
|
||||
{ "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
|
||||
{ "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
|
||||
};
|
||||
Tcl_Obj *pResult;
|
||||
int ii;
|
||||
if( objc>4 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?OPTION? ?BOOLEAN?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==2 ){
|
||||
/* With no arguments, list all configuration options and with the
|
||||
** current value */
|
||||
pResult = Tcl_NewListObj(0,0);
|
||||
for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){
|
||||
int v = 0;
|
||||
sqlite3_db_config(pDb->db, aDbConfig[ii].op, -1, &v);
|
||||
Tcl_ListObjAppendElement(interp, pResult,
|
||||
Tcl_NewStringObj(aDbConfig[ii].zName,-1));
|
||||
Tcl_ListObjAppendElement(interp, pResult,
|
||||
Tcl_NewIntObj(v));
|
||||
}
|
||||
}else{
|
||||
const char *zOpt = Tcl_GetString(objv[2]);
|
||||
int onoff = -1;
|
||||
int v = 0;
|
||||
if( zOpt[0]=='-' ) zOpt++;
|
||||
for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){
|
||||
if( strcmp(aDbConfig[ii].zName, zOpt)==0 ) break;
|
||||
}
|
||||
if( ii>=sizeof(aDbConfig)/sizeof(aDbConfig[0]) ){
|
||||
Tcl_AppendResult(interp, "unknown config option: \"", zOpt,
|
||||
"\"", (void*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==4 ){
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
sqlite3_db_config(pDb->db, aDbConfig[ii].op, onoff, &v);
|
||||
pResult = Tcl_NewIntObj(v);
|
||||
}
|
||||
Tcl_SetObjResult(interp, pResult);
|
||||
break;
|
||||
}
|
||||
|
||||
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
|
||||
**
|
||||
** Copy data into table from filename, optionally using SEPARATOR
|
||||
@@ -2741,10 +2809,16 @@ deserialize_error:
|
||||
}
|
||||
|
||||
/*
|
||||
** $db function NAME [-argcount N] [-deterministic] SCRIPT
|
||||
** $db function NAME [OPTIONS] SCRIPT
|
||||
**
|
||||
** Create a new SQL function called NAME. Whenever that function is
|
||||
** called, invoke SCRIPT to evaluate the function.
|
||||
**
|
||||
** Options:
|
||||
** --argcount N Function has exactly N arguments
|
||||
** --deterministic The function is pure
|
||||
** --directonly Prohibit use inside triggers and views
|
||||
** --returntype TYPE Specify the return type of the function
|
||||
*/
|
||||
case DB_FUNCTION: {
|
||||
int flags = SQLITE_UTF8;
|
||||
@@ -2777,6 +2851,9 @@ deserialize_error:
|
||||
if( n>1 && strncmp(z, "-deterministic",n)==0 ){
|
||||
flags |= SQLITE_DETERMINISTIC;
|
||||
}else
|
||||
if( n>1 && strncmp(z, "-directonly",n)==0 ){
|
||||
flags |= SQLITE_DIRECTONLY;
|
||||
}else
|
||||
if( n>1 && strncmp(z, "-returntype", n)==0 ){
|
||||
const char *azType[] = {"integer", "real", "text", "blob", "any", 0};
|
||||
assert( SQLITE_INTEGER==1 && SQLITE_FLOAT==2 && SQLITE_TEXT==3 );
|
||||
@@ -2792,7 +2869,8 @@ deserialize_error:
|
||||
eType++;
|
||||
}else{
|
||||
Tcl_AppendResult(interp, "bad option \"", z,
|
||||
"\": must be -argcount, -deterministic or -returntype", (char*)0
|
||||
"\": must be -argcount, -deterministic, -directonly,"
|
||||
" or -returntype", (char*)0
|
||||
);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
+71
-3
@@ -1110,6 +1110,33 @@ static int SQLITE_TCLAPI test_create_function(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_drop_modules DB ?NAME ...?
|
||||
**
|
||||
** Invoke the sqlite3_drop_modules(D,L) interface on database
|
||||
** connection DB, in order to drop all modules except those named in
|
||||
** the argument.
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_drop_modules(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
){
|
||||
sqlite3 *db;
|
||||
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" DB\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
sqlite3_drop_modules(db, argc>2 ? (const char**)(argv+2) : 0);
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Routines to implement the x_count() aggregate function.
|
||||
**
|
||||
@@ -6373,7 +6400,41 @@ static int SQLITE_TCLAPI reset_prng_state(
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESET);
|
||||
sqlite3_randomness(0,0);
|
||||
return TCL_OK;
|
||||
}
|
||||
/*
|
||||
** tclcmd: prng_seed INT ?DB?
|
||||
**
|
||||
** Set up the SQLITE_TESTCTRL_PRNG_SEED pragma with parameter INT and DB.
|
||||
** INT is an integer. DB is a database connection, or a NULL pointer if
|
||||
** omitted.
|
||||
**
|
||||
** When INT!=0 and DB!=0, set the PRNG seed to the value of the schema
|
||||
** cookie for DB, or to INT if the schema cookie happens to be zero.
|
||||
**
|
||||
** When INT!=0 and DB==0, set the PRNG seed to just INT.
|
||||
**
|
||||
** If INT==0 and DB==0 then use the default procedure of calling the
|
||||
** xRandomness method on the default VFS to get the PRNG seed.
|
||||
*/
|
||||
static int SQLITE_TCLAPI prng_seed(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
int i = 0;
|
||||
sqlite3 *db = 0;
|
||||
if( objc!=2 && objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SEED ?DB?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp,objv[0],&i) ) return TCL_ERROR;
|
||||
if( objc==3 && getDbPointer(interp, Tcl_GetString(objv[2]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, i, db);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -7139,9 +7200,9 @@ static int SQLITE_TCLAPI optimization_control(
|
||||
{ "order-by-idx-join", SQLITE_OrderByIdxJoin },
|
||||
{ "transitive", SQLITE_Transitive },
|
||||
{ "omit-noop-join", SQLITE_OmitNoopJoin },
|
||||
{ "stat3", SQLITE_Stat34 },
|
||||
{ "stat4", SQLITE_Stat34 },
|
||||
{ "stat4", SQLITE_Stat4 },
|
||||
{ "skip-scan", SQLITE_SkipScan },
|
||||
{ "push-down", SQLITE_PushDown },
|
||||
};
|
||||
|
||||
if( objc!=4 ){
|
||||
@@ -7740,6 +7801,11 @@ static int SQLITE_TCLAPI test_decode_hexdb(
|
||||
int pgsz;
|
||||
rc = sscanf(zIn+i, "| size %d pagesize %d", &n, &pgsz);
|
||||
if( rc!=2 ) continue;
|
||||
if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ){
|
||||
Tcl_AppendResult(interp, "bad 'pagesize' field", (void*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */
|
||||
if( n<512 ){
|
||||
Tcl_AppendResult(interp, "bad 'size' field", (void*)0);
|
||||
return TCL_ERROR;
|
||||
@@ -7822,6 +7888,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_close_v2", (Tcl_CmdProc*)sqlite_test_close_v2 },
|
||||
{ "sqlite3_create_function", (Tcl_CmdProc*)test_create_function },
|
||||
{ "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate },
|
||||
{ "sqlite3_drop_modules", (Tcl_CmdProc*)test_drop_modules },
|
||||
{ "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func },
|
||||
{ "sqlite_abort", (Tcl_CmdProc*)sqlite_abort },
|
||||
{ "sqlite_bind", (Tcl_CmdProc*)test_bind },
|
||||
@@ -7918,6 +7985,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "save_prng_state", save_prng_state, 0 },
|
||||
{ "restore_prng_state", restore_prng_state, 0 },
|
||||
{ "reset_prng_state", reset_prng_state, 0 },
|
||||
{ "prng_seed", prng_seed, 0 },
|
||||
{ "database_never_corrupt", database_never_corrupt, 0},
|
||||
{ "database_may_be_corrupt", database_may_be_corrupt, 0},
|
||||
{ "optimization_control", optimization_control,0},
|
||||
|
||||
@@ -585,12 +585,6 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "stat4", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_STAT3) && !defined(SQLITE_ENABLE_STAT4)
|
||||
Tcl_SetVar2(interp, "sqlite_options", "stat3", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "stat3", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_ENABLE_STMTVTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
Tcl_SetVar2(interp, "sqlite_options", "stmtvtab", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
@@ -337,6 +337,17 @@ static int getFts3Varint(const char *p, sqlite_int64 *v){
|
||||
return (int) (q - (unsigned char *)p);
|
||||
}
|
||||
|
||||
static int putFts3Varint(char *p, sqlite_int64 v){
|
||||
unsigned char *q = (unsigned char *) p;
|
||||
sqlite_uint64 vu = v;
|
||||
do{
|
||||
*q++ = (unsigned char) ((vu & 0x7f) | 0x80);
|
||||
vu >>= 7;
|
||||
}while( vu!=0 );
|
||||
q[-1] &= 0x7f; /* turn off high bit in final byte */
|
||||
assert( q - (unsigned char *)p <= 10 );
|
||||
return (int) (q - (unsigned char *)p);
|
||||
}
|
||||
|
||||
/*
|
||||
** USAGE: read_fts3varint BLOB VARNAME
|
||||
@@ -367,6 +378,67 @@ static int SQLITE_TCLAPI read_fts3varint(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** USAGE: make_fts3record ARGLIST
|
||||
*/
|
||||
static int SQLITE_TCLAPI make_fts3record(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
Tcl_Obj **aArg = 0;
|
||||
int nArg = 0;
|
||||
unsigned char *aOut = 0;
|
||||
int nOut = 0;
|
||||
int nAlloc = 0;
|
||||
int i;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "LIST");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_ListObjGetElements(interp, objv[1], &nArg, &aArg) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
for(i=0; i<nArg; i++){
|
||||
sqlite3_int64 iVal;
|
||||
if( TCL_OK==Tcl_GetWideIntFromObj(0, aArg[i], &iVal) ){
|
||||
if( nOut+10>nAlloc ){
|
||||
int nNew = nAlloc?nAlloc*2:128;
|
||||
unsigned char *aNew = sqlite3_realloc(aOut, nNew);
|
||||
if( aNew==0 ){
|
||||
sqlite3_free(aOut);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
aOut = aNew;
|
||||
nAlloc = nNew;
|
||||
}
|
||||
nOut += putFts3Varint((char*)&aOut[nOut], iVal);
|
||||
}else{
|
||||
int nVal = 0;
|
||||
char *zVal = Tcl_GetStringFromObj(aArg[i], &nVal);
|
||||
while( (nOut + nVal)>nAlloc ){
|
||||
int nNew = nAlloc?nAlloc*2:128;
|
||||
unsigned char *aNew = sqlite3_realloc(aOut, nNew);
|
||||
if( aNew==0 ){
|
||||
sqlite3_free(aOut);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
aOut = aNew;
|
||||
nAlloc = nNew;
|
||||
}
|
||||
memcpy(&aOut[nOut], zVal, nVal);
|
||||
nOut += nVal;
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(aOut, nOut));
|
||||
sqlite3_free(aOut);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
@@ -383,6 +455,7 @@ int Sqlitetest_hexio_Init(Tcl_Interp *interp){
|
||||
{ "hexio_render_int32", hexio_render_int32 },
|
||||
{ "utf8_to_utf8", utf8_to_utf8 },
|
||||
{ "read_fts3varint", read_fts3varint },
|
||||
{ "make_fts3record", make_fts3record },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
|
||||
+34
-18
@@ -176,13 +176,17 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
sqlite3TreeViewPush(pView, 1);
|
||||
}
|
||||
do{
|
||||
sqlite3TreeViewLine(pView,
|
||||
"SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d",
|
||||
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
|
||||
((p->selFlags & SF_Aggregate) ? " agg_flag" : ""),
|
||||
p->selId, p, p->selFlags,
|
||||
(int)p->nSelectRow
|
||||
);
|
||||
if( p->selFlags & SF_WhereBegin ){
|
||||
sqlite3TreeViewLine(pView, "sqlite3WhereBegin()");
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView,
|
||||
"SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d",
|
||||
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
|
||||
((p->selFlags & SF_Aggregate) ? " agg_flag" : ""),
|
||||
p->selId, p, p->selFlags,
|
||||
(int)p->nSelectRow
|
||||
);
|
||||
}
|
||||
if( cnt++ ) sqlite3TreeViewPop(pView);
|
||||
if( p->pPrior ){
|
||||
n = 1000;
|
||||
@@ -199,7 +203,10 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
if( p->pWinDefn ) n++;
|
||||
#endif
|
||||
}
|
||||
sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
|
||||
if( p->pEList ){
|
||||
sqlite3TreeViewExprList(pView, p->pEList, n>0, "result-set");
|
||||
}
|
||||
n--;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( p->pWin ){
|
||||
Window *pX;
|
||||
@@ -395,12 +402,14 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
sqlite3TreeViewPop(pView);
|
||||
return;
|
||||
}
|
||||
if( pExpr->flags ){
|
||||
if( pExpr->flags || pExpr->affExpr ){
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x iRJT=%d",
|
||||
pExpr->flags, pExpr->iRightJoinTable);
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," fg.af=%x.%c iRJT=%d",
|
||||
pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n',
|
||||
pExpr->iRightJoinTable);
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," fg.af=%x.%c",
|
||||
pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');
|
||||
}
|
||||
}else{
|
||||
zFlgs[0] = 0;
|
||||
@@ -527,7 +536,14 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
}
|
||||
|
||||
case TK_COLLATE: {
|
||||
sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
|
||||
/* COLLATE operators without the EP_Collate flag are intended to
|
||||
** emulate collation associated with a table column. These show
|
||||
** up in the treeview output as "SOFT-COLLATE". Explicit COLLATE
|
||||
** operators that appear in the original SQL always have the
|
||||
** EP_Collate bit set and appear in treeview output as just "COLLATE" */
|
||||
sqlite3TreeViewLine(pView, "%sCOLLATE %Q%s",
|
||||
!ExprHasProperty(pExpr, EP_Collate) ? "SOFT-" : "",
|
||||
pExpr->u.zToken, zFlgs);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
@@ -548,10 +564,10 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
#endif
|
||||
}
|
||||
if( pExpr->op==TK_AGG_FUNCTION ){
|
||||
sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
|
||||
pExpr->op2, pExpr->u.zToken);
|
||||
sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
|
||||
pExpr->op2, pExpr->u.zToken, zFlgs);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
|
||||
sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs);
|
||||
}
|
||||
if( pFarg ){
|
||||
sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
|
||||
@@ -628,7 +644,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
case TK_RAISE: {
|
||||
const char *zType = "unk";
|
||||
switch( pExpr->affinity ){
|
||||
switch( pExpr->affExpr ){
|
||||
case OE_Rollback: zType = "rollback"; break;
|
||||
case OE_Abort: zType = "abort"; break;
|
||||
case OE_Fail: zType = "fail"; break;
|
||||
@@ -669,7 +685,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
|
||||
}else if( zUniOp ){
|
||||
sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
|
||||
+16
-8
@@ -177,7 +177,11 @@ void sqlite3BeginTrigger(
|
||||
/* Check that the trigger name is not reserved and that no trigger of the
|
||||
** specified name exists */
|
||||
zName = sqlite3NameFromToken(db, pName);
|
||||
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||
if( zName==0 ){
|
||||
assert( db->mallocFailed );
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqlite3CheckObjectName(pParse, zName, "trigger", pTab->zName) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
@@ -340,6 +344,7 @@ void sqlite3FinishTrigger(
|
||||
Trigger *pLink = pTrig;
|
||||
Hash *pHash = &db->aDb[iDb].pSchema->trigHash;
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
assert( pLink!=0 );
|
||||
pTrig = sqlite3HashInsert(pHash, zName, pTrig);
|
||||
if( pTrig ){
|
||||
sqlite3OomFault(db);
|
||||
@@ -458,6 +463,9 @@ TriggerStep *sqlite3TriggerInsertStep(
|
||||
pTriggerStep->pIdList = pColumn;
|
||||
pTriggerStep->pUpsert = pUpsert;
|
||||
pTriggerStep->orconf = orconf;
|
||||
if( pUpsert ){
|
||||
sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget);
|
||||
}
|
||||
}else{
|
||||
testcase( pColumn );
|
||||
sqlite3IdListDelete(db, pColumn);
|
||||
@@ -613,10 +621,9 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
pTable = tableOfTrigger(pTrigger);
|
||||
assert( pTable );
|
||||
assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
|
||||
assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 );
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
if( pTable ){
|
||||
int code = SQLITE_DROP_TRIGGER;
|
||||
const char *zDb = db->aDb[iDb].zDbSName;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
@@ -630,7 +637,6 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
||||
|
||||
/* Generate code to destroy the database record of the trigger.
|
||||
*/
|
||||
assert( pTable!=0 );
|
||||
if( (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
sqlite3NestedParse(pParse,
|
||||
"DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
|
||||
@@ -654,9 +660,11 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
|
||||
if( ALWAYS(pTrigger) ){
|
||||
if( pTrigger->pSchema==pTrigger->pTabSchema ){
|
||||
Table *pTab = tableOfTrigger(pTrigger);
|
||||
Trigger **pp;
|
||||
for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
|
||||
*pp = (*pp)->pNext;
|
||||
if( pTab ){
|
||||
Trigger **pp;
|
||||
for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
|
||||
*pp = (*pp)->pNext;
|
||||
}
|
||||
}
|
||||
sqlite3DeleteTrigger(db, pTrigger);
|
||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
||||
|
||||
+12
-13
@@ -715,28 +715,30 @@ void sqlite3Update(
|
||||
}
|
||||
|
||||
if( !isView ){
|
||||
int addr1 = 0; /* Address of jump instruction */
|
||||
|
||||
/* Do constraint checks. */
|
||||
assert( regOldRowid>0 );
|
||||
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
|
||||
regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace,
|
||||
aXRef, 0);
|
||||
|
||||
/* If REPLACE conflict handling may have been used, or if the PK of the
|
||||
** row is changing, then the GenerateConstraintChecks() above may have
|
||||
** moved cursor iDataCur. Reseek it. */
|
||||
if( bReplace || chngKey ){
|
||||
if( pPk ){
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid);
|
||||
}
|
||||
VdbeCoverageNeverTaken(v);
|
||||
}
|
||||
|
||||
/* Do FK constraint checks. */
|
||||
if( hasFK ){
|
||||
sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey);
|
||||
}
|
||||
|
||||
/* Delete the index entries associated with the current record. */
|
||||
if( bReplace || chngKey ){
|
||||
if( pPk ){
|
||||
addr1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey);
|
||||
}else{
|
||||
addr1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid);
|
||||
}
|
||||
VdbeCoverageNeverTaken(v);
|
||||
}
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);
|
||||
|
||||
/* If changing the rowid value, or if there are foreign key constraints
|
||||
@@ -766,9 +768,6 @@ void sqlite3Update(
|
||||
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
|
||||
}
|
||||
#endif
|
||||
if( bReplace || chngKey ){
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
}
|
||||
|
||||
if( hasFK ){
|
||||
sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey);
|
||||
|
||||
+7
-1
@@ -205,6 +205,7 @@ void sqlite3UpsertDoUpdate(
|
||||
sqlite3 *db = pParse->db;
|
||||
SrcList *pSrc; /* FROM clause for the UPDATE */
|
||||
int iDataCur;
|
||||
int i;
|
||||
|
||||
assert( v!=0 );
|
||||
assert( pUpsert!=0 );
|
||||
@@ -221,7 +222,6 @@ void sqlite3UpsertDoUpdate(
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
int nPk = pPk->nKeyCol;
|
||||
int iPk = pParse->nMem+1;
|
||||
int i;
|
||||
pParse->nMem += nPk;
|
||||
for(i=0; i<nPk; i++){
|
||||
int k;
|
||||
@@ -242,6 +242,12 @@ void sqlite3UpsertDoUpdate(
|
||||
/* pUpsert does not own pUpsertSrc - the outer INSERT statement does. So
|
||||
** we have to make a copy before passing it down into sqlite3Update() */
|
||||
pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0);
|
||||
/* excluded.* columns of type REAL need to be converted to a hard real */
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
|
||||
sqlite3VdbeAddOp1(v, OP_RealAffinity, pUpsert->regData+i);
|
||||
}
|
||||
}
|
||||
sqlite3Update(pParse, pSrc, pUpsert->pUpsertSet,
|
||||
pUpsert->pUpsertWhere, OE_Abort, 0, 0, pUpsert);
|
||||
pUpsert->pUpsertSet = 0; /* Will have been deleted by sqlite3Update() */
|
||||
|
||||
+2
-2
@@ -1498,7 +1498,7 @@ LogEst sqlite3LogEstFromDouble(double x){
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
|
||||
defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
|
||||
defined(SQLITE_ENABLE_STAT4) || \
|
||||
defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
|
||||
/*
|
||||
** Convert a LogEst into an integer.
|
||||
@@ -1516,7 +1516,7 @@ u64 sqlite3LogEstToInt(LogEst x){
|
||||
defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
|
||||
if( x>60 ) return (u64)LARGEST_INT64;
|
||||
#else
|
||||
/* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input
|
||||
/* If only SQLITE_ENABLE_STAT4 is on, then the largest input
|
||||
** possible to this routine is 310, resulting in a maximum x of 31 */
|
||||
assert( x<=60 );
|
||||
#endif
|
||||
|
||||
+163
-53
@@ -343,6 +343,7 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
|
||||
** Convert pRec to a text representation.
|
||||
**
|
||||
** SQLITE_AFF_BLOB:
|
||||
** SQLITE_AFF_NONE:
|
||||
** No-op. pRec is unchanged.
|
||||
*/
|
||||
static void applyAffinity(
|
||||
@@ -482,13 +483,15 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
|
||||
c = 's';
|
||||
}
|
||||
*(zCsr++) = c;
|
||||
*(zCsr++) = 'x';
|
||||
sqlite3_snprintf(100, zCsr, "%d[", pMem->n);
|
||||
zCsr += sqlite3Strlen30(zCsr);
|
||||
for(i=0; i<16 && i<pMem->n; i++){
|
||||
for(i=0; i<25 && i<pMem->n; i++){
|
||||
sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF));
|
||||
zCsr += sqlite3Strlen30(zCsr);
|
||||
}
|
||||
for(i=0; i<16 && i<pMem->n; i++){
|
||||
*zCsr++ = '|';
|
||||
for(i=0; i<25 && i<pMem->n; i++){
|
||||
char z = pMem->z[i];
|
||||
if( z<32 || z>126 ) *zCsr++ = '.';
|
||||
else *zCsr++ = z;
|
||||
@@ -518,7 +521,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
|
||||
sqlite3_snprintf(100, &zBuf[k], "%d", pMem->n);
|
||||
k += sqlite3Strlen30(&zBuf[k]);
|
||||
zBuf[k++] = '[';
|
||||
for(j=0; j<15 && j<pMem->n; j++){
|
||||
for(j=0; j<25 && j<pMem->n; j++){
|
||||
u8 c = pMem->z[j];
|
||||
if( c>=0x20 && c<0x7f ){
|
||||
zBuf[k++] = c;
|
||||
@@ -551,7 +554,7 @@ static void memTracePrint(Mem *p){
|
||||
printf(" i:%lld", p->u.i);
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
}else if( p->flags & MEM_Real ){
|
||||
printf(" r:%g", p->u.r);
|
||||
printf(" r:%.17g", p->u.r);
|
||||
#endif
|
||||
}else if( sqlite3VdbeMemIsRowSet(p) ){
|
||||
printf(" (rowset)");
|
||||
@@ -1140,7 +1143,6 @@ case OP_Real: { /* same as TK_FLOAT, out2 */
|
||||
case OP_String8: { /* same as TK_STRING, out2 */
|
||||
assert( pOp->p4.z!=0 );
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOp->opcode = OP_String;
|
||||
pOp->p1 = sqlite3Strlen30(pOp->p4.z);
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
@@ -1164,6 +1166,7 @@ case OP_String8: { /* same as TK_STRING, out2 */
|
||||
if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
goto too_big;
|
||||
}
|
||||
pOp->opcode = OP_String;
|
||||
assert( rc==SQLITE_OK );
|
||||
/* Fall through to the next case, OP_String */
|
||||
}
|
||||
@@ -1831,6 +1834,7 @@ case OP_RealAffinity: { /* in1 */
|
||||
testcase( pIn1->flags & MEM_Int );
|
||||
testcase( pIn1->flags & MEM_IntReal );
|
||||
sqlite3VdbeMemRealify(pIn1);
|
||||
REGISTER_TRACE(pOp->p1, pIn1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2226,9 +2230,14 @@ case OP_Compare: {
|
||||
REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
|
||||
assert( i<pKeyInfo->nKeyField );
|
||||
pColl = pKeyInfo->aColl[i];
|
||||
bRev = pKeyInfo->aSortOrder[i];
|
||||
bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC);
|
||||
iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
|
||||
if( iCompare ){
|
||||
if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
|
||||
&& ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null))
|
||||
){
|
||||
iCompare = -iCompare;
|
||||
}
|
||||
if( bRev ) iCompare = -iCompare;
|
||||
break;
|
||||
}
|
||||
@@ -2519,11 +2528,6 @@ case OP_Offset: { /* out3 */
|
||||
** if the P4 argument is a P4_MEM use the value of the P4 argument as
|
||||
** the result.
|
||||
**
|
||||
** If the OPFLAG_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor,
|
||||
** then the cache of the cursor is reset prior to extracting the column.
|
||||
** The first OP_Column against a pseudo-table after the value of the content
|
||||
** register has changed should have this bit set.
|
||||
**
|
||||
** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
|
||||
** the result is guaranteed to only be used as the argument of a length()
|
||||
** or typeof() function, respectively. The loading of large blobs can be
|
||||
@@ -2812,15 +2816,27 @@ case OP_Affinity: {
|
||||
assert( pOp->p2>0 );
|
||||
assert( zAffinity[pOp->p2]==0 );
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
while( 1 /*edit-by-break*/ ){
|
||||
while( 1 /*exit-by-break*/ ){
|
||||
assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
|
||||
assert( memIsValid(pIn1) );
|
||||
applyAffinity(pIn1, zAffinity[0], encoding);
|
||||
if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){
|
||||
/* When applying REAL affinity, if the result is still MEM_Int,
|
||||
** indicate that REAL is actually desired */
|
||||
pIn1->flags |= MEM_IntReal;
|
||||
pIn1->flags &= ~MEM_Int;
|
||||
/* When applying REAL affinity, if the result is still an MEM_Int
|
||||
** that will fit in 6 bytes, then change the type to MEM_IntReal
|
||||
** so that we keep the high-resolution integer value but know that
|
||||
** the type really wants to be REAL. */
|
||||
testcase( pIn1->u.i==140737488355328LL );
|
||||
testcase( pIn1->u.i==140737488355327LL );
|
||||
testcase( pIn1->u.i==-140737488355328LL );
|
||||
testcase( pIn1->u.i==-140737488355329LL );
|
||||
if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL ){
|
||||
pIn1->flags |= MEM_IntReal;
|
||||
pIn1->flags &= ~MEM_Int;
|
||||
}else{
|
||||
pIn1->u.r = (double)pIn1->u.i;
|
||||
pIn1->flags |= MEM_Real;
|
||||
pIn1->flags &= ~MEM_Int;
|
||||
}
|
||||
}
|
||||
REGISTER_TRACE((int)(pIn1-aMem), pIn1);
|
||||
zAffinity++;
|
||||
@@ -2927,14 +2943,36 @@ case OP_MakeRecord: {
|
||||
#endif
|
||||
|
||||
/* Loop through the elements that will make up the record to figure
|
||||
** out how much space is required for the new record.
|
||||
** out how much space is required for the new record. After this loop,
|
||||
** the Mem.uTemp field of each term should hold the serial-type that will
|
||||
** be used for that term in the generated record:
|
||||
**
|
||||
** Mem.uTemp value type
|
||||
** --------------- ---------------
|
||||
** 0 NULL
|
||||
** 1 1-byte signed integer
|
||||
** 2 2-byte signed integer
|
||||
** 3 3-byte signed integer
|
||||
** 4 4-byte signed integer
|
||||
** 5 6-byte signed integer
|
||||
** 6 8-byte signed integer
|
||||
** 7 IEEE float
|
||||
** 8 Integer constant 0
|
||||
** 9 Integer constant 1
|
||||
** 10,11 reserved for expansion
|
||||
** N>=12 and even BLOB
|
||||
** N>=13 and odd text
|
||||
**
|
||||
** The following additional values are computed:
|
||||
** nHdr Number of bytes needed for the record header
|
||||
** nData Number of bytes of data space needed for the record
|
||||
** nZero Zero bytes at the end of the record
|
||||
*/
|
||||
pRec = pLast;
|
||||
do{
|
||||
assert( memIsValid(pRec) );
|
||||
serial_type = sqlite3VdbeSerialType(pRec, file_format, &len);
|
||||
if( pRec->flags & MEM_Zero ){
|
||||
if( serial_type==0 ){
|
||||
if( pRec->flags & MEM_Null ){
|
||||
if( pRec->flags & MEM_Zero ){
|
||||
/* Values with MEM_Null and MEM_Zero are created by xColumn virtual
|
||||
** table methods that never invoke sqlite3_result_xxxxx() while
|
||||
** computing an unchanging column value in an UPDATE statement.
|
||||
@@ -2942,19 +2980,83 @@ case OP_MakeRecord: {
|
||||
** so that they can be passed through to xUpdate and have
|
||||
** a true sqlite3_value_nochange(). */
|
||||
assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB );
|
||||
serial_type = 10;
|
||||
}else if( nData ){
|
||||
if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem;
|
||||
pRec->uTemp = 10;
|
||||
}else{
|
||||
nZero += pRec->u.nZero;
|
||||
len -= pRec->u.nZero;
|
||||
pRec->uTemp = 0;
|
||||
}
|
||||
nHdr++;
|
||||
}else if( pRec->flags & (MEM_Int|MEM_IntReal) ){
|
||||
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
|
||||
i64 i = pRec->u.i;
|
||||
u64 uu;
|
||||
testcase( pRec->flags & MEM_Int );
|
||||
testcase( pRec->flags & MEM_IntReal );
|
||||
if( i<0 ){
|
||||
uu = ~i;
|
||||
}else{
|
||||
uu = i;
|
||||
}
|
||||
nHdr++;
|
||||
testcase( uu==127 ); testcase( uu==128 );
|
||||
testcase( uu==32767 ); testcase( uu==32768 );
|
||||
testcase( uu==8388607 ); testcase( uu==8388608 );
|
||||
testcase( uu==2147483647 ); testcase( uu==2147483648 );
|
||||
testcase( uu==140737488355327LL ); testcase( uu==140737488355328LL );
|
||||
if( uu<=127 ){
|
||||
if( (i&1)==i && file_format>=4 ){
|
||||
pRec->uTemp = 8+(u32)uu;
|
||||
}else{
|
||||
nData++;
|
||||
pRec->uTemp = 1;
|
||||
}
|
||||
}else if( uu<=32767 ){
|
||||
nData += 2;
|
||||
pRec->uTemp = 2;
|
||||
}else if( uu<=8388607 ){
|
||||
nData += 3;
|
||||
pRec->uTemp = 3;
|
||||
}else if( uu<=2147483647 ){
|
||||
nData += 4;
|
||||
pRec->uTemp = 4;
|
||||
}else if( uu<=140737488355327LL ){
|
||||
nData += 6;
|
||||
pRec->uTemp = 5;
|
||||
}else{
|
||||
nData += 8;
|
||||
if( pRec->flags & MEM_IntReal ){
|
||||
/* If the value is IntReal and is going to take up 8 bytes to store
|
||||
** as an integer, then we might as well make it an 8-byte floating
|
||||
** point value */
|
||||
pRec->u.r = (double)pRec->u.i;
|
||||
pRec->flags &= ~MEM_IntReal;
|
||||
pRec->flags |= MEM_Real;
|
||||
pRec->uTemp = 7;
|
||||
}else{
|
||||
pRec->uTemp = 6;
|
||||
}
|
||||
}
|
||||
}else if( pRec->flags & MEM_Real ){
|
||||
nHdr++;
|
||||
nData += 8;
|
||||
pRec->uTemp = 7;
|
||||
}else{
|
||||
assert( db->mallocFailed || pRec->flags&(MEM_Str|MEM_Blob) );
|
||||
assert( pRec->n>=0 );
|
||||
len = (u32)pRec->n;
|
||||
serial_type = (len*2) + 12 + ((pRec->flags & MEM_Str)!=0);
|
||||
if( pRec->flags & MEM_Zero ){
|
||||
serial_type += pRec->u.nZero*2;
|
||||
if( nData ){
|
||||
if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem;
|
||||
len += pRec->u.nZero;
|
||||
}else{
|
||||
nZero += pRec->u.nZero;
|
||||
}
|
||||
}
|
||||
nData += len;
|
||||
nHdr += sqlite3VarintLen(serial_type);
|
||||
pRec->uTemp = serial_type;
|
||||
}
|
||||
nData += len;
|
||||
testcase( serial_type==127 );
|
||||
testcase( serial_type==128 );
|
||||
nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
|
||||
pRec->uTemp = serial_type;
|
||||
if( pRec==pData0 ) break;
|
||||
pRec--;
|
||||
}while(1);
|
||||
@@ -3290,7 +3392,7 @@ case OP_AutoCommit: {
|
||||
rc = SQLITE_ERROR;
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
break;
|
||||
/*NOTREACHED*/ assert(0);
|
||||
}
|
||||
|
||||
/* Opcode: Transaction P1 P2 P3 P4 P5
|
||||
@@ -4028,6 +4130,7 @@ case OP_SeekGT: { /* jump, in3, group */
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
if( pC->isTable ){
|
||||
u16 flags3, newType;
|
||||
/* The BTREE_SEEK_EQ flag is only set on index cursors */
|
||||
assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0
|
||||
|| CORRUPT_DB );
|
||||
@@ -4036,18 +4139,21 @@ case OP_SeekGT: { /* jump, in3, group */
|
||||
** blob, or NULL. But it needs to be an integer before we can do
|
||||
** the seek, so convert it. */
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Str))==MEM_Str ){
|
||||
flags3 = pIn3->flags;
|
||||
if( (flags3 & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Str))==MEM_Str ){
|
||||
applyNumericAffinity(pIn3, 0);
|
||||
}
|
||||
iKey = sqlite3VdbeIntValue(pIn3);
|
||||
iKey = sqlite3VdbeIntValue(pIn3); /* Get the integer key value */
|
||||
newType = pIn3->flags; /* Record the type after applying numeric affinity */
|
||||
pIn3->flags = flags3; /* But convert the type back to its original */
|
||||
|
||||
/* If the P3 value could not be converted into an integer without
|
||||
** loss of information, then special processing is required... */
|
||||
if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){
|
||||
if( (pIn3->flags & MEM_Real)==0 ){
|
||||
if( (pIn3->flags & MEM_Null) || oc>=OP_SeekGE ){
|
||||
VdbeBranchTaken(1,2); goto jump_to_p2;
|
||||
break;
|
||||
if( (newType & (MEM_Int|MEM_IntReal))==0 ){
|
||||
if( (newType & MEM_Real)==0 ){
|
||||
if( (newType & MEM_Null) || oc>=OP_SeekGE ){
|
||||
VdbeBranchTaken(1,2);
|
||||
goto jump_to_p2;
|
||||
}else{
|
||||
rc = sqlite3BtreeLast(pC->uc.pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
@@ -4432,23 +4538,27 @@ case OP_SeekRowid: { /* jump, in3 */
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
testcase( pIn3->flags & MEM_Int );
|
||||
testcase( pIn3->flags & MEM_IntReal );
|
||||
testcase( pIn3->flags & MEM_Real );
|
||||
testcase( (pIn3->flags & (MEM_Str|MEM_Int))==MEM_Str );
|
||||
if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){
|
||||
/* Make sure pIn3->u.i contains a valid integer representation of
|
||||
** the key value, but do not change the datatype of the register, as
|
||||
** other parts of the perpared statement might be depending on the
|
||||
** current datatype. */
|
||||
u16 origFlags = pIn3->flags;
|
||||
int isNotInt;
|
||||
applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding);
|
||||
isNotInt = (pIn3->flags & MEM_Int)==0;
|
||||
pIn3->flags = origFlags;
|
||||
if( isNotInt ) goto jump_to_p2;
|
||||
/* If pIn3->u.i does not contain an integer, compute iKey as the
|
||||
** integer value of pIn3. Jump to P2 if pIn3 cannot be converted
|
||||
** into an integer without loss of information. Take care to avoid
|
||||
** changing the datatype of pIn3, however, as it is used by other
|
||||
** parts of the prepared statement. */
|
||||
Mem x = pIn3[0];
|
||||
applyAffinity(&x, SQLITE_AFF_NUMERIC, encoding);
|
||||
if( (x.flags & MEM_Int)==0 ) goto jump_to_p2;
|
||||
iKey = x.u.i;
|
||||
goto notExistsWithKey;
|
||||
}
|
||||
/* Fall through into OP_NotExists */
|
||||
case OP_NotExists: /* jump, in3 */
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
iKey = pIn3->u.i;
|
||||
notExistsWithKey:
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -4459,7 +4569,6 @@ case OP_NotExists: /* jump, in3 */
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr!=0 );
|
||||
res = 0;
|
||||
iKey = pIn3->u.i;
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
|
||||
assert( rc==SQLITE_OK || res==0 );
|
||||
pC->movetoTarget = iKey; /* Used by OP_Delete */
|
||||
@@ -5341,11 +5450,12 @@ case OP_Next: /* jump */
|
||||
** The Prev opcode is only used after SeekLT, SeekLE, and Last. */
|
||||
assert( pOp->opcode!=OP_Next
|
||||
|| pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE
|
||||
|| pC->seekOp==OP_Rewind || pC->seekOp==OP_Found
|
||||
|| pC->seekOp==OP_NullRow|| pC->seekOp==OP_SeekRowid);
|
||||
|| pC->seekOp==OP_Rewind || pC->seekOp==OP_Found
|
||||
|| pC->seekOp==OP_NullRow|| pC->seekOp==OP_SeekRowid
|
||||
|| pC->seekOp==OP_IfNoHope);
|
||||
assert( pOp->opcode!=OP_Prev
|
||||
|| pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|
||||
|| pC->seekOp==OP_Last
|
||||
|| pC->seekOp==OP_Last || pC->seekOp==OP_IfNoHope
|
||||
|| pC->seekOp==OP_NullRow);
|
||||
|
||||
rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3);
|
||||
@@ -5864,7 +5974,7 @@ case OP_ParseSchema: {
|
||||
initData.pzErrMsg = &p->zErrMsg;
|
||||
initData.mInitFlags = 0;
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
|
||||
"SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid",
|
||||
db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
|
||||
+4
-4
@@ -222,10 +222,10 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
|
||||
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
|
||||
#endif
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
|
||||
void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
|
||||
void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
|
||||
void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
|
||||
void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
|
||||
void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
||||
int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
|
||||
|
||||
@@ -486,7 +486,6 @@ int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
|
||||
int sqlite3VdbeCursorRestore(VdbeCursor*);
|
||||
u32 sqlite3VdbeSerialTypeLen(u32);
|
||||
u8 sqlite3VdbeOneByteSerialTypeLen(u8);
|
||||
u32 sqlite3VdbeSerialType(Mem*, int, u32*);
|
||||
u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
|
||||
u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
||||
void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
|
||||
|
||||
+3
-3
@@ -844,7 +844,7 @@ int sqlite3_vtab_nochange(sqlite3_context *p){
|
||||
*/
|
||||
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){
|
||||
int rc;
|
||||
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifndef SQLITE_ENABLE_STAT4
|
||||
sqlite3_int64 *piTime = &p->pVdbe->iCurrentTime;
|
||||
assert( p->pVdbe!=0 );
|
||||
#else
|
||||
@@ -909,7 +909,7 @@ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
|
||||
AuxData *pAuxData;
|
||||
|
||||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
#if SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#if SQLITE_ENABLE_STAT4
|
||||
if( pCtx->pVdbe==0 ) return 0;
|
||||
#else
|
||||
assert( pCtx->pVdbe!=0 );
|
||||
@@ -943,7 +943,7 @@ void sqlite3_set_auxdata(
|
||||
Vdbe *pVdbe = pCtx->pVdbe;
|
||||
|
||||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( pVdbe==0 ) goto failed;
|
||||
#else
|
||||
assert( pVdbe!=0 );
|
||||
|
||||
+49
-22
@@ -640,7 +640,7 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
||||
int opcode = pOp->opcode;
|
||||
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|
||||
|| opcode==OP_VDestroy
|
||||
|| (opcode==OP_Function0 && pOp->p4.pFunc->funcFlags&SQLITE_FUNC_INTERNAL)
|
||||
|| (opcode==OP_ParseSchema && pOp->p4.z==0)
|
||||
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
|
||||
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
|
||||
){
|
||||
@@ -977,16 +977,16 @@ void sqlite3VdbeScanStatus(
|
||||
** Change the value of the opcode, or P1, P2, P3, or P5 operands
|
||||
** for a specific instruction.
|
||||
*/
|
||||
void sqlite3VdbeChangeOpcode(Vdbe *p, u32 addr, u8 iNewOpcode){
|
||||
void sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){
|
||||
sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
|
||||
}
|
||||
void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){
|
||||
void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
|
||||
sqlite3VdbeGetOp(p,addr)->p1 = val;
|
||||
}
|
||||
void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){
|
||||
void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
|
||||
sqlite3VdbeGetOp(p,addr)->p2 = val;
|
||||
}
|
||||
void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
|
||||
void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
|
||||
sqlite3VdbeGetOp(p,addr)->p3 = val;
|
||||
}
|
||||
void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
|
||||
@@ -1493,14 +1493,16 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
case P4_KEYINFO: {
|
||||
int j;
|
||||
KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
|
||||
assert( pKeyInfo->aSortOrder!=0 );
|
||||
assert( pKeyInfo->aSortFlags!=0 );
|
||||
sqlite3_str_appendf(&x, "k(%d", pKeyInfo->nKeyField);
|
||||
for(j=0; j<pKeyInfo->nKeyField; j++){
|
||||
CollSeq *pColl = pKeyInfo->aColl[j];
|
||||
const char *zColl = pColl ? pColl->zName : "";
|
||||
if( strcmp(zColl, "BINARY")==0 ) zColl = "B";
|
||||
sqlite3_str_appendf(&x, ",%s%s",
|
||||
pKeyInfo->aSortOrder[j] ? "-" : "", zColl);
|
||||
sqlite3_str_appendf(&x, ",%s%s%s",
|
||||
(pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_DESC) ? "-" : "",
|
||||
(pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_BIGNULL)? "N." : "",
|
||||
zColl);
|
||||
}
|
||||
sqlite3_str_append(&x, ")", 1);
|
||||
break;
|
||||
@@ -1907,8 +1909,11 @@ int sqlite3VdbeList(
|
||||
** pick up the appropriate opcode. */
|
||||
int j;
|
||||
i -= p->nOp;
|
||||
assert( apSub!=0 );
|
||||
assert( nSub>0 );
|
||||
for(j=0; i>=apSub[j]->nOp; j++){
|
||||
i -= apSub[j]->nOp;
|
||||
assert( i<apSub[j]->nOp || j+1<nSub );
|
||||
}
|
||||
pOp = &apSub[j]->aOp[i];
|
||||
}
|
||||
@@ -3430,10 +3435,17 @@ int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
|
||||
** of SQLite will not understand those serial types.
|
||||
*/
|
||||
|
||||
#if 0 /* Inlined into the OP_MakeRecord opcode */
|
||||
/*
|
||||
** Return the serial-type for the value stored in pMem.
|
||||
**
|
||||
** This routine might convert a large MEM_IntReal value into MEM_Real.
|
||||
**
|
||||
** 2019-07-11: The primary user of this subroutine was the OP_MakeRecord
|
||||
** opcode in the byte-code engine. But by moving this routine in-line, we
|
||||
** can omit some redundant tests and make that opcode a lot faster. So
|
||||
** this routine is now only used by the STAT3 logic and STAT3 support has
|
||||
** ended. The code is kept here for historical reference only.
|
||||
*/
|
||||
u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
|
||||
int flags = pMem->flags;
|
||||
@@ -3494,6 +3506,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
|
||||
*pLen = n;
|
||||
return ((n*2) + 12 + ((flags&MEM_Str)!=0));
|
||||
}
|
||||
#endif /* inlined into OP_MakeRecord */
|
||||
|
||||
/*
|
||||
** The sizes for serial types less than 128
|
||||
@@ -3802,7 +3815,7 @@ UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
|
||||
p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
|
||||
if( !p ) return 0;
|
||||
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
|
||||
assert( pKeyInfo->aSortOrder!=0 );
|
||||
assert( pKeyInfo->aSortFlags!=0 );
|
||||
p->pKeyInfo = pKeyInfo;
|
||||
p->nField = pKeyInfo->nKeyField + 1;
|
||||
return p;
|
||||
@@ -3901,7 +3914,7 @@ static int vdbeRecordCompareDebug(
|
||||
if( szHdr1>98307 ) return SQLITE_CORRUPT;
|
||||
d1 = szHdr1;
|
||||
assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB );
|
||||
assert( pKeyInfo->aSortOrder!=0 );
|
||||
assert( pKeyInfo->aSortFlags!=0 );
|
||||
assert( pKeyInfo->nKeyField>0 );
|
||||
assert( idx1<=szHdr1 || CORRUPT_DB );
|
||||
do{
|
||||
@@ -3932,7 +3945,12 @@ static int vdbeRecordCompareDebug(
|
||||
pKeyInfo->nAllField>i ? pKeyInfo->aColl[i] : 0);
|
||||
if( rc!=0 ){
|
||||
assert( mem1.szMalloc==0 ); /* See comment below */
|
||||
if( pKeyInfo->aSortOrder[i] ){
|
||||
if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
|
||||
&& ((mem1.flags & MEM_Null) || (pPKey2->aMem[i].flags & MEM_Null))
|
||||
){
|
||||
rc = -rc;
|
||||
}
|
||||
if( pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC ){
|
||||
rc = -rc; /* Invert the result for DESC sort order. */
|
||||
}
|
||||
goto debugCompareEnd;
|
||||
@@ -4308,7 +4326,7 @@ int sqlite3VdbeRecordCompareWithSkip(
|
||||
VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
|
||||
assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField
|
||||
|| CORRUPT_DB );
|
||||
assert( pPKey2->pKeyInfo->aSortOrder!=0 );
|
||||
assert( pPKey2->pKeyInfo->aSortFlags!=0 );
|
||||
assert( pPKey2->pKeyInfo->nKeyField>0 );
|
||||
assert( idx1<=szHdr1 || CORRUPT_DB );
|
||||
do{
|
||||
@@ -4431,8 +4449,14 @@ int sqlite3VdbeRecordCompareWithSkip(
|
||||
}
|
||||
|
||||
if( rc!=0 ){
|
||||
if( pPKey2->pKeyInfo->aSortOrder[i] ){
|
||||
rc = -rc;
|
||||
int sortFlags = pPKey2->pKeyInfo->aSortFlags[i];
|
||||
if( sortFlags ){
|
||||
if( (sortFlags & KEYINFO_ORDER_BIGNULL)==0
|
||||
|| ((sortFlags & KEYINFO_ORDER_DESC)
|
||||
!=(serial_type==0 || (pRhs->flags&MEM_Null)))
|
||||
){
|
||||
rc = -rc;
|
||||
}
|
||||
}
|
||||
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) );
|
||||
assert( mem1.szMalloc==0 ); /* See comment below */
|
||||
@@ -4600,7 +4624,11 @@ static int vdbeRecordCompareString(
|
||||
nCmp = MIN( pPKey2->aMem[0].n, nStr );
|
||||
res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
|
||||
|
||||
if( res==0 ){
|
||||
if( res>0 ){
|
||||
res = pPKey2->r2;
|
||||
}else if( res<0 ){
|
||||
res = pPKey2->r1;
|
||||
}else{
|
||||
res = nStr - pPKey2->aMem[0].n;
|
||||
if( res==0 ){
|
||||
if( pPKey2->nField>1 ){
|
||||
@@ -4614,10 +4642,6 @@ static int vdbeRecordCompareString(
|
||||
}else{
|
||||
res = pPKey2->r1;
|
||||
}
|
||||
}else if( res>0 ){
|
||||
res = pPKey2->r2;
|
||||
}else{
|
||||
res = pPKey2->r1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4649,7 +4673,10 @@ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
|
||||
** header size is (12*5 + 1 + 1) bytes. */
|
||||
if( p->pKeyInfo->nAllField<=13 ){
|
||||
int flags = p->aMem[0].flags;
|
||||
if( p->pKeyInfo->aSortOrder[0] ){
|
||||
if( p->pKeyInfo->aSortFlags[0] ){
|
||||
if( p->pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL ){
|
||||
return sqlite3VdbeRecordCompare;
|
||||
}
|
||||
p->r1 = 1;
|
||||
p->r2 = -1;
|
||||
}else{
|
||||
@@ -4898,7 +4925,7 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
|
||||
** features such as 'now'.
|
||||
*/
|
||||
int sqlite3NotPureFunc(sqlite3_context *pCtx){
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( pCtx->pVdbe==0 ) return 1;
|
||||
#endif
|
||||
if( pCtx->pVdbe->aOp[pCtx->iOp].opcode==OP_PureFunc ){
|
||||
@@ -4995,7 +5022,7 @@ void sqlite3VdbePreUpdateHook(
|
||||
preupdate.keyinfo.db = db;
|
||||
preupdate.keyinfo.enc = ENC(db);
|
||||
preupdate.keyinfo.nKeyField = pTab->nCol;
|
||||
preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder;
|
||||
preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder;
|
||||
preupdate.iKey1 = iKey1;
|
||||
preupdate.iKey2 = iKey2;
|
||||
preupdate.pTab = pTab;
|
||||
|
||||
+2
-1
@@ -355,11 +355,12 @@ int sqlite3_blob_close(sqlite3_blob *pBlob){
|
||||
sqlite3 *db;
|
||||
|
||||
if( p ){
|
||||
sqlite3_stmt *pStmt = p->pStmt;
|
||||
db = p->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
rc = sqlite3_finalize(p->pStmt);
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
+16
-59
@@ -232,7 +232,13 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
assert( pMem->szMalloc==0
|
||||
|| pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
|
||||
if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
|
||||
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
|
||||
if( pMem->db ){
|
||||
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
|
||||
}else{
|
||||
pMem->zMalloc = sqlite3Realloc(pMem->z, n);
|
||||
if( pMem->zMalloc==0 ) sqlite3_free(pMem->z);
|
||||
pMem->z = pMem->zMalloc;
|
||||
}
|
||||
bPreserve = 0;
|
||||
}else{
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
|
||||
@@ -1303,7 +1309,7 @@ struct ValueNewStat4Ctx {
|
||||
** an sqlite3_value within the UnpackedRecord.a[] array.
|
||||
*/
|
||||
static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( p ){
|
||||
UnpackedRecord *pRec = p->ppRec[0];
|
||||
|
||||
@@ -1339,7 +1345,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(p);
|
||||
#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
|
||||
#endif /* defined(SQLITE_ENABLE_STAT4) */
|
||||
return sqlite3ValueNew(db);
|
||||
}
|
||||
|
||||
@@ -1363,7 +1369,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to
|
||||
** NULL and an SQLite error code returned.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static int valueFromFunction(
|
||||
sqlite3 *db, /* The database connection */
|
||||
Expr *p, /* The expression to evaluate */
|
||||
@@ -1446,7 +1452,7 @@ static int valueFromFunction(
|
||||
}
|
||||
#else
|
||||
# define valueFromFunction(a,b,c,d,e,f) SQLITE_OK
|
||||
#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
|
||||
#endif /* defined(SQLITE_ENABLE_STAT4) */
|
||||
|
||||
/*
|
||||
** Extract a value from the supplied expression in the manner described
|
||||
@@ -1475,7 +1481,7 @@ static int valueFromExpr(
|
||||
|
||||
assert( pExpr!=0 );
|
||||
while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
|
||||
#if defined(SQLITE_ENABLE_STAT3_OR_STAT4)
|
||||
#if defined(SQLITE_ENABLE_STAT4)
|
||||
if( op==TK_REGISTER ) op = pExpr->op2;
|
||||
#else
|
||||
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
|
||||
@@ -1568,7 +1574,7 @@ static int valueFromExpr(
|
||||
0, SQLITE_DYNAMIC);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
else if( op==TK_FUNCTION && pCtx!=0 ){
|
||||
rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx);
|
||||
}
|
||||
@@ -1585,13 +1591,13 @@ static int valueFromExpr(
|
||||
return rc;
|
||||
|
||||
no_mem:
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( pCtx==0 || pCtx->pParse->nErr==0 )
|
||||
#endif
|
||||
sqlite3OomFault(db);
|
||||
sqlite3DbFree(db, zVal);
|
||||
assert( *ppVal==0 );
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
if( pCtx==0 ) sqlite3ValueFree(pVal);
|
||||
#else
|
||||
assert( pCtx==0 ); sqlite3ValueFree(pVal);
|
||||
@@ -1619,56 +1625,7 @@ int sqlite3ValueFromExpr(
|
||||
return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
/*
|
||||
** The implementation of the sqlite_record() function. This function accepts
|
||||
** a single argument of any type. The return value is a formatted database
|
||||
** record (a blob) containing the argument value.
|
||||
**
|
||||
** This is used to convert the value stored in the 'sample' column of the
|
||||
** sqlite_stat3 table to the record format SQLite uses internally.
|
||||
*/
|
||||
static void recordFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const int file_format = 1;
|
||||
u32 iSerial; /* Serial type */
|
||||
int nSerial; /* Bytes of space for iSerial as varint */
|
||||
u32 nVal; /* Bytes of space required for argv[0] */
|
||||
int nRet;
|
||||
sqlite3 *db;
|
||||
u8 *aRet;
|
||||
|
||||
UNUSED_PARAMETER( argc );
|
||||
iSerial = sqlite3VdbeSerialType(argv[0], file_format, &nVal);
|
||||
nSerial = sqlite3VarintLen(iSerial);
|
||||
db = sqlite3_context_db_handle(context);
|
||||
|
||||
nRet = 1 + nSerial + nVal;
|
||||
aRet = sqlite3DbMallocRawNN(db, nRet);
|
||||
if( aRet==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
aRet[0] = nSerial+1;
|
||||
putVarint32(&aRet[1], iSerial);
|
||||
sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial);
|
||||
sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
|
||||
sqlite3DbFreeNN(db, aRet);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Register built-in functions used to help read ANALYZE data.
|
||||
*/
|
||||
void sqlite3AnalyzeFunctions(void){
|
||||
static FuncDef aAnalyzeTableFuncs[] = {
|
||||
FUNCTION(sqlite_record, 1, 0, 0, recordFunc),
|
||||
};
|
||||
sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs));
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/*
|
||||
** Attempt to extract a value from pExpr and use it to construct *ppVal.
|
||||
**
|
||||
|
||||
+10
-4
@@ -829,7 +829,8 @@ static int vdbeSorterCompareText(
|
||||
);
|
||||
}
|
||||
}else{
|
||||
if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){
|
||||
assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) );
|
||||
if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){
|
||||
res = res * -1;
|
||||
}
|
||||
}
|
||||
@@ -897,7 +898,8 @@ static int vdbeSorterCompareInt(
|
||||
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
|
||||
);
|
||||
}
|
||||
}else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){
|
||||
}else if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){
|
||||
assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) );
|
||||
res = res * -1;
|
||||
}
|
||||
|
||||
@@ -1012,6 +1014,7 @@ int sqlite3VdbeSorterInit(
|
||||
|
||||
if( pKeyInfo->nAllField<13
|
||||
&& (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
|
||||
&& (pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL)==0
|
||||
){
|
||||
pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
|
||||
}
|
||||
@@ -1728,13 +1731,16 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
|
||||
rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], &pSorter->list);
|
||||
}else{
|
||||
/* Launch a background thread for this operation */
|
||||
u8 *aMem = pTask->list.aMemory;
|
||||
void *pCtx = (void*)pTask;
|
||||
u8 *aMem;
|
||||
void *pCtx;
|
||||
|
||||
assert( pTask!=0 );
|
||||
assert( pTask->pThread==0 && pTask->bDone==0 );
|
||||
assert( pTask->list.pList==0 );
|
||||
assert( pTask->list.aMemory==0 || pSorter->list.aMemory!=0 );
|
||||
|
||||
aMem = pTask->list.aMemory;
|
||||
pCtx = (void*)pTask;
|
||||
pSorter->iPrev = (u8)(pTask - pSorter->aTask);
|
||||
pTask->list = pSorter->list;
|
||||
pSorter->list.pList = 0;
|
||||
|
||||
+64
-14
@@ -32,6 +32,9 @@ struct VtabCtx {
|
||||
** Construct and install a Module object for a virtual table. When this
|
||||
** routine is called, it is guaranteed that all appropriate locks are held
|
||||
** and the module is not already part of the connection.
|
||||
**
|
||||
** If there already exists a module with zName, replace it with the new one.
|
||||
** If pModule==0, then delete the module zName if it exists.
|
||||
*/
|
||||
Module *sqlite3VtabCreateModule(
|
||||
sqlite3 *db, /* Database in which module is registered */
|
||||
@@ -41,25 +44,36 @@ Module *sqlite3VtabCreateModule(
|
||||
void (*xDestroy)(void *) /* Module destructor function */
|
||||
){
|
||||
Module *pMod;
|
||||
int nName = sqlite3Strlen30(zName);
|
||||
pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1);
|
||||
if( pMod==0 ){
|
||||
sqlite3OomFault(db);
|
||||
Module *pDel;
|
||||
char *zCopy;
|
||||
if( pModule==0 ){
|
||||
zCopy = (char*)zName;
|
||||
pMod = 0;
|
||||
}else{
|
||||
Module *pDel;
|
||||
char *zCopy = (char *)(&pMod[1]);
|
||||
int nName = sqlite3Strlen30(zName);
|
||||
pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1);
|
||||
if( pMod==0 ){
|
||||
sqlite3OomFault(db);
|
||||
return 0;
|
||||
}
|
||||
zCopy = (char *)(&pMod[1]);
|
||||
memcpy(zCopy, zName, nName+1);
|
||||
pMod->zName = zCopy;
|
||||
pMod->pModule = pModule;
|
||||
pMod->pAux = pAux;
|
||||
pMod->xDestroy = xDestroy;
|
||||
pMod->pEpoTab = 0;
|
||||
pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
|
||||
assert( pDel==0 || pDel==pMod );
|
||||
if( pDel ){
|
||||
pMod->nRefModule = 1;
|
||||
}
|
||||
pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
|
||||
if( pDel ){
|
||||
if( pDel==pMod ){
|
||||
sqlite3OomFault(db);
|
||||
sqlite3DbFree(db, pDel);
|
||||
pMod = 0;
|
||||
}else{
|
||||
sqlite3VtabEponymousTableClear(db, pDel);
|
||||
sqlite3VtabModuleUnref(db, pDel);
|
||||
}
|
||||
}
|
||||
return pMod;
|
||||
@@ -80,11 +94,7 @@ static int createModule(
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( sqlite3HashFind(&db->aModule, zName) ){
|
||||
rc = SQLITE_MISUSE_BKPT;
|
||||
}else{
|
||||
(void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy);
|
||||
}
|
||||
(void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
@@ -123,6 +133,44 @@ int sqlite3_create_module_v2(
|
||||
return createModule(db, zName, pModule, pAux, xDestroy);
|
||||
}
|
||||
|
||||
/*
|
||||
** External API to drop all virtual-table modules, except those named
|
||||
** on the azNames list.
|
||||
*/
|
||||
int sqlite3_drop_modules(sqlite3 *db, const char** azNames){
|
||||
HashElem *pThis, *pNext;
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
||||
#endif
|
||||
for(pThis=sqliteHashFirst(&db->aModule); pThis; pThis=pNext){
|
||||
Module *pMod = (Module*)sqliteHashData(pThis);
|
||||
pNext = sqliteHashNext(pThis);
|
||||
if( azNames ){
|
||||
int ii;
|
||||
for(ii=0; azNames[ii]!=0 && strcmp(azNames[ii],pMod->zName)!=0; ii++){}
|
||||
if( azNames[ii]!=0 ) continue;
|
||||
}
|
||||
createModule(db, pMod->zName, 0, 0, 0);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Decrement the reference count on a Module object. Destroy the
|
||||
** module when the reference count reaches zero.
|
||||
*/
|
||||
void sqlite3VtabModuleUnref(sqlite3 *db, Module *pMod){
|
||||
assert( pMod->nRefModule>0 );
|
||||
pMod->nRefModule--;
|
||||
if( pMod->nRefModule==0 ){
|
||||
if( pMod->xDestroy ){
|
||||
pMod->xDestroy(pMod->pAux);
|
||||
}
|
||||
assert( pMod->pEpoTab==0 );
|
||||
sqlite3DbFree(db, pMod);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock the virtual table so that it cannot be disconnected.
|
||||
** Locks nest. Every lock should have a corresponding unlock.
|
||||
@@ -162,6 +210,7 @@ void sqlite3VtabUnlock(VTable *pVTab){
|
||||
pVTab->nRef--;
|
||||
if( pVTab->nRef==0 ){
|
||||
sqlite3_vtab *p = pVTab->pVtab;
|
||||
sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
|
||||
if( p ){
|
||||
p->pModule->xDisconnect(p);
|
||||
}
|
||||
@@ -566,6 +615,7 @@ static int vtabCallConstructor(
|
||||
** the sqlite3_vtab object if successful. */
|
||||
memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0]));
|
||||
pVTable->pVtab->pModule = pMod->pModule;
|
||||
pMod->nRefModule++;
|
||||
pVTable->nRef = 1;
|
||||
if( sCtx.bDeclared==0 ){
|
||||
const char *zFormat = "vtable constructor did not declare schema: %s";
|
||||
|
||||
@@ -3478,6 +3478,7 @@ int sqlite3WalFrames(
|
||||
if( rc ) return rc;
|
||||
iOffset += szFrame;
|
||||
nExtra++;
|
||||
assert( pLast!=0 );
|
||||
}
|
||||
}
|
||||
if( bSync ){
|
||||
@@ -3510,6 +3511,7 @@ int sqlite3WalFrames(
|
||||
iFrame++;
|
||||
rc = walIndexAppend(pWal, iFrame, p->pgno);
|
||||
}
|
||||
assert( pLast!=0 || nExtra==0 );
|
||||
while( rc==SQLITE_OK && nExtra>0 ){
|
||||
iFrame++;
|
||||
nExtra--;
|
||||
|
||||
+28
-10
@@ -25,9 +25,22 @@
|
||||
static int walkWindowList(Walker *pWalker, Window *pList){
|
||||
Window *pWin;
|
||||
for(pWin=pList; pWin; pWin=pWin->pNextWin){
|
||||
if( sqlite3WalkExprList(pWalker, pWin->pOrderBy) ) return WRC_Abort;
|
||||
if( sqlite3WalkExprList(pWalker, pWin->pPartition) ) return WRC_Abort;
|
||||
if( sqlite3WalkExpr(pWalker, pWin->pFilter) ) return WRC_Abort;
|
||||
int rc;
|
||||
rc = sqlite3WalkExprList(pWalker, pWin->pOrderBy);
|
||||
if( rc ) return WRC_Abort;
|
||||
rc = sqlite3WalkExprList(pWalker, pWin->pPartition);
|
||||
if( rc ) return WRC_Abort;
|
||||
rc = sqlite3WalkExpr(pWalker, pWin->pFilter);
|
||||
if( rc ) return WRC_Abort;
|
||||
|
||||
/* The next two are purely for calls to sqlite3RenameExprUnmap()
|
||||
** within sqlite3WindowOffsetExpr(). Because of constraints imposed
|
||||
** by sqlite3WindowOffsetExpr(), they can never fail. The results do
|
||||
** not matter anyhow. */
|
||||
rc = sqlite3WalkExpr(pWalker, pWin->pStart);
|
||||
if( NEVER(rc) ) return WRC_Abort;
|
||||
rc = sqlite3WalkExpr(pWalker, pWin->pEnd);
|
||||
if( NEVER(rc) ) return WRC_Abort;
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
@@ -63,18 +76,22 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
|
||||
assert( pExpr->x.pList==0 || pExpr->pRight==0 );
|
||||
if( pExpr->pRight ){
|
||||
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
|
||||
pExpr = pExpr->pRight;
|
||||
continue;
|
||||
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
|
||||
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
|
||||
}else if( pExpr->x.pList ){
|
||||
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
|
||||
}
|
||||
}else{
|
||||
if( pExpr->x.pList ){
|
||||
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
if( walkWindowList(pWalker, pExpr->y.pWin) ) return WRC_Abort;
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
if( walkWindowList(pWalker, pExpr->y.pWin) ) return WRC_Abort;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -116,8 +133,9 @@ int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){
|
||||
{
|
||||
Parse *pParse = pWalker->pParse;
|
||||
if( pParse && IN_RENAME_OBJECT ){
|
||||
/* The following may return WRC_Abort if there are unresolvable
|
||||
** symbols (e.g. a table that does not exist) in a window definition. */
|
||||
int rc = walkWindowList(pWalker, p->pWinDefn);
|
||||
assert( rc==WRC_Continue );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
+82
-42
@@ -253,7 +253,8 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
|
||||
){
|
||||
if( (pTerm->eOperator & WO_EQUIV)!=0
|
||||
&& pScan->nEquiv<ArraySize(pScan->aiCur)
|
||||
&& (pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN
|
||||
&& (pX = sqlite3ExprSkipCollateAndLikely(pTerm->pExpr->pRight))->op
|
||||
==TK_COLUMN
|
||||
){
|
||||
int j;
|
||||
for(j=0; j<pScan->nEquiv; j++){
|
||||
@@ -449,7 +450,7 @@ static int findIndexCol(
|
||||
const char *zColl = pIdx->azColl[iCol];
|
||||
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr);
|
||||
Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr);
|
||||
if( p->op==TK_COLUMN
|
||||
&& p->iColumn==pIdx->aiColumn[iCol]
|
||||
&& p->iTable==iBase
|
||||
@@ -513,7 +514,7 @@ static int isDistinctRedundant(
|
||||
** current SELECT is a correlated sub-query.
|
||||
*/
|
||||
for(i=0; i<pDistinct->nExpr; i++){
|
||||
Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr);
|
||||
Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr);
|
||||
if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1;
|
||||
}
|
||||
|
||||
@@ -933,6 +934,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
for(i=0; i<n; i++){
|
||||
Expr *pExpr = pOrderBy->a[i].pExpr;
|
||||
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
|
||||
if( pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL ) break;
|
||||
}
|
||||
if( i==n){
|
||||
nOrderBy = n;
|
||||
@@ -1031,7 +1033,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
for(i=0; i<nOrderBy; i++){
|
||||
Expr *pExpr = pOrderBy->a[i].pExpr;
|
||||
pIdxOrderBy[i].iColumn = pExpr->iColumn;
|
||||
pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder;
|
||||
pIdxOrderBy[i].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC;
|
||||
}
|
||||
|
||||
*pmNoOmit = mNoOmit;
|
||||
@@ -1077,7 +1079,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/*
|
||||
** Estimate the location of a particular key among all keys in an
|
||||
** index. Store the results in aStat as follows:
|
||||
@@ -1270,7 +1272,7 @@ static int whereKeyStats(
|
||||
pRec->nField = nField;
|
||||
return i;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/*
|
||||
** If it is not NULL, pTerm is a term that provides an upper or lower
|
||||
@@ -1296,7 +1298,7 @@ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){
|
||||
}
|
||||
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/*
|
||||
** Return the affinity for a single column of an index.
|
||||
*/
|
||||
@@ -1305,12 +1307,13 @@ char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){
|
||||
if( !pIdx->zColAff ){
|
||||
if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB;
|
||||
}
|
||||
assert( pIdx->zColAff[iCol]!=0 );
|
||||
return pIdx->zColAff[iCol];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/*
|
||||
** This function is called to estimate the number of rows visited by a
|
||||
** range-scan on a skip-scan index. For example:
|
||||
@@ -1416,7 +1419,7 @@ static int whereRangeSkipScanEst(
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/*
|
||||
** This function is used to estimate the number of rows that will be visited
|
||||
@@ -1469,12 +1472,12 @@ static int whereRangeScanEst(
|
||||
int nOut = pLoop->nOut;
|
||||
LogEst nNew;
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
Index *p = pLoop->u.btree.pIndex;
|
||||
int nEq = pLoop->u.btree.nEq;
|
||||
|
||||
if( p->nSample>0 && nEq<p->nSampleCol
|
||||
&& OptimizationEnabled(pParse->db, SQLITE_Stat34)
|
||||
if( p->nSample>0 && ALWAYS(nEq<p->nSampleCol)
|
||||
&& OptimizationEnabled(pParse->db, SQLITE_Stat4)
|
||||
){
|
||||
if( nEq==pBuilder->nRecValid ){
|
||||
UnpackedRecord *pRec = pBuilder->pRec;
|
||||
@@ -1572,7 +1575,7 @@ static int whereRangeScanEst(
|
||||
/* TUNING: If both iUpper and iLower are derived from the same
|
||||
** sample, then assume they are 4x more selective. This brings
|
||||
** the estimated selectivity more in line with what it would be
|
||||
** if estimated without the use of STAT3/4 tables. */
|
||||
** if estimated without the use of STAT4 tables. */
|
||||
if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) );
|
||||
}else{
|
||||
nNew = 10; assert( 10==sqlite3LogEst(2) );
|
||||
@@ -1621,12 +1624,12 @@ static int whereRangeScanEst(
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/*
|
||||
** Estimate the number of rows that will be returned based on
|
||||
** an equality constraint x=VALUE and where that VALUE occurs in
|
||||
** the histogram data. This only works when x is the left-most
|
||||
** column of an index and sqlite_stat3 histogram data is available
|
||||
** column of an index and sqlite_stat4 histogram data is available
|
||||
** for that index. When pExpr==NULL that means the constraint is
|
||||
** "x IS NULL" instead of "x=VALUE".
|
||||
**
|
||||
@@ -1684,9 +1687,9 @@ static int whereEqualScanEst(
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/*
|
||||
** Estimate the number of rows that will be returned based on
|
||||
** an IN constraint where the right-hand side of the IN operator
|
||||
@@ -1733,7 +1736,7 @@ static int whereInScanEst(
|
||||
assert( pBuilder->nRecValid==nRecValid );
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
|
||||
#ifdef WHERETRACE_ENABLED
|
||||
@@ -2265,11 +2268,12 @@ static void whereLoopOutputAdjust(
|
||||
){
|
||||
WhereTerm *pTerm, *pX;
|
||||
Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf);
|
||||
int i, j, k;
|
||||
int i, j;
|
||||
LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */
|
||||
|
||||
assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
|
||||
for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){
|
||||
assert( pTerm!=0 );
|
||||
if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break;
|
||||
if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
|
||||
if( (pTerm->prereqAll & notAllowed)!=0 ) continue;
|
||||
@@ -2290,6 +2294,7 @@ static void whereLoopOutputAdjust(
|
||||
pLoop->nOut--;
|
||||
if( pTerm->eOperator&(WO_EQ|WO_IS) ){
|
||||
Expr *pRight = pTerm->pExpr->pRight;
|
||||
int k = 0;
|
||||
testcase( pTerm->pExpr->op==TK_IS );
|
||||
if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
|
||||
k = 10;
|
||||
@@ -2453,7 +2458,7 @@ static int whereLoopAddBtreeIndex(
|
||||
LogEst rCostIdx;
|
||||
LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */
|
||||
int nIn = 0;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int nRecValid = pBuilder->nRecValid;
|
||||
#endif
|
||||
if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0)
|
||||
@@ -2514,8 +2519,6 @@ static int whereLoopAddBtreeIndex(
|
||||
}else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
|
||||
/* "x IN (value, value, ...)" */
|
||||
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
|
||||
assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
|
||||
** changes "x IN (?)" into "x=?". */
|
||||
}
|
||||
if( pProbe->hasStat1 ){
|
||||
LogEst M, logK, safetyMargin;
|
||||
@@ -2611,7 +2614,7 @@ static int whereLoopAddBtreeIndex(
|
||||
** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */
|
||||
assert( pNew->nOut==saved_nOut );
|
||||
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
|
||||
/* Adjust nOut using stat3/stat4 data. Or, if there is no stat3/stat4
|
||||
/* Adjust nOut using stat4 data. Or, if there is no stat4
|
||||
** data, using some other estimate. */
|
||||
whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew);
|
||||
}else{
|
||||
@@ -2625,13 +2628,13 @@ static int whereLoopAddBtreeIndex(
|
||||
pNew->nOut += pTerm->truthProb;
|
||||
pNew->nOut -= nIn;
|
||||
}else{
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
tRowcnt nOut = 0;
|
||||
if( nInMul==0
|
||||
&& pProbe->nSample
|
||||
&& pNew->u.btree.nEq<=pProbe->nSampleCol
|
||||
&& ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
|
||||
&& OptimizationEnabled(db, SQLITE_Stat34)
|
||||
&& OptimizationEnabled(db, SQLITE_Stat4)
|
||||
){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){
|
||||
@@ -2668,6 +2671,7 @@ static int whereLoopAddBtreeIndex(
|
||||
** it to pNew->rRun, which is currently set to the cost of the index
|
||||
** seek only. Then, if this is a non-covering index, add the cost of
|
||||
** visiting the rows in the main table. */
|
||||
assert( pSrc->pTab->szTabRow>0 );
|
||||
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
|
||||
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
|
||||
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
|
||||
@@ -2693,7 +2697,7 @@ static int whereLoopAddBtreeIndex(
|
||||
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn);
|
||||
}
|
||||
pNew->nOut = saved_nOut;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
pBuilder->nRecValid = nRecValid;
|
||||
#endif
|
||||
}
|
||||
@@ -2766,7 +2770,7 @@ static int indexMightHelpWithOrderBy(
|
||||
if( pIndex->bUnordered ) return 0;
|
||||
if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0;
|
||||
for(ii=0; ii<pOB->nExpr; ii++){
|
||||
Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr);
|
||||
Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr);
|
||||
if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
|
||||
if( pExpr->iColumn<0 ) return 1;
|
||||
for(jj=0; jj<pIndex->nKeyCol; jj++){
|
||||
@@ -2797,7 +2801,9 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
|
||||
}
|
||||
if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
|
||||
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
Expr *pExpr;
|
||||
if( pTerm->wtFlags & TERM_NOPARTIDX ) continue;
|
||||
pExpr = pTerm->pExpr;
|
||||
if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
|
||||
&& sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
|
||||
){
|
||||
@@ -3066,7 +3072,7 @@ static int whereLoopAddBtree(
|
||||
** plan */
|
||||
pTab->tabFlags |= TF_StatsUsed;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
sqlite3Stat4ProbeFree(pBuilder->pRec);
|
||||
pBuilder->nRecValid = 0;
|
||||
pBuilder->pRec = 0;
|
||||
@@ -3694,8 +3700,8 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
|
||||
if( pLoop->u.vtab.isOrdered ) obSat = obDone;
|
||||
break;
|
||||
}else{
|
||||
pLoop->u.btree.nIdxCol = 0;
|
||||
}else if( wctrlFlags & WHERE_DISTINCTBY ){
|
||||
pLoop->u.btree.nDistinctCol = 0;
|
||||
}
|
||||
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
|
||||
|
||||
@@ -3706,7 +3712,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
*/
|
||||
for(i=0; i<nOrderBy; i++){
|
||||
if( MASKBIT(i) & obSat ) continue;
|
||||
pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr);
|
||||
pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
|
||||
if( pOBExpr->op!=TK_COLUMN ) continue;
|
||||
if( pOBExpr->iTable!=iCur ) continue;
|
||||
pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
|
||||
@@ -3743,7 +3749,8 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
|
||||
assert( pIndex->aiColumn[nColumn-1]==XN_ROWID
|
||||
|| !HasRowid(pIndex->pTable));
|
||||
isOrderDistinct = IsUniqueIndex(pIndex);
|
||||
isOrderDistinct = IsUniqueIndex(pIndex)
|
||||
&& (pLoop->wsFlags & WHERE_SKIPSCAN)==0;
|
||||
}
|
||||
|
||||
/* Loop through all columns of the index and deal with the ones
|
||||
@@ -3761,15 +3768,21 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
u16 eOp = pLoop->aLTerm[j]->eOperator;
|
||||
|
||||
/* Skip over == and IS and ISNULL terms. (Also skip IN terms when
|
||||
** doing WHERE_ORDERBY_LIMIT processing).
|
||||
** doing WHERE_ORDERBY_LIMIT processing). Except, IS and ISNULL
|
||||
** terms imply that the index is not UNIQUE NOT NULL in which case
|
||||
** the loop need to be marked as not order-distinct because it can
|
||||
** have repeated NULL rows.
|
||||
**
|
||||
** If the current term is a column of an ((?,?) IN (SELECT...))
|
||||
** expression for which the SELECT returns more than one column,
|
||||
** check that it is the only column used by this loop. Otherwise,
|
||||
** if it is one of two or more, none of the columns can be
|
||||
** considered to match an ORDER BY term. */
|
||||
** considered to match an ORDER BY term.
|
||||
*/
|
||||
if( (eOp & eqOpMask)!=0 ){
|
||||
if( eOp & WO_ISNULL ){
|
||||
if( eOp & (WO_ISNULL|WO_IS) ){
|
||||
testcase( eOp & WO_ISNULL );
|
||||
testcase( eOp & WO_IS );
|
||||
testcase( isOrderDistinct );
|
||||
isOrderDistinct = 0;
|
||||
}
|
||||
@@ -3795,7 +3808,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
*/
|
||||
if( pIndex ){
|
||||
iColumn = pIndex->aiColumn[j];
|
||||
revIdx = pIndex->aSortOrder[j];
|
||||
revIdx = pIndex->aSortOrder[j] & KEYINFO_ORDER_DESC;
|
||||
if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID;
|
||||
}else{
|
||||
iColumn = XN_ROWID;
|
||||
@@ -3819,7 +3832,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
isMatch = 0;
|
||||
for(i=0; bOnce && i<nOrderBy; i++){
|
||||
if( MASKBIT(i) & obSat ) continue;
|
||||
pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr);
|
||||
pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
|
||||
testcase( wctrlFlags & WHERE_GROUPBY );
|
||||
testcase( wctrlFlags & WHERE_DISTINCTBY );
|
||||
if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
|
||||
@@ -3837,7 +3850,9 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
|
||||
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
|
||||
}
|
||||
pLoop->u.btree.nIdxCol = j+1;
|
||||
if( wctrlFlags & WHERE_DISTINCTBY ){
|
||||
pLoop->u.btree.nDistinctCol = j+1;
|
||||
}
|
||||
isMatch = 1;
|
||||
break;
|
||||
}
|
||||
@@ -3845,13 +3860,22 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
/* Make sure the sort order is compatible in an ORDER BY clause.
|
||||
** Sort order is irrelevant for a GROUP BY clause. */
|
||||
if( revSet ){
|
||||
if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0;
|
||||
if( (rev ^ revIdx)!=(pOrderBy->a[i].sortFlags&KEYINFO_ORDER_DESC) ){
|
||||
isMatch = 0;
|
||||
}
|
||||
}else{
|
||||
rev = revIdx ^ pOrderBy->a[i].sortOrder;
|
||||
rev = revIdx ^ (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC);
|
||||
if( rev ) *pRevMask |= MASKBIT(iLoop);
|
||||
revSet = 1;
|
||||
}
|
||||
}
|
||||
if( isMatch && (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL) ){
|
||||
if( j==pLoop->u.btree.nEq ){
|
||||
pLoop->wsFlags |= WHERE_BIGNULL_SORT;
|
||||
}else{
|
||||
isMatch = 0;
|
||||
}
|
||||
}
|
||||
if( isMatch ){
|
||||
if( iColumn==XN_ROWID ){
|
||||
testcase( distinctColumns==0 );
|
||||
@@ -4765,6 +4789,16 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3DebugPrintf(", limit: %d", iAuxArg);
|
||||
}
|
||||
sqlite3DebugPrintf(")\n");
|
||||
if( sqlite3WhereTrace & 0x100 ){
|
||||
Select sSelect;
|
||||
memset(&sSelect, 0, sizeof(sSelect));
|
||||
sSelect.selFlags = SF_WhereBegin;
|
||||
sSelect.pSrc = pTabList;
|
||||
sSelect.pWhere = pWhere;
|
||||
sSelect.pOrderBy = pOrderBy;
|
||||
sSelect.pEList = pResultSet;
|
||||
sqlite3TreeViewSelect(0, &sSelect, 0);
|
||||
}
|
||||
}
|
||||
if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
|
||||
sqlite3WhereClausePrint(sWLB.pWC);
|
||||
@@ -5041,6 +5075,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pIx);
|
||||
if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
|
||||
&& (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
|
||||
&& (pLoop->wsFlags & WHERE_BIGNULL_SORT)==0
|
||||
&& (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
|
||||
&& pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
|
||||
){
|
||||
@@ -5158,7 +5193,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
&& i==pWInfo->nLevel-1 /* Ticket [ef9318757b152e3] 2017-10-21 */
|
||||
&& (pLoop->wsFlags & WHERE_INDEXED)!=0
|
||||
&& (pIdx = pLoop->u.btree.pIndex)->hasStat1
|
||||
&& (n = pLoop->u.btree.nIdxCol)>0
|
||||
&& (n = pLoop->u.btree.nDistinctCol)>0
|
||||
&& pIdx->aiRowLogEst[n]>=36
|
||||
){
|
||||
int r1 = pParse->nMem+1;
|
||||
@@ -5182,6 +5217,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
VdbeCoverageIf(v, pLevel->op==OP_Next);
|
||||
VdbeCoverageIf(v, pLevel->op==OP_Prev);
|
||||
VdbeCoverageIf(v, pLevel->op==OP_VNext);
|
||||
if( pLevel->regBignull ){
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrBignull);
|
||||
sqlite3VdbeAddOp2(v, OP_DecrJumpZero, pLevel->regBignull, pLevel->p2-1);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
||||
if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
|
||||
#endif
|
||||
|
||||
+9
-5
@@ -71,13 +71,15 @@ struct WhereLevel {
|
||||
int addrCont; /* Jump here to continue with the next loop cycle */
|
||||
int addrFirst; /* First instruction of interior of the loop */
|
||||
int addrBody; /* Beginning of the body of this loop */
|
||||
int regBignull; /* big-null flag reg. True if a NULL-scan is needed */
|
||||
int addrBignull; /* Jump here for next part of big-null scan */
|
||||
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||
u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */
|
||||
int addrLikeRep; /* LIKE range processing address */
|
||||
#endif
|
||||
u8 iFrom; /* Which entry in the FROM clause */
|
||||
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
|
||||
int p1, p2; /* Operands of the opcode used to ends the loop */
|
||||
int p1, p2; /* Operands of the opcode used to end the loop */
|
||||
union { /* Information that depends on pWLoop->wsFlags */
|
||||
struct {
|
||||
int nIn; /* Number of entries in aInLoop[] */
|
||||
@@ -128,7 +130,7 @@ struct WhereLoop {
|
||||
u16 nEq; /* Number of equality constraints */
|
||||
u16 nBtm; /* Size of BTM vector */
|
||||
u16 nTop; /* Size of TOP vector */
|
||||
u16 nIdxCol; /* Index column used for ORDER BY */
|
||||
u16 nDistinctCol; /* Index columns used to sort for DISTINCT */
|
||||
Index *pIndex; /* Index used, or NULL */
|
||||
} btree;
|
||||
struct { /* Information for virtual tables */
|
||||
@@ -279,16 +281,17 @@ struct WhereTerm {
|
||||
#define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */
|
||||
#define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */
|
||||
#define TERM_OR_OK 0x40 /* Used during OR-clause processing */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
# define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */
|
||||
#else
|
||||
# define TERM_VNULL 0x00 /* Disabled if not using stat3 */
|
||||
# define TERM_VNULL 0x00 /* Disabled if not using stat4 */
|
||||
#endif
|
||||
#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */
|
||||
#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */
|
||||
#define TERM_LIKE 0x400 /* The original LIKE operator */
|
||||
#define TERM_IS 0x800 /* Term.pExpr is an IS operator */
|
||||
#define TERM_VARSELECT 0x1000 /* Term.pExpr contains a correlated sub-query */
|
||||
#define TERM_NOPARTIDX 0x2000 /* Not for use to enable a partial index */
|
||||
|
||||
/*
|
||||
** An instance of the WhereScan object is used as an iterator for locating
|
||||
@@ -399,7 +402,7 @@ struct WhereLoopBuilder {
|
||||
ExprList *pOrderBy; /* ORDER BY clause */
|
||||
WhereLoop *pNew; /* Template WhereLoop */
|
||||
WhereOrSet *pOrSet; /* Record best loops here, if not NULL */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
UnpackedRecord *pRec; /* Probe for stat4 (if required) */
|
||||
int nRecValid; /* Number of valid fields currently in pRec */
|
||||
#endif
|
||||
@@ -586,5 +589,6 @@ void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
|
||||
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
|
||||
#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */
|
||||
#define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */
|
||||
#define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */
|
||||
|
||||
#endif /* !defined(SQLITE_WHEREINT_H) */
|
||||
|
||||
+85
-33
@@ -318,9 +318,9 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
||||
** Code an OP_Affinity opcode to apply the column affinity string zAff
|
||||
** to the n registers starting at base.
|
||||
**
|
||||
** As an optimization, SQLITE_AFF_BLOB entries (which are no-ops) at the
|
||||
** beginning and end of zAff are ignored. If all entries in zAff are
|
||||
** SQLITE_AFF_BLOB, then no code gets generated.
|
||||
** As an optimization, SQLITE_AFF_BLOB and SQLITE_AFF_NONE entries (which
|
||||
** are no-ops) at the beginning and end of zAff are ignored. If all entries
|
||||
** in zAff are SQLITE_AFF_BLOB or SQLITE_AFF_NONE, then no code gets generated.
|
||||
**
|
||||
** This routine makes its own copy of zAff so that the caller is free
|
||||
** to modify zAff after this routine returns.
|
||||
@@ -333,15 +333,16 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
|
||||
}
|
||||
assert( v!=0 );
|
||||
|
||||
/* Adjust base and n to skip over SQLITE_AFF_BLOB entries at the beginning
|
||||
** and end of the affinity string.
|
||||
/* Adjust base and n to skip over SQLITE_AFF_BLOB and SQLITE_AFF_NONE
|
||||
** entries at the beginning and end of the affinity string.
|
||||
*/
|
||||
while( n>0 && zAff[0]==SQLITE_AFF_BLOB ){
|
||||
assert( SQLITE_AFF_NONE<SQLITE_AFF_BLOB );
|
||||
while( n>0 && zAff[0]<=SQLITE_AFF_BLOB ){
|
||||
n--;
|
||||
base++;
|
||||
zAff++;
|
||||
}
|
||||
while( n>1 && zAff[n-1]==SQLITE_AFF_BLOB ){
|
||||
while( n>1 && zAff[n-1]<=SQLITE_AFF_BLOB ){
|
||||
n--;
|
||||
}
|
||||
|
||||
@@ -1116,6 +1117,7 @@ typedef struct IdxExprTrans {
|
||||
static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
|
||||
IdxExprTrans *pX = p->u.pIdxTrans;
|
||||
if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
|
||||
pExpr->affExpr = sqlite3ExprAffinity(pExpr);
|
||||
pExpr->op = TK_COLUMN;
|
||||
pExpr->iTable = pX->iIdxCur;
|
||||
pExpr->iColumn = pX->iIdxCol;
|
||||
@@ -1548,32 +1550,12 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
u8 bSeekPastNull = 0; /* True to seek past initial nulls */
|
||||
u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */
|
||||
int omitTable; /* True if we use the index only */
|
||||
|
||||
int regBignull = 0; /* big-null flag register */
|
||||
|
||||
pIdx = pLoop->u.btree.pIndex;
|
||||
iIdxCur = pLevel->iIdxCur;
|
||||
assert( nEq>=pLoop->nSkip );
|
||||
|
||||
/* If this loop satisfies a sort order (pOrderBy) request that
|
||||
** was passed to this function to implement a "SELECT min(x) ..."
|
||||
** query, then the caller will only allow the loop to run for
|
||||
** a single iteration. This means that the first row returned
|
||||
** should not have a NULL value stored in 'x'. If column 'x' is
|
||||
** the first one after the nEq equality constraints in the index,
|
||||
** this requires some special handling.
|
||||
*/
|
||||
assert( pWInfo->pOrderBy==0
|
||||
|| pWInfo->pOrderBy->nExpr==1
|
||||
|| (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 );
|
||||
if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
|
||||
&& pWInfo->nOBSat>0
|
||||
&& (pIdx->nKeyCol>nEq)
|
||||
){
|
||||
assert( pLoop->nSkip==0 );
|
||||
bSeekPastNull = 1;
|
||||
nExtraReg = 1;
|
||||
}
|
||||
|
||||
/* Find any inequality constraint terms for the start and end
|
||||
** of the range.
|
||||
*/
|
||||
@@ -1614,6 +1596,25 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
}
|
||||
assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
|
||||
|
||||
/* If the WHERE_BIGNULL_SORT flag is set, then index column nEq uses
|
||||
** a non-default "big-null" sort (either ASC NULLS LAST or DESC NULLS
|
||||
** FIRST). In both cases separate ordered scans are made of those
|
||||
** index entries for which the column is null and for those for which
|
||||
** it is not. For an ASC sort, the non-NULL entries are scanned first.
|
||||
** For DESC, NULL entries are scanned first.
|
||||
*/
|
||||
if( (pLoop->wsFlags & (WHERE_TOP_LIMIT|WHERE_BTM_LIMIT))==0
|
||||
&& (pLoop->wsFlags & WHERE_BIGNULL_SORT)!=0
|
||||
){
|
||||
assert( bSeekPastNull==0 && nExtraReg==0 && nBtm==0 && nTop==0 );
|
||||
assert( pRangeEnd==0 && pRangeStart==0 );
|
||||
assert( pLoop->nSkip==0 );
|
||||
nExtraReg = 1;
|
||||
bSeekPastNull = 1;
|
||||
pLevel->regBignull = regBignull = ++pParse->nMem;
|
||||
pLevel->addrBignull = sqlite3VdbeMakeLabel(pParse);
|
||||
}
|
||||
|
||||
/* If we are doing a reverse order scan on an ascending index, or
|
||||
** a forward order scan on a descending index, interchange the
|
||||
** start and end terms (pRangeStart and pRangeEnd).
|
||||
@@ -1636,7 +1637,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
if( zStartAff && nTop ){
|
||||
zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]);
|
||||
}
|
||||
addrNxt = pLevel->addrNxt;
|
||||
addrNxt = (regBignull ? pLevel->addrBignull : pLevel->addrNxt);
|
||||
|
||||
testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
|
||||
testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 );
|
||||
@@ -1670,10 +1671,14 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
}
|
||||
bSeekPastNull = 0;
|
||||
}else if( bSeekPastNull ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
|
||||
nConstraint++;
|
||||
startEq = 0;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
|
||||
start_constraints = 1;
|
||||
nConstraint++;
|
||||
}else if( regBignull ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
|
||||
start_constraints = 1;
|
||||
nConstraint++;
|
||||
}
|
||||
codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff);
|
||||
if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){
|
||||
@@ -1684,6 +1689,11 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
|
||||
sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur);
|
||||
}
|
||||
if( regBignull ){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull);
|
||||
VdbeComment((v, "NULL-scan pass ctr"));
|
||||
}
|
||||
|
||||
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
|
||||
assert( op!=0 );
|
||||
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
|
||||
@@ -1694,6 +1704,23 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
|
||||
VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
|
||||
VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT );
|
||||
|
||||
assert( bSeekPastNull==0 || bStopAtNull==0 );
|
||||
if( regBignull ){
|
||||
assert( bSeekPastNull==1 || bStopAtNull==1 );
|
||||
assert( bSeekPastNull==!bStopAtNull );
|
||||
assert( bStopAtNull==startEq );
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2);
|
||||
op = aStartOp[(nConstraint>1)*4 + 2 + bRev];
|
||||
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
|
||||
nConstraint-startEq);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
|
||||
VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
|
||||
VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
|
||||
VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
|
||||
assert( op==OP_Rewind || op==OP_Last || op==OP_SeekGE || op==OP_SeekLE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Load the value for the inequality constraint at the end of the
|
||||
@@ -1725,8 +1752,10 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
endEq = 1;
|
||||
}
|
||||
}else if( bStopAtNull ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
|
||||
endEq = 0;
|
||||
if( regBignull==0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
|
||||
endEq = 0;
|
||||
}
|
||||
nConstraint++;
|
||||
}
|
||||
sqlite3DbFree(db, zStartAff);
|
||||
@@ -1737,6 +1766,12 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
|
||||
/* Check if the index cursor is past the end of the range. */
|
||||
if( nConstraint ){
|
||||
if( regBignull ){
|
||||
/* Except, skip the end-of-range check while doing the NULL-scan */
|
||||
sqlite3VdbeAddOp2(v, OP_IfNot, regBignull, sqlite3VdbeCurrentAddr(v)+3);
|
||||
VdbeComment((v, "If NULL-scan 2nd pass"));
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
op = aEndOp[bRev*2 + endEq];
|
||||
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
|
||||
testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
|
||||
@@ -1744,6 +1779,23 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
|
||||
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
|
||||
}
|
||||
if( regBignull ){
|
||||
/* During a NULL-scan, check to see if we have reached the end of
|
||||
** the NULLs */
|
||||
assert( bSeekPastNull==!bStopAtNull );
|
||||
assert( bSeekPastNull+bStopAtNull==1 );
|
||||
assert( nConstraint+bSeekPastNull>0 );
|
||||
sqlite3VdbeAddOp2(v, OP_If, regBignull, sqlite3VdbeCurrentAddr(v)+2);
|
||||
VdbeComment((v, "If NULL-scan 1st pass"));
|
||||
VdbeCoverage(v);
|
||||
op = aEndOp[bRev*2 + bSeekPastNull];
|
||||
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
|
||||
nConstraint+bSeekPastNull);
|
||||
testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
|
||||
testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE );
|
||||
testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
|
||||
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
|
||||
}
|
||||
|
||||
if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
|
||||
sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 1);
|
||||
|
||||
+25
-11
@@ -84,7 +84,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
|
||||
}else{
|
||||
pTerm->truthProb = 1;
|
||||
}
|
||||
pTerm->pExpr = sqlite3ExprSkipCollate(p);
|
||||
pTerm->pExpr = sqlite3ExprSkipCollateAndLikely(p);
|
||||
pTerm->wtFlags = wtFlags;
|
||||
pTerm->pWC = pWC;
|
||||
pTerm->iParent = -1;
|
||||
@@ -117,10 +117,16 @@ static int allowedOp(int op){
|
||||
** the left hand side of a comparison overrides any collation sequence
|
||||
** attached to the right. For the same reason the EP_Collate flag
|
||||
** is not commuted.
|
||||
**
|
||||
** The return value is extra flags that are added to the WhereTerm object
|
||||
** after it is commuted. The only extra flag ever added is TERM_NOPARTIDX
|
||||
** which prevents the term from being used to enable a partial index if
|
||||
** COLLATE changes have been made.
|
||||
*/
|
||||
static void exprCommute(Parse *pParse, Expr *pExpr){
|
||||
static u16 exprCommute(Parse *pParse, Expr *pExpr){
|
||||
u16 expRight = (pExpr->pRight->flags & EP_Collate);
|
||||
u16 expLeft = (pExpr->pLeft->flags & EP_Collate);
|
||||
u16 wtFlags = 0;
|
||||
assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN );
|
||||
if( expRight==expLeft ){
|
||||
/* Either X and Y both have COLLATE operator or neither do */
|
||||
@@ -128,11 +134,13 @@ static void exprCommute(Parse *pParse, Expr *pExpr){
|
||||
/* Both X and Y have COLLATE operators. Make sure X is always
|
||||
** used by clearing the EP_Collate flag from Y. */
|
||||
pExpr->pRight->flags &= ~EP_Collate;
|
||||
wtFlags |= TERM_NOPARTIDX;
|
||||
}else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){
|
||||
/* Neither X nor Y have COLLATE operators, but X has a non-default
|
||||
** collating sequence. So add the EP_Collate marker on X to cause
|
||||
** it to be searched first. */
|
||||
pExpr->pLeft->flags |= EP_Collate;
|
||||
wtFlags |= TERM_NOPARTIDX;
|
||||
}
|
||||
}
|
||||
SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
|
||||
@@ -144,6 +152,7 @@ static void exprCommute(Parse *pParse, Expr *pExpr){
|
||||
assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE );
|
||||
pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT;
|
||||
}
|
||||
return wtFlags;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -275,6 +284,7 @@ static int isLikeOrGlob(
|
||||
** 2019-05-02 https://sqlite.org/src/info/b043a54c3de54b28
|
||||
** 2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07
|
||||
** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975
|
||||
** 2019-09-03 https://sqlite.org/src/info/0f0428096f17252a
|
||||
*/
|
||||
if( pLeft->op!=TK_COLUMN
|
||||
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|
||||
@@ -284,9 +294,13 @@ static int isLikeOrGlob(
|
||||
double rDummy;
|
||||
isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8);
|
||||
if( isNum<=0 ){
|
||||
zNew[iTo-1]++;
|
||||
isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8);
|
||||
zNew[iTo-1]--;
|
||||
if( iTo==1 && zNew[0]=='-' ){
|
||||
isNum = +1;
|
||||
}else{
|
||||
zNew[iTo-1]++;
|
||||
isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8);
|
||||
zNew[iTo-1]--;
|
||||
}
|
||||
}
|
||||
if( isNum>0 ){
|
||||
sqlite3ExprDelete(db, pPrefix);
|
||||
@@ -1140,7 +1154,7 @@ static void exprAnalyze(
|
||||
pDup = pExpr;
|
||||
pNew = pTerm;
|
||||
}
|
||||
exprCommute(pParse, pDup);
|
||||
pNew->wtFlags |= exprCommute(pParse, pDup);
|
||||
pNew->leftCursor = aiCurCol[0];
|
||||
pNew->u.leftColumn = aiCurCol[1];
|
||||
testcase( (prereqLeft | extraRight) != prereqLeft );
|
||||
@@ -1381,8 +1395,8 @@ static void exprAnalyze(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
/* When sqlite_stat3 histogram data is available an operator of the
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/* When sqlite_stat4 histogram data is available an operator of the
|
||||
** form "x IS NOT NULL" can sometimes be evaluated more efficiently
|
||||
** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a
|
||||
** virtual term of that form.
|
||||
@@ -1393,7 +1407,7 @@ static void exprAnalyze(
|
||||
&& pExpr->pLeft->op==TK_COLUMN
|
||||
&& pExpr->pLeft->iColumn>=0
|
||||
&& !ExprHasProperty(pExpr, EP_FromJoin)
|
||||
&& OptimizationEnabled(db, SQLITE_Stat34)
|
||||
&& OptimizationEnabled(db, SQLITE_Stat4)
|
||||
){
|
||||
Expr *pNewExpr;
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
@@ -1418,7 +1432,7 @@ static void exprAnalyze(
|
||||
pNewTerm->prereqAll = pTerm->prereqAll;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/* Prevent ON clause terms of a LEFT JOIN from being used to drive
|
||||
** an index for tables to the left of the join.
|
||||
@@ -1451,7 +1465,7 @@ static void exprAnalyze(
|
||||
** all terms of the WHERE clause.
|
||||
*/
|
||||
void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
|
||||
Expr *pE2 = sqlite3ExprSkipCollate(pExpr);
|
||||
Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr);
|
||||
pWC->op = op;
|
||||
if( pE2==0 ) return;
|
||||
if( pE2->op!=op ){
|
||||
|
||||
+337
-104
@@ -748,6 +748,8 @@ struct WindowRewrite {
|
||||
static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
||||
struct WindowRewrite *p = pWalker->u.pRewrite;
|
||||
Parse *pParse = pWalker->pParse;
|
||||
assert( p!=0 );
|
||||
assert( p->pWin!=0 );
|
||||
|
||||
/* If this function is being called from within a scalar sub-select
|
||||
** that used by the SELECT statement being processed, only process
|
||||
@@ -847,6 +849,7 @@ static void selectWindowRewriteEList(
|
||||
Walker sWalker;
|
||||
WindowRewrite sRewrite;
|
||||
|
||||
assert( pWin!=0 );
|
||||
memset(&sWalker, 0, sizeof(Walker));
|
||||
memset(&sRewrite, 0, sizeof(WindowRewrite));
|
||||
|
||||
@@ -885,7 +888,7 @@ static ExprList *exprListAppendList(
|
||||
pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
|
||||
}
|
||||
pList = sqlite3ExprListAppend(pParse, pList, pDup);
|
||||
if( pList ) pList->a[nInit+i].sortOrder = pAppend->a[i].sortOrder;
|
||||
if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
|
||||
}
|
||||
}
|
||||
return pList;
|
||||
@@ -931,11 +934,14 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
** redundant, remove the ORDER BY from the parent SELECT. */
|
||||
pSort = sqlite3ExprListDup(db, pMWin->pPartition, 0);
|
||||
pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1);
|
||||
if( pSort && p->pOrderBy ){
|
||||
if( pSort && p->pOrderBy && p->pOrderBy->nExpr<=pSort->nExpr ){
|
||||
int nSave = pSort->nExpr;
|
||||
pSort->nExpr = p->pOrderBy->nExpr;
|
||||
if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){
|
||||
sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
p->pOrderBy = 0;
|
||||
}
|
||||
pSort->nExpr = nSave;
|
||||
}
|
||||
|
||||
/* Assign a cursor number for the ephemeral table used to buffer rows.
|
||||
@@ -959,8 +965,15 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
** window function - one for the accumulator, another for interim
|
||||
** results. */
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
|
||||
pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList, 0);
|
||||
ExprList *pArgs = pWin->pOwner->x.pList;
|
||||
if( pWin->pFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){
|
||||
selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist);
|
||||
pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
|
||||
pWin->bExprArgs = 1;
|
||||
}else{
|
||||
pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
|
||||
pSublist = exprListAppendList(pParse, pSublist, pArgs, 0);
|
||||
}
|
||||
if( pWin->pFilter ){
|
||||
Expr *pFilter = sqlite3ExprDup(db, pWin->pFilter, 0);
|
||||
pSublist = sqlite3ExprListAppend(pParse, pSublist, pFilter);
|
||||
@@ -978,7 +991,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
*/
|
||||
if( pSublist==0 ){
|
||||
pSublist = sqlite3ExprListAppend(pParse, 0,
|
||||
sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0)
|
||||
sqlite3Expr(db, TK_INTEGER, "0")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -991,7 +1004,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
p->pSrc->a[0].pSelect = pSub;
|
||||
sqlite3SrcListAssignCursors(pParse, p->pSrc);
|
||||
pSub->selFlags |= SF_Expanded;
|
||||
pTab2 = sqlite3ResultSetOfSelect(pParse, pSub);
|
||||
pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
|
||||
if( pTab2==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1014,11 +1027,24 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlink the Window object from the Select to which it is attached,
|
||||
** if it is attached.
|
||||
*/
|
||||
void sqlite3WindowUnlinkFromSelect(Window *p){
|
||||
if( p->ppThis ){
|
||||
*p->ppThis = p->pNextWin;
|
||||
if( p->pNextWin ) p->pNextWin->ppThis = p->ppThis;
|
||||
p->ppThis = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Free the Window object passed as the second argument.
|
||||
*/
|
||||
void sqlite3WindowDelete(sqlite3 *db, Window *p){
|
||||
if( p ){
|
||||
sqlite3WindowUnlinkFromSelect(p);
|
||||
sqlite3ExprDelete(db, p->pFilter);
|
||||
sqlite3ExprListDelete(db, p->pPartition);
|
||||
sqlite3ExprListDelete(db, p->pOrderBy);
|
||||
@@ -1196,28 +1222,44 @@ void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pList){
|
||||
void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
|
||||
if( p ){
|
||||
assert( p->op==TK_FUNCTION );
|
||||
/* This routine is only called for the parser. If pWin was not
|
||||
** allocated due to an OOM, then the parser would fail before ever
|
||||
** invoking this routine */
|
||||
if( ALWAYS(pWin) ){
|
||||
p->y.pWin = pWin;
|
||||
ExprSetProperty(p, EP_WinFunc);
|
||||
pWin->pOwner = p;
|
||||
if( p->flags & EP_Distinct ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"DISTINCT is not supported for window functions");
|
||||
}
|
||||
assert( pWin );
|
||||
p->y.pWin = pWin;
|
||||
ExprSetProperty(p, EP_WinFunc);
|
||||
pWin->pOwner = p;
|
||||
if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"DISTINCT is not supported for window functions"
|
||||
);
|
||||
}
|
||||
}else{
|
||||
sqlite3WindowDelete(pParse->db, pWin);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Possibly link window pWin into the list at pSel->pWin (window functions
|
||||
** to be processed as part of SELECT statement pSel). The window is linked
|
||||
** in if either (a) there are no other windows already linked to this
|
||||
** SELECT, or (b) the windows already linked use a compatible window frame.
|
||||
*/
|
||||
void sqlite3WindowLink(Select *pSel, Window *pWin){
|
||||
if( 0==pSel->pWin
|
||||
|| 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0)
|
||||
){
|
||||
pWin->pNextWin = pSel->pWin;
|
||||
if( pSel->pWin ){
|
||||
pSel->pWin->ppThis = &pWin->pNextWin;
|
||||
}
|
||||
pSel->pWin = pWin;
|
||||
pWin->ppThis = &pSel->pWin;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return 0 if the two window objects are identical, or non-zero otherwise.
|
||||
** Identical window objects can be processed in a single scan.
|
||||
*/
|
||||
int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){
|
||||
int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2, int bFilter){
|
||||
if( p1->eFrmType!=p2->eFrmType ) return 1;
|
||||
if( p1->eStart!=p2->eStart ) return 1;
|
||||
if( p1->eEnd!=p2->eEnd ) return 1;
|
||||
@@ -1226,6 +1268,9 @@ int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){
|
||||
if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1;
|
||||
if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1;
|
||||
if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1;
|
||||
if( bFilter ){
|
||||
if( sqlite3ExprCompare(pParse, p1->pFilter, p2->pFilter, -1) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1277,8 +1322,8 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
|
||||
pWin->regApp = pParse->nMem+1;
|
||||
pParse->nMem += 3;
|
||||
if( pKeyInfo && pWin->pFunc->zName[1]=='i' ){
|
||||
assert( pKeyInfo->aSortOrder[0]==0 );
|
||||
pKeyInfo->aSortOrder[0] = 1;
|
||||
assert( pKeyInfo->aSortFlags[0]==0 );
|
||||
pKeyInfo->aSortFlags[0] = KEYINFO_ORDER_DESC;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->csrApp, 2);
|
||||
sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
|
||||
@@ -1363,6 +1408,108 @@ static int windowArgCount(Window *pWin){
|
||||
return (pList ? pList->nExpr : 0);
|
||||
}
|
||||
|
||||
typedef struct WindowCodeArg WindowCodeArg;
|
||||
typedef struct WindowCsrAndReg WindowCsrAndReg;
|
||||
|
||||
/*
|
||||
** See comments above struct WindowCodeArg.
|
||||
*/
|
||||
struct WindowCsrAndReg {
|
||||
int csr; /* Cursor number */
|
||||
int reg; /* First in array of peer values */
|
||||
};
|
||||
|
||||
/*
|
||||
** A single instance of this structure is allocated on the stack by
|
||||
** sqlite3WindowCodeStep() and a pointer to it passed to the various helper
|
||||
** routines. This is to reduce the number of arguments required by each
|
||||
** helper function.
|
||||
**
|
||||
** regArg:
|
||||
** Each window function requires an accumulator register (just as an
|
||||
** ordinary aggregate function does). This variable is set to the first
|
||||
** in an array of accumulator registers - one for each window function
|
||||
** in the WindowCodeArg.pMWin list.
|
||||
**
|
||||
** eDelete:
|
||||
** The window functions implementation sometimes caches the input rows
|
||||
** that it processes in a temporary table. If it is not zero, this
|
||||
** variable indicates when rows may be removed from the temp table (in
|
||||
** order to reduce memory requirements - it would always be safe just
|
||||
** to leave them there). Possible values for eDelete are:
|
||||
**
|
||||
** WINDOW_RETURN_ROW:
|
||||
** An input row can be discarded after it is returned to the caller.
|
||||
**
|
||||
** WINDOW_AGGINVERSE:
|
||||
** An input row can be discarded after the window functions xInverse()
|
||||
** callbacks have been invoked in it.
|
||||
**
|
||||
** WINDOW_AGGSTEP:
|
||||
** An input row can be discarded after the window functions xStep()
|
||||
** callbacks have been invoked in it.
|
||||
**
|
||||
** start,current,end
|
||||
** Consider a window-frame similar to the following:
|
||||
**
|
||||
** (ORDER BY a, b GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING)
|
||||
**
|
||||
** The windows functions implmentation caches the input rows in a temp
|
||||
** table, sorted by "a, b" (it actually populates the cache lazily, and
|
||||
** aggressively removes rows once they are no longer required, but that's
|
||||
** a mere detail). It keeps three cursors open on the temp table. One
|
||||
** (current) that points to the next row to return to the query engine
|
||||
** once its window function values have been calculated. Another (end)
|
||||
** points to the next row to call the xStep() method of each window function
|
||||
** on (so that it is 2 groups ahead of current). And a third (start) that
|
||||
** points to the next row to call the xInverse() method of each window
|
||||
** function on.
|
||||
**
|
||||
** Each cursor (start, current and end) consists of a VDBE cursor
|
||||
** (WindowCsrAndReg.csr) and an array of registers (starting at
|
||||
** WindowCodeArg.reg) that always contains a copy of the peer values
|
||||
** read from the corresponding cursor.
|
||||
**
|
||||
** Depending on the window-frame in question, all three cursors may not
|
||||
** be required. In this case both WindowCodeArg.csr and reg are set to
|
||||
** 0.
|
||||
*/
|
||||
struct WindowCodeArg {
|
||||
Parse *pParse; /* Parse context */
|
||||
Window *pMWin; /* First in list of functions being processed */
|
||||
Vdbe *pVdbe; /* VDBE object */
|
||||
int addrGosub; /* OP_Gosub to this address to return one row */
|
||||
int regGosub; /* Register used with OP_Gosub(addrGosub) */
|
||||
int regArg; /* First in array of accumulator registers */
|
||||
int eDelete; /* See above */
|
||||
|
||||
WindowCsrAndReg start;
|
||||
WindowCsrAndReg current;
|
||||
WindowCsrAndReg end;
|
||||
};
|
||||
|
||||
/*
|
||||
** Generate VM code to read the window frames peer values from cursor csr into
|
||||
** an array of registers starting at reg.
|
||||
*/
|
||||
static void windowReadPeerValues(
|
||||
WindowCodeArg *p,
|
||||
int csr,
|
||||
int reg
|
||||
){
|
||||
Window *pMWin = p->pMWin;
|
||||
ExprList *pOrderBy = pMWin->pOrderBy;
|
||||
if( pOrderBy ){
|
||||
Vdbe *v = sqlite3GetVdbe(p->pParse);
|
||||
ExprList *pPart = pMWin->pPartition;
|
||||
int iColOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0);
|
||||
int i;
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, csr, iColOff+i, reg+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate VM code to invoke either xStep() (if bInverse is 0) or
|
||||
** xInverse (if bInverse is non-zero) for each window function in the
|
||||
@@ -1383,20 +1530,27 @@ static int windowArgCount(Window *pWin){
|
||||
** number of rows in the current partition.
|
||||
*/
|
||||
static void windowAggStep(
|
||||
Parse *pParse,
|
||||
WindowCodeArg *p,
|
||||
Window *pMWin, /* Linked list of window functions */
|
||||
int csr, /* Read arguments from this cursor */
|
||||
int bInverse, /* True to invoke xInverse instead of xStep */
|
||||
int reg /* Array of registers */
|
||||
){
|
||||
Parse *pParse = p->pParse;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
Window *pWin;
|
||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||
FuncDef *pFunc = pWin->pFunc;
|
||||
int regArg;
|
||||
int nArg = windowArgCount(pWin);
|
||||
int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
|
||||
int i;
|
||||
|
||||
assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );
|
||||
|
||||
/* All OVER clauses in the same window function aggregate step must
|
||||
** be the same. */
|
||||
assert( pWin==pMWin || sqlite3WindowCompare(pParse,pWin,pMWin,0)==0 );
|
||||
|
||||
for(i=0; i<nArg; i++){
|
||||
if( i!=1 || pFunc->zName!=nth_valueName ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i);
|
||||
@@ -1434,14 +1588,30 @@ static void windowAggStep(
|
||||
int addrIf = 0;
|
||||
if( pWin->pFilter ){
|
||||
int regTmp;
|
||||
assert( nArg==0 || nArg==pWin->pOwner->x.pList->nExpr );
|
||||
assert( nArg || pWin->pOwner->x.pList==0 );
|
||||
assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
|
||||
assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 );
|
||||
regTmp = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
|
||||
addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3ReleaseTempReg(pParse, regTmp);
|
||||
}
|
||||
|
||||
if( pWin->bExprArgs ){
|
||||
int iStart = sqlite3VdbeCurrentAddr(v);
|
||||
VdbeOp *pOp, *pEnd;
|
||||
|
||||
nArg = pWin->pOwner->x.pList->nExpr;
|
||||
regArg = sqlite3GetTempRange(pParse, nArg);
|
||||
sqlite3ExprCodeExprList(pParse, pWin->pOwner->x.pList, regArg, 0, 0);
|
||||
|
||||
pEnd = sqlite3VdbeGetOp(v, -1);
|
||||
for(pOp=sqlite3VdbeGetOp(v, iStart); pOp<=pEnd; pOp++){
|
||||
if( pOp->opcode==OP_Column && pOp->p1==pWin->iEphCsr ){
|
||||
pOp->p1 = csr;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
||||
CollSeq *pColl;
|
||||
assert( nArg>0 );
|
||||
@@ -1452,32 +1622,14 @@ static void windowAggStep(
|
||||
bInverse, regArg, pWin->regAccum);
|
||||
sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)nArg);
|
||||
if( pWin->bExprArgs ){
|
||||
sqlite3ReleaseTempRange(pParse, regArg, nArg);
|
||||
}
|
||||
if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct WindowCodeArg WindowCodeArg;
|
||||
typedef struct WindowCsrAndReg WindowCsrAndReg;
|
||||
struct WindowCsrAndReg {
|
||||
int csr;
|
||||
int reg;
|
||||
};
|
||||
|
||||
struct WindowCodeArg {
|
||||
Parse *pParse;
|
||||
Window *pMWin;
|
||||
Vdbe *pVdbe;
|
||||
int regGosub;
|
||||
int addrGosub;
|
||||
int regArg;
|
||||
int eDelete;
|
||||
|
||||
WindowCsrAndReg start;
|
||||
WindowCsrAndReg current;
|
||||
WindowCsrAndReg end;
|
||||
};
|
||||
|
||||
/*
|
||||
** Values that may be passed as the second argument to windowCodeOp().
|
||||
*/
|
||||
@@ -1485,28 +1637,6 @@ struct WindowCodeArg {
|
||||
#define WINDOW_AGGINVERSE 2
|
||||
#define WINDOW_AGGSTEP 3
|
||||
|
||||
/*
|
||||
** Generate VM code to read the window frames peer values from cursor csr into
|
||||
** an array of registers starting at reg.
|
||||
*/
|
||||
static void windowReadPeerValues(
|
||||
WindowCodeArg *p,
|
||||
int csr,
|
||||
int reg
|
||||
){
|
||||
Window *pMWin = p->pMWin;
|
||||
ExprList *pOrderBy = pMWin->pOrderBy;
|
||||
if( pOrderBy ){
|
||||
Vdbe *v = sqlite3GetVdbe(p->pParse);
|
||||
ExprList *pPart = pMWin->pPartition;
|
||||
int iColOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0);
|
||||
int i;
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, csr, iColOff+i, reg+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate VM code to invoke either xValue() (bFin==0) or xFinalize()
|
||||
** (bFin==1) for each window function in the linked list starting at
|
||||
@@ -1567,8 +1697,12 @@ static void windowFullScan(WindowCodeArg *p){
|
||||
int lblNext;
|
||||
int lblBrk;
|
||||
int addrNext;
|
||||
int csr = pMWin->csrApp;
|
||||
int csr;
|
||||
|
||||
VdbeModuleComment((v, "windowFullScan begin"));
|
||||
|
||||
assert( pMWin!=0 );
|
||||
csr = pMWin->csrApp;
|
||||
nPeer = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0);
|
||||
|
||||
lblNext = sqlite3VdbeMakeLabel(pParse);
|
||||
@@ -1623,7 +1757,7 @@ static void windowFullScan(WindowCodeArg *p){
|
||||
if( addrEq ) sqlite3VdbeJumpHere(v, addrEq);
|
||||
}
|
||||
|
||||
windowAggStep(pParse, pMWin, csr, 0, p->regArg);
|
||||
windowAggStep(p, pMWin, csr, 0, p->regArg);
|
||||
|
||||
sqlite3VdbeResolveLabel(v, lblNext);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, csr, addrNext);
|
||||
@@ -1638,6 +1772,7 @@ static void windowFullScan(WindowCodeArg *p){
|
||||
}
|
||||
|
||||
windowAggFinal(p, 1);
|
||||
VdbeModuleComment((v, "windowFullScan end"));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1812,34 +1947,46 @@ static void windowIfNewPeer(
|
||||
/*
|
||||
** This function is called as part of generating VM programs for RANGE
|
||||
** offset PRECEDING/FOLLOWING frame boundaries. Assuming "ASC" order for
|
||||
** the ORDER BY term in the window, it generates code equivalent to:
|
||||
** the ORDER BY term in the window, and that argument op is OP_Ge, it generates
|
||||
** code equivalent to:
|
||||
**
|
||||
** if( csr1.peerVal + regVal >= csr2.peerVal ) goto lbl;
|
||||
**
|
||||
** A special type of arithmetic is used such that if csr.peerVal is not
|
||||
** a numeric type (real or integer), then the result of the addition is
|
||||
** a copy of csr1.peerVal.
|
||||
** The value of parameter op may also be OP_Gt or OP_Le. In these cases the
|
||||
** operator in the above pseudo-code is replaced with ">" or "<=", respectively.
|
||||
**
|
||||
** If the sort-order for the ORDER BY term in the window is DESC, then the
|
||||
** comparison is reversed. Instead of adding regVal to csr1.peerVal, it is
|
||||
** subtracted. And the comparison operator is inverted to - ">=" becomes "<=",
|
||||
** ">" becomes "<", and so on. So, with DESC sort order, if the argument op
|
||||
** is OP_Ge, the generated code is equivalent to:
|
||||
**
|
||||
** if( csr1.peerVal - regVal <= csr2.peerVal ) goto lbl;
|
||||
**
|
||||
** A special type of arithmetic is used such that if csr1.peerVal is not
|
||||
** a numeric type (real or integer), then the result of the addition addition
|
||||
** or subtraction is a a copy of csr1.peerVal.
|
||||
*/
|
||||
static void windowCodeRangeTest(
|
||||
WindowCodeArg *p,
|
||||
int op, /* OP_Ge or OP_Gt */
|
||||
int csr1,
|
||||
int regVal,
|
||||
int csr2,
|
||||
int lbl
|
||||
int op, /* OP_Ge, OP_Gt, or OP_Le */
|
||||
int csr1, /* Cursor number for cursor 1 */
|
||||
int regVal, /* Register containing non-negative number */
|
||||
int csr2, /* Cursor number for cursor 2 */
|
||||
int lbl /* Jump destination if condition is true */
|
||||
){
|
||||
Parse *pParse = p->pParse;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int reg1 = sqlite3GetTempReg(pParse);
|
||||
int reg2 = sqlite3GetTempReg(pParse);
|
||||
int arith = OP_Add;
|
||||
int addrGe;
|
||||
|
||||
int regString = ++pParse->nMem;
|
||||
ExprList *pOrderBy = p->pMWin->pOrderBy; /* ORDER BY clause for window */
|
||||
int reg1 = sqlite3GetTempReg(pParse); /* Reg. for csr1.peerVal+regVal */
|
||||
int reg2 = sqlite3GetTempReg(pParse); /* Reg. for csr2.peerVal */
|
||||
int regString = ++pParse->nMem; /* Reg. for constant value '' */
|
||||
int arith = OP_Add; /* OP_Add or OP_Subtract */
|
||||
int addrGe; /* Jump destination */
|
||||
|
||||
assert( op==OP_Ge || op==OP_Gt || op==OP_Le );
|
||||
assert( p->pMWin->pOrderBy && p->pMWin->pOrderBy->nExpr==1 );
|
||||
if( p->pMWin->pOrderBy->a[0].sortOrder ){
|
||||
assert( pOrderBy && pOrderBy->nExpr==1 );
|
||||
if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_DESC ){
|
||||
switch( op ){
|
||||
case OP_Ge: op = OP_Le; break;
|
||||
case OP_Gt: op = OP_Lt; break;
|
||||
@@ -1848,27 +1995,95 @@ static void windowCodeRangeTest(
|
||||
arith = OP_Subtract;
|
||||
}
|
||||
|
||||
/* Read the peer-value from each cursor into a register */
|
||||
windowReadPeerValues(p, csr1, reg1);
|
||||
windowReadPeerValues(p, csr2, reg2);
|
||||
|
||||
/* Check if the peer value for csr1 value is a text or blob by comparing
|
||||
** it to the smallest possible string - ''. If it is, jump over the
|
||||
** OP_Add or OP_Subtract operation and proceed directly to the comparison. */
|
||||
VdbeModuleComment((v, "CodeRangeTest: if( R%d %s R%d %s R%d ) goto lbl",
|
||||
reg1, (arith==OP_Add ? "+" : "-"), regVal,
|
||||
((op==OP_Ge) ? ">=" : (op==OP_Le) ? "<=" : (op==OP_Gt) ? ">" : "<"), reg2
|
||||
));
|
||||
|
||||
/* Register reg1 currently contains csr1.peerVal (the peer-value from csr1).
|
||||
** This block adds (or subtracts for DESC) the numeric value in regVal
|
||||
** from it. Or, if reg1 is not numeric (it is a NULL, a text value or a blob),
|
||||
** then leave reg1 as it is. In pseudo-code, this is implemented as:
|
||||
**
|
||||
** if( reg1>='' ) goto addrGe;
|
||||
** reg1 = reg1 +/- regVal
|
||||
** addrGe:
|
||||
**
|
||||
** Since all strings and blobs are greater-than-or-equal-to an empty string,
|
||||
** the add/subtract is skipped for these, as required. If reg1 is a NULL,
|
||||
** then the arithmetic is performed, but since adding or subtracting from
|
||||
** NULL is always NULL anyway, this case is handled as required too. */
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC);
|
||||
addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1);
|
||||
sqlite3VdbeJumpHere(v, addrGe);
|
||||
|
||||
/* If the BIGNULL flag is set for the ORDER BY, then it is required to
|
||||
** consider NULL values to be larger than all other values, instead of
|
||||
** the usual smaller. The VDBE opcodes OP_Ge and so on do not handle this
|
||||
** (and adding that capability causes a performance regression), so
|
||||
** instead if the BIGNULL flag is set then cases where either reg1 or
|
||||
** reg2 are NULL are handled separately in the following block. The code
|
||||
** generated is equivalent to:
|
||||
**
|
||||
** if( reg1 IS NULL ){
|
||||
** if( op==OP_Ge ) goto lbl;
|
||||
** if( op==OP_Gt && reg2 IS NOT NULL ) goto lbl;
|
||||
** if( op==OP_Le && reg2 IS NULL ) goto lbl;
|
||||
** }else if( reg2 IS NULL ){
|
||||
** if( op==OP_Le ) goto lbl;
|
||||
** }
|
||||
**
|
||||
** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is
|
||||
** not taken, control jumps over the comparison operator coded below this
|
||||
** block. */
|
||||
if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_BIGNULL ){
|
||||
/* This block runs if reg1 contains a NULL. */
|
||||
int addr = sqlite3VdbeAddOp1(v, OP_NotNull, reg1); VdbeCoverage(v);
|
||||
switch( op ){
|
||||
case OP_Ge:
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, lbl);
|
||||
break;
|
||||
case OP_Gt:
|
||||
sqlite3VdbeAddOp2(v, OP_NotNull, reg2, lbl);
|
||||
VdbeCoverage(v);
|
||||
break;
|
||||
case OP_Le:
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl);
|
||||
VdbeCoverage(v);
|
||||
break;
|
||||
default: assert( op==OP_Lt ); /* no-op */ break;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
|
||||
|
||||
/* This block runs if reg1 is not NULL, but reg2 is. */
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v);
|
||||
if( op==OP_Gt || op==OP_Ge ){
|
||||
sqlite3VdbeChangeP2(v, -1, sqlite3VdbeCurrentAddr(v)+1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compare registers reg2 and reg1, taking the jump if required. Note that
|
||||
** control skips over this test if the BIGNULL flag is set and either
|
||||
** reg1 or reg2 contain a NULL value. */
|
||||
sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
|
||||
assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le );
|
||||
testcase(op==OP_Ge); VdbeCoverageIf(v, op==OP_Ge);
|
||||
testcase(op==OP_Lt); VdbeCoverageIf(v, op==OP_Lt);
|
||||
testcase(op==OP_Le); VdbeCoverageIf(v, op==OP_Le);
|
||||
testcase(op==OP_Gt); VdbeCoverageIf(v, op==OP_Gt);
|
||||
|
||||
sqlite3ReleaseTempReg(pParse, reg1);
|
||||
sqlite3ReleaseTempReg(pParse, reg2);
|
||||
|
||||
VdbeModuleComment((v, "CodeRangeTest: end"));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1888,9 +2103,7 @@ static int windowCodeOp(
|
||||
Window *pMWin = p->pMWin;
|
||||
int ret = 0;
|
||||
Vdbe *v = p->pVdbe;
|
||||
int addrIf = 0;
|
||||
int addrContinue = 0;
|
||||
int addrGoto = 0;
|
||||
int bPeer = (pMWin->eFrmType!=TK_ROWS);
|
||||
|
||||
int lblDone = sqlite3VdbeMakeLabel(pParse);
|
||||
@@ -1923,7 +2136,7 @@ static int windowCodeOp(
|
||||
);
|
||||
}
|
||||
}else{
|
||||
addrIf = sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, 0, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, lblDone, 1);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
}
|
||||
@@ -1932,6 +2145,25 @@ static int windowCodeOp(
|
||||
windowAggFinal(p, 0);
|
||||
}
|
||||
addrContinue = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
/* If this is a (RANGE BETWEEN a FOLLOWING AND b FOLLOWING) or
|
||||
** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the
|
||||
** start cursor does not advance past the end cursor within the
|
||||
** temporary table. It otherwise might, if (a>b). */
|
||||
if( pMWin->eStart==pMWin->eEnd && regCountdown
|
||||
&& pMWin->eFrmType==TK_RANGE && op==WINDOW_AGGINVERSE
|
||||
){
|
||||
int regRowid1 = sqlite3GetTempReg(pParse);
|
||||
int regRowid2 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, p->start.csr, regRowid1);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid2);
|
||||
sqlite3VdbeAddOp3(v, OP_Ge, regRowid2, lblDone, regRowid1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3ReleaseTempReg(pParse, regRowid1);
|
||||
sqlite3ReleaseTempReg(pParse, regRowid2);
|
||||
assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING );
|
||||
}
|
||||
|
||||
switch( op ){
|
||||
case WINDOW_RETURN_ROW:
|
||||
csr = p->current.csr;
|
||||
@@ -1946,7 +2178,7 @@ static int windowCodeOp(
|
||||
assert( pMWin->regEndRowid );
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regStartRowid, 1);
|
||||
}else{
|
||||
windowAggStep(pParse, pMWin, csr, 1, p->regArg);
|
||||
windowAggStep(p, pMWin, csr, 1, p->regArg);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1958,7 +2190,7 @@ static int windowCodeOp(
|
||||
assert( pMWin->regEndRowid );
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regEndRowid, 1);
|
||||
}else{
|
||||
windowAggStep(pParse, pMWin, csr, 0, p->regArg);
|
||||
windowAggStep(p, pMWin, csr, 0, p->regArg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1976,7 +2208,7 @@ static int windowCodeOp(
|
||||
sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+1+bPeer);
|
||||
VdbeCoverage(v);
|
||||
if( bPeer ){
|
||||
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, lblDone);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1992,8 +2224,6 @@ static int windowCodeOp(
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNextRange);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, lblDone);
|
||||
if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto);
|
||||
if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2009,6 +2239,7 @@ Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(Window));
|
||||
if( pNew ){
|
||||
pNew->zName = sqlite3DbStrDup(db, p->zName);
|
||||
pNew->zBase = sqlite3DbStrDup(db, p->zBase);
|
||||
pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0);
|
||||
pNew->pFunc = p->pFunc;
|
||||
pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0);
|
||||
@@ -2017,9 +2248,11 @@ Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){
|
||||
pNew->eEnd = p->eEnd;
|
||||
pNew->eStart = p->eStart;
|
||||
pNew->eExclude = p->eExclude;
|
||||
pNew->regResult = p->regResult;
|
||||
pNew->pStart = sqlite3ExprDup(db, p->pStart, 0);
|
||||
pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0);
|
||||
pNew->pOwner = pOwner;
|
||||
pNew->bImplicitFrame = p->bImplicitFrame;
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
@@ -2343,7 +2576,7 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
||||
** regEnd = <expr2>
|
||||
** regStart = <expr1>
|
||||
** }else{
|
||||
** if( (csrEnd.key + regEnd) <= csrCurrent.key ){
|
||||
** while( (csrEnd.key + regEnd) <= csrCurrent.key ){
|
||||
** AGGSTEP
|
||||
** }
|
||||
** while( (csrStart.key + regStart) < csrCurrent.key ){
|
||||
@@ -2416,8 +2649,6 @@ void sqlite3WindowCodeStep(
|
||||
int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */
|
||||
int addrInteger = 0; /* Address of OP_Integer */
|
||||
int addrEmpty; /* Address of OP_Rewind in flush: */
|
||||
int regStart = 0; /* Value of <expr> PRECEDING */
|
||||
int regEnd = 0; /* Value of <expr> FOLLOWING */
|
||||
int regNew; /* Array of registers holding new input row */
|
||||
int regRecord; /* regNew array in record form */
|
||||
int regRowid; /* Rowid for regRecord in eph table */
|
||||
@@ -2426,6 +2657,8 @@ void sqlite3WindowCodeStep(
|
||||
int regFlushPart = 0; /* Register for "Gosub flush_partition" */
|
||||
WindowCodeArg s; /* Context object for sub-routines */
|
||||
int lblWhereEnd; /* Label just before sqlite3WhereEnd() code */
|
||||
int regStart = 0; /* Value of <expr> PRECEDING */
|
||||
int regEnd = 0; /* Value of <expr> FOLLOWING */
|
||||
|
||||
assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT
|
||||
|| pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED
|
||||
@@ -2556,14 +2789,14 @@ void sqlite3WindowCodeStep(
|
||||
|
||||
if( regStart ){
|
||||
sqlite3ExprCode(pParse, pMWin->pStart, regStart);
|
||||
windowCheckValue(pParse, regStart, 0 + (pMWin->eFrmType==TK_RANGE ? 3 : 0));
|
||||
windowCheckValue(pParse, regStart, 0 + (pMWin->eFrmType==TK_RANGE?3:0));
|
||||
}
|
||||
if( regEnd ){
|
||||
sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
|
||||
windowCheckValue(pParse, regEnd, 1 + (pMWin->eFrmType==TK_RANGE ? 3 : 0));
|
||||
windowCheckValue(pParse, regEnd, 1 + (pMWin->eFrmType==TK_RANGE?3:0));
|
||||
}
|
||||
|
||||
if( pMWin->eStart==pMWin->eEnd && regStart ){
|
||||
if( pMWin->eFrmType!=TK_RANGE && pMWin->eStart==pMWin->eEnd && regStart ){
|
||||
int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le);
|
||||
int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd);
|
||||
VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound <expr> */
|
||||
|
||||
Reference in New Issue
Block a user