Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e1c4226ee | |||
| 9ea258d712 | |||
| dd1bb43ab5 | |||
| 96a27f4cbb | |||
| c8d3e836ca | |||
| ee3333b202 | |||
| 9715f0e544 | |||
| 6b4fbabd6a | |||
| 3fb153cb29 | |||
| f7fa4e71f4 | |||
| 9418921c59 | |||
| ee92eb80db | |||
| 2336c935af | |||
| e694139788 | |||
| 0d236a8bb0 | |||
| 701caf1eb1 | |||
| 7b458519f2 | |||
| e4eb0497d8 | |||
| 614c6a09f7 | |||
| 2617c9bdd8 | |||
| ffe280596e | |||
| f8a2e8c2d2 | |||
| 050b124ce2 | |||
| 30f01249a3 | |||
| 313e6fd222 | |||
| ad012d09dc | |||
| e780764b4e | |||
| 3f4df4c6f3 | |||
| a1f5c0c90b | |||
| ab314001b8 | |||
| 8d5cee166e | |||
| c478c8daec | |||
| 4b2667c8b8 | |||
| 874080bbb6 | |||
| ed71298085 | |||
| 33543c237b | |||
| e08e8d6b61 | |||
| 181a1167dc | |||
| ab31a8450b | |||
| 7555581fc1 | |||
| bb6783b86f | |||
| bc43995f99 | |||
| 6ab3eb5d0e | |||
| 6f654a40e8 | |||
| 4b17369579 | |||
| b9e6a73866 | |||
| 69bfa55279 | |||
| a1188d6d93 | |||
| 0c3233be0b | |||
| 39c9d3a367 | |||
| 0619838c55 | |||
| dc62daca86 | |||
| a059e99ca8 | |||
| 0027e98b85 | |||
| bff6fe1f40 | |||
| bda00fbdb7 | |||
| cfcca02765 | |||
| e2bc6552fe | |||
| 4bee5599c0 | |||
| 940464b1dc | |||
| 624edacf6a | |||
| ddf4747053 | |||
| 6887e8facd | |||
| b6d5a43b8a | |||
| b65b3e429a | |||
| 147fd88268 | |||
| 06f60d8e87 | |||
| 14d8855b8f | |||
| 31d6fd5507 | |||
| 1a17b44231 | |||
| 399c7e21e4 | |||
| b1ed717f18 | |||
| d97cda43ab | |||
| 46967de2ec | |||
| 7c88bcd473 | |||
| d0a537100c | |||
| 44ae27ac32 | |||
| 929b695111 |
+2
-2
@@ -21,7 +21,7 @@ USE_AMALGAMATION = 1
|
||||
# Set this non-0 to enable full warnings (-W4, etc) when compiling.
|
||||
#
|
||||
!IFNDEF USE_FULLWARN
|
||||
USE_FULLWARN = 0
|
||||
USE_FULLWARN = 1
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to enable treating warnings as errors (-WX, etc) when
|
||||
@@ -1562,7 +1562,7 @@ $(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
|
||||
sqlite3.def: libsqlite3.lib
|
||||
echo EXPORTS > sqlite3.def
|
||||
dumpbin /all libsqlite3.lib \
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset)?_[^@]*)(?:@\d+)?$$" \1 \
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup)?_[^@]*)(?:@\d+)?$$" \1 \
|
||||
| sort >> sqlite3.def
|
||||
# <</block2>>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ TOP = .
|
||||
# Set this non-0 to enable full warnings (-W4, etc) when compiling.
|
||||
#
|
||||
!IFNDEF USE_FULLWARN
|
||||
USE_FULLWARN = 0
|
||||
USE_FULLWARN = 1
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to enable treating warnings as errors (-WX, etc) when
|
||||
@@ -954,7 +954,7 @@ Replace.exe:
|
||||
sqlite3.def: Replace.exe $(LIBOBJ)
|
||||
echo EXPORTS > sqlite3.def
|
||||
dumpbin /all $(LIBOBJ) \
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
|
||||
| sort >> sqlite3.def
|
||||
|
||||
$(SQLITE3EXE): $(TOP)\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
|
||||
|
||||
+132
-135
@@ -372,8 +372,8 @@ int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
||||
}
|
||||
|
||||
/*
|
||||
** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to a
|
||||
** 32-bit integer before it is returned.
|
||||
** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to
|
||||
** a non-negative 32-bit integer before it is returned.
|
||||
*/
|
||||
int sqlite3Fts3GetVarint32(const char *p, int *pi){
|
||||
u32 a;
|
||||
@@ -389,7 +389,9 @@ int sqlite3Fts3GetVarint32(const char *p, int *pi){
|
||||
GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *pi, 3);
|
||||
GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *pi, 4);
|
||||
a = (a & 0x0FFFFFFF );
|
||||
*pi = (int)(a | ((u32)(*p & 0x0F) << 28));
|
||||
*pi = (int)(a | ((u32)(*p & 0x07) << 28));
|
||||
assert( 0==(a & 0x80000000) );
|
||||
assert( *pi>=0 );
|
||||
return 5;
|
||||
}
|
||||
|
||||
@@ -1219,65 +1221,66 @@ static int fts3InitVtab(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( iOpt==SizeofArray(aFts4Opt) ){
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
switch( iOpt ){
|
||||
case 0: /* MATCHINFO */
|
||||
if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
bNoDocsize = 1;
|
||||
break;
|
||||
switch( iOpt ){
|
||||
case 0: /* MATCHINFO */
|
||||
if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
bNoDocsize = 1;
|
||||
break;
|
||||
|
||||
case 1: /* PREFIX */
|
||||
sqlite3_free(zPrefix);
|
||||
zPrefix = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
case 1: /* PREFIX */
|
||||
sqlite3_free(zPrefix);
|
||||
zPrefix = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
case 2: /* COMPRESS */
|
||||
sqlite3_free(zCompress);
|
||||
zCompress = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
case 2: /* COMPRESS */
|
||||
sqlite3_free(zCompress);
|
||||
zCompress = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
case 3: /* UNCOMPRESS */
|
||||
sqlite3_free(zUncompress);
|
||||
zUncompress = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
case 3: /* UNCOMPRESS */
|
||||
sqlite3_free(zUncompress);
|
||||
zUncompress = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
case 4: /* ORDER */
|
||||
if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
|
||||
&& (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
|
||||
){
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
|
||||
break;
|
||||
case 4: /* ORDER */
|
||||
if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
|
||||
&& (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
|
||||
){
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
|
||||
break;
|
||||
|
||||
case 5: /* CONTENT */
|
||||
sqlite3_free(zContent);
|
||||
zContent = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
case 5: /* CONTENT */
|
||||
sqlite3_free(zContent);
|
||||
zContent = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
case 6: /* LANGUAGEID */
|
||||
assert( iOpt==6 );
|
||||
sqlite3_free(zLanguageid);
|
||||
zLanguageid = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
case 6: /* LANGUAGEID */
|
||||
assert( iOpt==6 );
|
||||
sqlite3_free(zLanguageid);
|
||||
zLanguageid = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
case 7: /* NOTINDEXED */
|
||||
azNotindexed[nNotindexed++] = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
}
|
||||
case 7: /* NOTINDEXED */
|
||||
azNotindexed[nNotindexed++] = zVal;
|
||||
zVal = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( iOpt==SizeofArray(aFts4Opt) );
|
||||
sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
}
|
||||
sqlite3_free(zVal);
|
||||
}
|
||||
@@ -1846,7 +1849,8 @@ static int fts3ScanInteriorNode(
|
||||
isFirstTerm = 0;
|
||||
zCsr += fts3GetVarint32(zCsr, &nSuffix);
|
||||
|
||||
if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
|
||||
assert( nPrefix>=0 && nSuffix>=0 );
|
||||
if( &zCsr[nSuffix]>zEnd ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
goto finish_scan;
|
||||
}
|
||||
@@ -2656,7 +2660,7 @@ int sqlite3Fts3FirstFilter(
|
||||
fts3ColumnlistCopy(0, &p);
|
||||
}
|
||||
|
||||
while( p<pEnd && *p==0x01 ){
|
||||
while( p<pEnd ){
|
||||
sqlite3_int64 iCol;
|
||||
p++;
|
||||
p += sqlite3Fts3GetVarint(p, &iCol);
|
||||
@@ -3336,33 +3340,38 @@ static int fts3ColumnMethod(
|
||||
/* The column value supplied by SQLite must be in range. */
|
||||
assert( iCol>=0 && iCol<=p->nColumn+2 );
|
||||
|
||||
if( iCol==p->nColumn+1 ){
|
||||
/* This call is a request for the "docid" column. Since "docid" is an
|
||||
** alias for "rowid", use the xRowid() method to obtain the value.
|
||||
*/
|
||||
sqlite3_result_int64(pCtx, pCsr->iPrevId);
|
||||
}else if( iCol==p->nColumn ){
|
||||
/* The extra column whose name is the same as the table.
|
||||
** Return a blob which is a pointer to the cursor. */
|
||||
sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
|
||||
}else if( iCol==p->nColumn+2 && pCsr->pExpr ){
|
||||
sqlite3_result_int64(pCtx, pCsr->iLangid);
|
||||
}else{
|
||||
/* The requested column is either a user column (one that contains
|
||||
** indexed data), or the language-id column. */
|
||||
rc = fts3CursorSeek(0, pCsr);
|
||||
switch( iCol-p->nColumn ){
|
||||
case 0:
|
||||
/* The special 'table-name' column */
|
||||
sqlite3_result_blob(pCtx, &pCsr, sizeof(Fts3Cursor*), SQLITE_TRANSIENT);
|
||||
sqlite3_result_subtype(pCtx, SQLITE_BLOB);
|
||||
break;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iCol==p->nColumn+2 ){
|
||||
int iLangid = 0;
|
||||
if( p->zLanguageid ){
|
||||
iLangid = sqlite3_column_int(pCsr->pStmt, p->nColumn+1);
|
||||
}
|
||||
sqlite3_result_int(pCtx, iLangid);
|
||||
}else if( sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
|
||||
case 1:
|
||||
/* The docid column */
|
||||
sqlite3_result_int64(pCtx, pCsr->iPrevId);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if( pCsr->pExpr ){
|
||||
sqlite3_result_int64(pCtx, pCsr->iLangid);
|
||||
break;
|
||||
}else if( p->zLanguageid==0 ){
|
||||
sqlite3_result_int(pCtx, 0);
|
||||
break;
|
||||
}else{
|
||||
iCol = p->nColumn;
|
||||
/* fall-through */
|
||||
}
|
||||
|
||||
default:
|
||||
/* A user column. Or, if this is a full-table scan, possibly the
|
||||
** language-id column. Seek the cursor. */
|
||||
rc = fts3CursorSeek(0, pCsr);
|
||||
if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){
|
||||
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
|
||||
@@ -3442,17 +3451,11 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
|
||||
static int fts3SetHasStat(Fts3Table *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->bHasStat==2 ){
|
||||
const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'";
|
||||
char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName);
|
||||
if( zSql ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc==SQLITE_OK ) p->bHasStat = (u8)bHasStat;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
char *zTbl = sqlite3_mprintf("%s_stat", p->zName);
|
||||
if( zTbl ){
|
||||
int res = sqlite3_table_column_metadata(p->db, p->zDb, zTbl, 0,0,0,0,0,0);
|
||||
sqlite3_free(zTbl);
|
||||
p->bHasStat = (res==SQLITE_OK);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -3559,18 +3562,16 @@ static int fts3FunctionArg(
|
||||
sqlite3_value *pVal, /* argv[0] passed to function */
|
||||
Fts3Cursor **ppCsr /* OUT: Store cursor handle here */
|
||||
){
|
||||
Fts3Cursor *pRet;
|
||||
if( sqlite3_value_type(pVal)!=SQLITE_BLOB
|
||||
|| sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *)
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
if( sqlite3_value_subtype(pVal)==SQLITE_BLOB ){
|
||||
*ppCsr = *(Fts3Cursor**)sqlite3_value_blob(pVal);
|
||||
}else{
|
||||
char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc);
|
||||
sqlite3_result_error(pContext, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
return SQLITE_ERROR;
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *));
|
||||
*ppCsr = pRet;
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3957,7 +3958,7 @@ int sqlite3Fts3Init(sqlite3 *db){
|
||||
#endif
|
||||
|
||||
/* Create the virtual table wrapper around the hash-table and overload
|
||||
** the two scalar functions. If this is successful, register the
|
||||
** the four scalar functions. If this is successful, register the
|
||||
** module with sqlite.
|
||||
*/
|
||||
if( SQLITE_OK==rc
|
||||
@@ -4540,7 +4541,7 @@ static int fts3EvalIncrPhraseNext(
|
||||
** one incremental token. In which case the bIncr flag is set. */
|
||||
assert( p->bIncr==1 );
|
||||
|
||||
if( p->nToken==1 && p->bIncr ){
|
||||
if( p->nToken==1 ){
|
||||
rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
|
||||
&pDL->iDocid, &pDL->pList, &pDL->nList
|
||||
);
|
||||
@@ -4773,6 +4774,7 @@ static void fts3EvalTokenCosts(
|
||||
** the number of overflow pages consumed by a record B bytes in size.
|
||||
*/
|
||||
static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
||||
int rc = SQLITE_OK;
|
||||
if( pCsr->nRowAvg==0 ){
|
||||
/* The average document size, which is required to calculate the cost
|
||||
** of each doclist, has not yet been determined. Read the required
|
||||
@@ -4785,7 +4787,6 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
||||
** data stored in all rows of each column of the table, from left
|
||||
** to right.
|
||||
*/
|
||||
int rc;
|
||||
Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
|
||||
sqlite3_stmt *pStmt;
|
||||
sqlite3_int64 nDoc = 0;
|
||||
@@ -4812,11 +4813,10 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
||||
pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz);
|
||||
assert( pCsr->nRowAvg>0 );
|
||||
rc = sqlite3_reset(pStmt);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
|
||||
*pnPage = pCsr->nRowAvg;
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5166,7 +5166,8 @@ static void fts3EvalNextRow(
|
||||
pExpr->iDocid = pLeft->iDocid;
|
||||
pExpr->bEof = (pLeft->bEof || pRight->bEof);
|
||||
if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){
|
||||
if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){
|
||||
assert( pRight->eType==FTSQUERY_PHRASE );
|
||||
if( pRight->pPhrase->doclist.aAll ){
|
||||
Fts3Doclist *pDl = &pRight->pPhrase->doclist;
|
||||
while( *pRc==SQLITE_OK && pRight->bEof==0 ){
|
||||
memset(pDl->pList, 0, pDl->nList);
|
||||
@@ -5195,7 +5196,7 @@ static void fts3EvalNextRow(
|
||||
|
||||
if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){
|
||||
fts3EvalNextRow(pCsr, pLeft, pRc);
|
||||
}else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){
|
||||
}else if( pLeft->bEof || iCmp>0 ){
|
||||
fts3EvalNextRow(pCsr, pRight, pRc);
|
||||
}else{
|
||||
fts3EvalNextRow(pCsr, pLeft, pRc);
|
||||
@@ -5287,7 +5288,6 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
||||
*/
|
||||
if( *pRc==SQLITE_OK
|
||||
&& pExpr->eType==FTSQUERY_NEAR
|
||||
&& pExpr->bEof==0
|
||||
&& (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
|
||||
){
|
||||
Fts3Expr *p;
|
||||
@@ -5296,42 +5296,39 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
||||
|
||||
/* Allocate temporary working space. */
|
||||
for(p=pExpr; p->pLeft; p=p->pLeft){
|
||||
assert( p->pRight->pPhrase->doclist.nList>0 );
|
||||
nTmp += p->pRight->pPhrase->doclist.nList;
|
||||
}
|
||||
nTmp += p->pPhrase->doclist.nList;
|
||||
if( nTmp==0 ){
|
||||
aTmp = sqlite3_malloc(nTmp*2);
|
||||
if( !aTmp ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
res = 0;
|
||||
}else{
|
||||
aTmp = sqlite3_malloc(nTmp*2);
|
||||
if( !aTmp ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
res = 0;
|
||||
}else{
|
||||
char *aPoslist = p->pPhrase->doclist.pList;
|
||||
int nToken = p->pPhrase->nToken;
|
||||
char *aPoslist = p->pPhrase->doclist.pList;
|
||||
int nToken = p->pPhrase->nToken;
|
||||
|
||||
for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
|
||||
Fts3Phrase *pPhrase = p->pRight->pPhrase;
|
||||
int nNear = p->nNear;
|
||||
res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
|
||||
}
|
||||
|
||||
aPoslist = pExpr->pRight->pPhrase->doclist.pList;
|
||||
nToken = pExpr->pRight->pPhrase->nToken;
|
||||
for(p=pExpr->pLeft; p && res; p=p->pLeft){
|
||||
int nNear;
|
||||
Fts3Phrase *pPhrase;
|
||||
assert( p->pParent && p->pParent->pLeft==p );
|
||||
nNear = p->pParent->nNear;
|
||||
pPhrase = (
|
||||
p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
|
||||
);
|
||||
res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
|
||||
}
|
||||
for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
|
||||
Fts3Phrase *pPhrase = p->pRight->pPhrase;
|
||||
int nNear = p->nNear;
|
||||
res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
|
||||
}
|
||||
|
||||
sqlite3_free(aTmp);
|
||||
aPoslist = pExpr->pRight->pPhrase->doclist.pList;
|
||||
nToken = pExpr->pRight->pPhrase->nToken;
|
||||
for(p=pExpr->pLeft; p && res; p=p->pLeft){
|
||||
int nNear;
|
||||
Fts3Phrase *pPhrase;
|
||||
assert( p->pParent && p->pParent->pLeft==p );
|
||||
nNear = p->pParent->nNear;
|
||||
pPhrase = (
|
||||
p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
|
||||
);
|
||||
res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(aTmp);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -654,6 +654,7 @@ struct Fts5Token {
|
||||
/* Parse a MATCH expression. */
|
||||
int sqlite3Fts5ExprNew(
|
||||
Fts5Config *pConfig,
|
||||
int iCol, /* Column on LHS of MATCH operator */
|
||||
const char *zExpr,
|
||||
Fts5Expr **ppNew,
|
||||
char **pzErr
|
||||
|
||||
+14
-1
@@ -213,6 +213,7 @@ static void fts5ParseFree(void *p){ sqlite3_free(p); }
|
||||
|
||||
int sqlite3Fts5ExprNew(
|
||||
Fts5Config *pConfig, /* FTS5 Configuration */
|
||||
int iCol,
|
||||
const char *zExpr, /* Expression text */
|
||||
Fts5Expr **ppNew,
|
||||
char **pzErr
|
||||
@@ -237,6 +238,18 @@ int sqlite3Fts5ExprNew(
|
||||
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
|
||||
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
|
||||
|
||||
/* If the LHS of the MATCH expression was a user column, apply the
|
||||
** implicit column-filter. */
|
||||
if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
|
||||
int n = sizeof(Fts5Colset);
|
||||
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
|
||||
if( pColset ){
|
||||
pColset->nCol = 1;
|
||||
pColset->aiCol[0] = iCol;
|
||||
sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset);
|
||||
}
|
||||
}
|
||||
|
||||
assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
|
||||
if( sParse.rc==SQLITE_OK ){
|
||||
*ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
|
||||
@@ -2443,7 +2456,7 @@ static void fts5ExprFunction(
|
||||
|
||||
rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr);
|
||||
rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
char *zText;
|
||||
|
||||
+11
-10
@@ -2878,7 +2878,8 @@ static void fts5MultiIterNext2(
|
||||
){
|
||||
assert( pIter->bSkipEmpty );
|
||||
if( p->rc==SQLITE_OK ){
|
||||
do {
|
||||
*pbNewTerm = 0;
|
||||
do{
|
||||
int iFirst = pIter->aFirst[1].iFirst;
|
||||
Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
|
||||
int bNewTerm = 0;
|
||||
@@ -2891,8 +2892,6 @@ static void fts5MultiIterNext2(
|
||||
fts5MultiIterAdvanced(p, pIter, iFirst, 1);
|
||||
fts5MultiIterSetEof(pIter);
|
||||
*pbNewTerm = 1;
|
||||
}else{
|
||||
*pbNewTerm = 0;
|
||||
}
|
||||
fts5AssertMultiIterSetup(p, pIter);
|
||||
|
||||
@@ -3845,9 +3844,6 @@ static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
|
||||
Fts5PageWriter *pPage = &pWriter->writer;
|
||||
i64 iRowid;
|
||||
|
||||
static int nCall = 0;
|
||||
nCall++;
|
||||
|
||||
assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) );
|
||||
|
||||
/* Set the szLeaf header field. */
|
||||
@@ -4196,6 +4192,7 @@ static void fts5IndexMergeLevel(
|
||||
int bOldest; /* True if the output segment is the oldest */
|
||||
int eDetail = p->pConfig->eDetail;
|
||||
const int flags = FTS5INDEX_QUERY_NOOUTPUT;
|
||||
int bTermWritten = 0; /* True if current term already output */
|
||||
|
||||
assert( iLvl<pStruct->nLevel );
|
||||
assert( pLvl->nMerge<=pLvl->nSeg );
|
||||
@@ -4249,18 +4246,22 @@ static void fts5IndexMergeLevel(
|
||||
int nTerm;
|
||||
const u8 *pTerm;
|
||||
|
||||
/* Check for key annihilation. */
|
||||
if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
|
||||
|
||||
pTerm = fts5MultiIterTerm(pIter, &nTerm);
|
||||
if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){
|
||||
if( pnRem && writer.nLeafWritten>nRem ){
|
||||
break;
|
||||
}
|
||||
fts5BufferSet(&p->rc, &term, nTerm, pTerm);
|
||||
bTermWritten =0;
|
||||
}
|
||||
|
||||
/* Check for key annihilation. */
|
||||
if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
|
||||
|
||||
if( p->rc==SQLITE_OK && bTermWritten==0 ){
|
||||
/* This is a new term. Append a term to the output segment. */
|
||||
fts5WriteAppendTerm(p, &writer, nTerm, pTerm);
|
||||
fts5BufferSet(&p->rc, &term, nTerm, pTerm);
|
||||
bTermWritten = 1;
|
||||
}
|
||||
|
||||
/* Append the rowid to the output */
|
||||
|
||||
+27
-13
@@ -506,6 +506,7 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
|
||||
static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
Fts5Table *pTab = (Fts5Table*)pVTab;
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
const int nCol = pConfig->nCol;
|
||||
int idxFlags = 0; /* Parameter passed through to xFilter() */
|
||||
int bHasMatch;
|
||||
int iNext;
|
||||
@@ -531,24 +532,34 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
|
||||
int aColMap[3];
|
||||
aColMap[0] = -1;
|
||||
aColMap[1] = pConfig->nCol;
|
||||
aColMap[2] = pConfig->nCol+1;
|
||||
aColMap[1] = nCol;
|
||||
aColMap[2] = nCol+1;
|
||||
|
||||
/* Set idxFlags flags for all WHERE clause terms that will be used. */
|
||||
for(i=0; i<pInfo->nConstraint; i++){
|
||||
struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
|
||||
int j;
|
||||
for(j=0; j<ArraySize(aConstraint); j++){
|
||||
struct Constraint *pC = &aConstraint[j];
|
||||
if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){
|
||||
if( p->usable ){
|
||||
int iCol = p->iColumn;
|
||||
|
||||
if( (p->op==SQLITE_INDEX_CONSTRAINT_MATCH && iCol>=0 && iCol<=nCol)
|
||||
|| (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol==nCol)
|
||||
){
|
||||
/* A MATCH operator or equivalent */
|
||||
if( p->usable ){
|
||||
idxFlags = (idxFlags & 0xFFFF) | FTS5_BI_MATCH | (iCol << 16);
|
||||
aConstraint[0].iConsIndex = i;
|
||||
}else{
|
||||
/* As there exists an unusable MATCH constraint this is an
|
||||
** unusable plan. Set a prohibitively high cost. */
|
||||
pInfo->estimatedCost = 1e50;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}else{
|
||||
int j;
|
||||
for(j=1; j<ArraySize(aConstraint); j++){
|
||||
struct Constraint *pC = &aConstraint[j];
|
||||
if( iCol==aColMap[pC->iCol] && p->op & pC->op && p->usable ){
|
||||
pC->iConsIndex = i;
|
||||
idxFlags |= pC->fts5op;
|
||||
}else if( j==0 ){
|
||||
/* As there exists an unusable MATCH constraint this is an
|
||||
** unusable plan. Set a prohibitively high cost. */
|
||||
pInfo->estimatedCost = 1e50;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1123,6 +1134,7 @@ static int fts5FilterMethod(
|
||||
sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
|
||||
sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
|
||||
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
|
||||
int iCol; /* Column on LHS of MATCH operator */
|
||||
char **pzErrmsg = pConfig->pzErrmsg;
|
||||
|
||||
UNUSED_PARAM(zUnused);
|
||||
@@ -1153,6 +1165,8 @@ static int fts5FilterMethod(
|
||||
if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
|
||||
if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
|
||||
if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
|
||||
iCol = (idxNum>>16);
|
||||
assert( iCol>=0 && iCol<=pConfig->nCol );
|
||||
assert( iVal==nVal );
|
||||
bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
|
||||
pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
|
||||
@@ -1199,7 +1213,7 @@ static int fts5FilterMethod(
|
||||
rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
|
||||
}else{
|
||||
char **pzErr = &pTab->base.zErrMsg;
|
||||
rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
|
||||
rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( bOrderByRank ){
|
||||
pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
*/
|
||||
#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_FTS5)
|
||||
|
||||
#include <fts5.h>
|
||||
#include "fts5.h"
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
@@ -577,6 +577,20 @@ do_execsql_test 21.1 {
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 22.0 {
|
||||
CREATE VIRTUAL TABLE t9 USING fts5(x, detail=%DETAIL%);
|
||||
INSERT INTO t9(rowid, x) VALUES(2, 'bbb');
|
||||
BEGIN;
|
||||
INSERT INTO t9(rowid, x) VALUES(1, 'aaa');
|
||||
DELETE FROM t9 WHERE rowid = 2;
|
||||
INSERT INTO t9(rowid, x) VALUES(3, 'bbb');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 22.1 {
|
||||
SELECT rowid FROM t9('a*')
|
||||
} {1}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -63,6 +63,23 @@ foreach_detail_mode $::testprefix {
|
||||
SELECT rowid FROM t1($q)
|
||||
} $res
|
||||
}
|
||||
|
||||
foreach {tn w res} {
|
||||
0 "a MATCH 'a'" {1}
|
||||
1 "b MATCH 'a'" {2}
|
||||
2 "b MATCH '{a b c} : a'" {2}
|
||||
3 "b MATCH 'a OR b'" {1 2}
|
||||
4 "b MATCH 'a OR a:b'" {2}
|
||||
5 "b MATCH 'a OR b:b'" {1 2}
|
||||
} {
|
||||
do_execsql_test 3.$tn "
|
||||
SELECT rowid FROM t1 WHERE $w
|
||||
" $res
|
||||
}
|
||||
|
||||
do_catchsql_test 4.1 {
|
||||
SELECT * FROM t1 WHERE rowid MATCH 'a'
|
||||
} {1 {unable to use function MATCH in the requested context}}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# 2017 May 12
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5delete
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
fts5_aux_test_functions db
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<5000
|
||||
)
|
||||
INSERT INTO t1(rowid, x) SELECT i, (i/2)*2 FROM s;
|
||||
}
|
||||
|
||||
do_test 1.1 {
|
||||
execsql BEGIN
|
||||
for {set i 1} {$i<=5000} {incr i} {
|
||||
if {$i % 2} {
|
||||
execsql { INSERT INTO t1 VALUES($i) }
|
||||
} else {
|
||||
execsql { DELETE FROM t1 WHERE rowid = $i }
|
||||
}
|
||||
}
|
||||
execsql COMMIT
|
||||
} {}
|
||||
|
||||
do_test 1.2 {
|
||||
execsql { INSERT INTO t1(t1, rank) VALUES('usermerge', 2); }
|
||||
for {set i 0} {$i < 5} {incr i} {
|
||||
execsql { INSERT INTO t1(t1, rank) VALUES('merge', 1) }
|
||||
execsql { INSERT INTO t1(t1) VALUES('integrity-check') }
|
||||
}
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -30,7 +30,7 @@ do_eqp_test 1.1 {
|
||||
SELECT * FROM t1, f1 WHERE f1 MATCH t1.x
|
||||
} {
|
||||
0 0 0 {SCAN TABLE t1}
|
||||
0 1 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 1:}
|
||||
0 1 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:}
|
||||
}
|
||||
|
||||
do_eqp_test 1.2 {
|
||||
@@ -43,7 +43,7 @@ do_eqp_test 1.2 {
|
||||
do_eqp_test 1.3 {
|
||||
SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff
|
||||
} {
|
||||
0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 1:}
|
||||
0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
** 2017-04-16
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file implements a run-time loadable extension to SQLite that
|
||||
** registers a sqlite3_collation_needed() callback to register a fake
|
||||
** collating function for any unknown collating sequence. The fake
|
||||
** collating function works like BINARY.
|
||||
**
|
||||
** This extension can be used to load schemas that contain one or more
|
||||
** unknown collating sequences.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <string.h>
|
||||
|
||||
static int anyCollFunc(
|
||||
void *NotUsed,
|
||||
int nKey1, const void *pKey1,
|
||||
int nKey2, const void *pKey2
|
||||
){
|
||||
int rc, n;
|
||||
n = nKey1<nKey2 ? nKey1 : nKey2;
|
||||
rc = memcmp(pKey1, pKey2, n);
|
||||
if( rc==0 ) rc = nKey1 - nKey2;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void anyCollNeeded(
|
||||
void *NotUsed,
|
||||
sqlite3 *db,
|
||||
int eTextRep,
|
||||
const char *zCollName
|
||||
){
|
||||
sqlite3_create_collation(db, zCollName, eTextRep, 0, anyCollFunc);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_anycollseq_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
rc = sqlite3_collation_needed(db, 0, anyCollNeeded);
|
||||
return rc;
|
||||
}
|
||||
+68
-15
@@ -171,6 +171,7 @@ struct JsonParse {
|
||||
u8 oom; /* Set to true if out of memory */
|
||||
u8 nErr; /* Number of errors seen */
|
||||
u16 iDepth; /* Nesting depth */
|
||||
int nJson; /* Length of the zJson string in bytes */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -413,6 +414,14 @@ static void jsonParseReset(JsonParse *pParse){
|
||||
pParse->aUp = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a JsonParse object that was obtained from sqlite3_malloc().
|
||||
*/
|
||||
static void jsonParseFree(JsonParse *pParse){
|
||||
jsonParseReset(pParse);
|
||||
sqlite3_free(pParse);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert the JsonNode pNode into a pure JSON string and
|
||||
** append to pOut. Subsubstructure is also included. Return
|
||||
@@ -964,6 +973,49 @@ static int jsonParseFindParents(JsonParse *pParse){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
|
||||
*/
|
||||
#define JSON_CACHE_ID (-429938)
|
||||
|
||||
/*
|
||||
** Obtain a complete parse of the JSON found in the first argument
|
||||
** of the argv array. Use the sqlite3_get_auxdata() cache for this
|
||||
** parse if it is available. If the cache is not available or if it
|
||||
** is no longer valid, parse the JSON again and return the new parse,
|
||||
** and also register the new parse so that it will be available for
|
||||
** future sqlite3_get_auxdata() calls.
|
||||
*/
|
||||
static JsonParse *jsonParseCached(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zJson = (const char*)sqlite3_value_text(argv[0]);
|
||||
int nJson = sqlite3_value_bytes(argv[0]);
|
||||
JsonParse *p;
|
||||
if( zJson==0 ) return 0;
|
||||
p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
|
||||
if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){
|
||||
p->nErr = 0;
|
||||
return p; /* The cached entry matches, so return it */
|
||||
}
|
||||
p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
|
||||
if( p==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return 0;
|
||||
}
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->zJson = (char*)&p[1];
|
||||
memcpy((char*)p->zJson, zJson, nJson+1);
|
||||
if( jsonParse(p, pCtx, p->zJson) ){
|
||||
sqlite3_free(p);
|
||||
return 0;
|
||||
}
|
||||
p->nJson = nJson;
|
||||
sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree);
|
||||
return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare the OBJECT label at pNode against zKey,nKey. Return true on
|
||||
** a match.
|
||||
@@ -1329,29 +1381,30 @@ static void jsonArrayLengthFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
JsonParse x; /* The parse */
|
||||
JsonParse *p; /* The parse */
|
||||
sqlite3_int64 n = 0;
|
||||
u32 i;
|
||||
JsonNode *pNode;
|
||||
|
||||
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
|
||||
assert( x.nNode );
|
||||
p = jsonParseCached(ctx, argv);
|
||||
if( p==0 ) return;
|
||||
assert( p->nNode );
|
||||
if( argc==2 ){
|
||||
const char *zPath = (const char*)sqlite3_value_text(argv[1]);
|
||||
pNode = jsonLookup(&x, zPath, 0, ctx);
|
||||
pNode = jsonLookup(p, zPath, 0, ctx);
|
||||
}else{
|
||||
pNode = x.aNode;
|
||||
pNode = p->aNode;
|
||||
}
|
||||
if( pNode==0 ){
|
||||
x.nErr = 1;
|
||||
}else if( pNode->eType==JSON_ARRAY ){
|
||||
return;
|
||||
}
|
||||
if( pNode->eType==JSON_ARRAY ){
|
||||
assert( (pNode->jnFlags & JNODE_APPEND)==0 );
|
||||
for(i=1; i<=pNode->n; n++){
|
||||
i += jsonNodeSize(&pNode[i]);
|
||||
}
|
||||
}
|
||||
if( x.nErr==0 ) sqlite3_result_int64(ctx, n);
|
||||
jsonParseReset(&x);
|
||||
sqlite3_result_int64(ctx, n);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1367,20 +1420,21 @@ static void jsonExtractFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
JsonParse x; /* The parse */
|
||||
JsonParse *p; /* The parse */
|
||||
JsonNode *pNode;
|
||||
const char *zPath;
|
||||
JsonString jx;
|
||||
int i;
|
||||
|
||||
if( argc<2 ) return;
|
||||
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
|
||||
p = jsonParseCached(ctx, argv);
|
||||
if( p==0 ) return;
|
||||
jsonInit(&jx, ctx);
|
||||
jsonAppendChar(&jx, '[');
|
||||
for(i=1; i<argc; i++){
|
||||
zPath = (const char*)sqlite3_value_text(argv[i]);
|
||||
pNode = jsonLookup(&x, zPath, 0, ctx);
|
||||
if( x.nErr ) break;
|
||||
pNode = jsonLookup(p, zPath, 0, ctx);
|
||||
if( p->nErr ) break;
|
||||
if( argc>2 ){
|
||||
jsonAppendSeparator(&jx);
|
||||
if( pNode ){
|
||||
@@ -1398,14 +1452,13 @@ static void jsonExtractFunc(
|
||||
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
||||
}
|
||||
jsonReset(&jx);
|
||||
jsonParseReset(&x);
|
||||
}
|
||||
|
||||
/* This is the RFC 7396 MergePatch algorithm.
|
||||
*/
|
||||
static JsonNode *jsonMergePatch(
|
||||
JsonParse *pParse, /* The JSON parser that contains the TARGET */
|
||||
int iTarget, /* Node of the TARGET in pParse */
|
||||
u32 iTarget, /* Node of the TARGET in pParse */
|
||||
JsonNode *pPatch /* The PATCH */
|
||||
){
|
||||
u32 i, j;
|
||||
|
||||
+2
-2
@@ -82,10 +82,10 @@ int main(int argc, char **argv){
|
||||
int bVacuum = 0;
|
||||
int rc;
|
||||
sqlite3_int64 nProgress = 0;
|
||||
int nArg = argc-2;
|
||||
int nArgc = argc-2;
|
||||
|
||||
if( argc<3 ) usage(argv[0]);
|
||||
for(i=1; i<nArg; i++){
|
||||
for(i=1; i<nArgc; i++){
|
||||
const char *zArg = argv[i];
|
||||
int nArg = strlen(zArg);
|
||||
if( nArg>1 && nArg<=8 && 0==memcmp(zArg, "-vacuum", nArg) ){
|
||||
|
||||
@@ -3222,6 +3222,7 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
|
||||
static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Rtree *pRtree = (Rtree *)pVtab;
|
||||
int iwt = pRtree->inWrTrans;
|
||||
UNUSED_PARAMETER(iSavepoint);
|
||||
pRtree->inWrTrans = 0;
|
||||
nodeBlobReset(pRtree);
|
||||
pRtree->inWrTrans = iwt;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
C Fix\sto\sthe\sdecision\slogic\sfor\swhen\sto\suse\sthe\sskip-ahead-distinct\soptimization.
|
||||
D 2017-04-14T22:41:27.127
|
||||
C Fix\sa\sdocumentation\stypo.\s\sNo\schanges\sto\scode.
|
||||
D 2017-05-18T18:17:55.135
|
||||
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc a4c0613a18663bda56d8cf76079ab6590a7c3602e54befb4bbdef76bcaa38b6a
|
||||
F Makefile.msc 8eeb80162074004e906b53d7340a12a14c471a83743aab975947e95ce061efcc
|
||||
F README.md 2b15fae33852f2f53996774c21fb41e1d94181c4401a0e43ac93e11f2cc901b9
|
||||
F VERSION 0a0e02e16b44ea735b40118fc844311b2ab0d35b25fbeda5120aee62f973f663
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -11,7 +11,7 @@ F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am 1a47d071e3d5435f8f7ebff7eb6703848bbd65d4
|
||||
F autoconf/Makefile.msc 1fba0d762d115509d4fce7e333305cee172d521aaacec8bbf7aad5503605d3fb
|
||||
F autoconf/Makefile.msc 1014be616b420a5f48611d21b62ca2f50ec97ee795087ecb8a4d6bf6375ba11d
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac 2893b823ecc86cea13739f6c8109a41392254d1db08235c5615e0af5722c8578
|
||||
@@ -70,7 +70,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c f0d5de1bc2155ba7cd7c0c1a751779a3a8857fa34d5c12f3b233a23fa2e79ea2
|
||||
F ext/fts3/fts3.c 88ea5c444fdf262b4eb7b5872b9a3192b8b8d0df8cc9735c5aed159ec5dae02a
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h eb2502000148e80913b965db3e59f29251266d0a
|
||||
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
|
||||
@@ -99,18 +99,18 @@ F ext/fts3/unicode/mkunicode.tcl ab0543a3b2399092ea2dd75df1bef333405b0d7f6b8c495
|
||||
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
|
||||
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
|
||||
F ext/fts5/fts5.h 62f3e33ceeb9a428db139f9c012186b371da1cc7
|
||||
F ext/fts5/fts5Int.h d514c81997be588c2b23b82c77f6449e20a43903c503066f13d3d0ed8746ccde
|
||||
F ext/fts5/fts5Int.h 15e7514b46a845937d7c62e5c69e935091f0dbb72eb61aa4c8bcfbd39fdea158
|
||||
F ext/fts5/fts5_aux.c 67acf8d51723cf28ffc3828210ba662df4b8d267
|
||||
F ext/fts5/fts5_buffer.c 4c1502d4c956cd092c89ce4480867f9d8bf325cd
|
||||
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
|
||||
F ext/fts5/fts5_expr.c e5522f89e599e7e53c0014003b66480f676d2eff8b9cdb2c03c32d859b4b7cb3
|
||||
F ext/fts5/fts5_expr.c f2825f714d91bbe62ab5820aee9ad12e0c94205b2a01725eaa9072415ae9ff1c
|
||||
F ext/fts5/fts5_hash.c 880998e596b60f078348d48732ca4ad9a90caad2
|
||||
F ext/fts5/fts5_index.c 551add2b7762a2857336747def3b9d4fa304df476e188fb323492e2fd851772b
|
||||
F ext/fts5/fts5_main.c 24cafdc44c06b9665d73c34b75966f6223e9299cc9fd10184c6bf888e3ff563f
|
||||
F ext/fts5/fts5_index.c 9ce10106f42f8b84278a8ea859940224e2af5f0cc882f909364469f6f52769cb
|
||||
F ext/fts5/fts5_main.c 1ba0e7806886c1bc16e20d0dde1c2b535d1aeb98cbbb937c4c3e064af5ac6f03
|
||||
F ext/fts5/fts5_storage.c 7750986004f3f0c94619a85ecb5dd6cbef53e5e3853488e8a906c269d4d11db6
|
||||
F ext/fts5/fts5_tcl.c 4a901f00c8553740dba63511603f5527d741c26a
|
||||
F ext/fts5/fts5_test_mi.c 783b86697ebf773c18fc109992426c0173a055bc
|
||||
F ext/fts5/fts5_test_tok.c db08af63673c3a7d39f053b36fd6e065017706be
|
||||
F ext/fts5/fts5_test_tok.c f4c27f2e3200653a458f5316f6aaa863f7532d98fff7534ece3670fb7f2c196b
|
||||
F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
|
||||
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
|
||||
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
|
||||
@@ -118,7 +118,7 @@ F ext/fts5/fts5_vocab.c e44fefa7f0c1db252998af071daf06a7147e17e7
|
||||
F ext/fts5/fts5parse.y a070b538e08ae9e2177d15c337ed2a3464408f0f886e746307098f746efd94ca
|
||||
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
|
||||
F ext/fts5/test/fts5_common.tcl b01c584144b5064f30e6c648145a2dd6bc440841
|
||||
F ext/fts5/test/fts5aa.test b3cb080db4851580705c5e261c9d4308edf030d5cbbc24b5d6668403b73f023b
|
||||
F ext/fts5/test/fts5aa.test 6dd1bfa4426a8d77e8c8d447aad02515c85118b082f24053ac89802300077ff1
|
||||
F ext/fts5/test/fts5ab.test 30325a89453280160106be411bba3acf138e6d1b
|
||||
F ext/fts5/test/fts5ac.test 55cad4275a1f5acabfe14d8442a8046b47e49e5f
|
||||
F ext/fts5/test/fts5ad.test 36995f0586f30f5602074e012b9224c71ec5171c
|
||||
@@ -136,7 +136,7 @@ F ext/fts5/test/fts5aux.test 5dd158a1e7869e27e9762a2a452b189c728d1be3
|
||||
F ext/fts5/test/fts5auxdata.test 141a7cbffcceb1bd2799b4b29c183ff8780d586e
|
||||
F ext/fts5/test/fts5bigpl.test 04ee0d7eebbebf17c31f5a0b5c5f9494eac3a0cb
|
||||
F ext/fts5/test/fts5bigtok.test 017a9397b14e7598883a6328ead4a6539b42d59a
|
||||
F ext/fts5/test/fts5colset.test 5d6cc35a7cdf39b2709a36620c3f398f6f8c88de39e1485f367e5294ffc7c153
|
||||
F ext/fts5/test/fts5colset.test 97084e7fd3183a3c148ade1d4ad980b7e764cb2711ac77c3176680c3e75ea2b9
|
||||
F ext/fts5/test/fts5columnsize.test a8cfef21ffa1c264b9f670a7d94eeaccb5341c07
|
||||
F ext/fts5/test/fts5config.test 7788b9c058074d640dfcdd81d97b6a9480000368
|
||||
F ext/fts5/test/fts5conflict.test 26f4e46c4d31e16221794832a990dc4e30e18de5
|
||||
@@ -144,6 +144,7 @@ F ext/fts5/test/fts5content.test 9a952c95518a14182dc3b59e3c8fa71cda82a4e1
|
||||
F ext/fts5/test/fts5corrupt.test c2ad090192708150d50d961278df10ae7a4b8b62
|
||||
F ext/fts5/test/fts5corrupt2.test 128eb6e2d26b09f4da339e581f424b3321e0fdaa
|
||||
F ext/fts5/test/fts5corrupt3.test f77f65e386231daf62902466b40ff998b2c8ce4f
|
||||
F ext/fts5/test/fts5delete.test 0585395660889090a6a04b0cac0e70b16801da44ee321534d6169da49af8167f
|
||||
F ext/fts5/test/fts5detail.test ef5c690535a797413acaf5ad9b8ab5d49972df69
|
||||
F ext/fts5/test/fts5determin.test 10648edb75ef1e196b10978fd21a9be0c31e09c3
|
||||
F ext/fts5/test/fts5dlidx.test 007e9390c94638760797dbec2990c97c3fa08dfe
|
||||
@@ -175,7 +176,7 @@ F ext/fts5/test/fts5near.test b214cddb1c1f1bddf45c75af768f20145f7e71cc
|
||||
F ext/fts5/test/fts5onepass.test 7ed9608e258132cb8d55e7c479b08676ad68810c
|
||||
F ext/fts5/test/fts5optimize.test 9d3ac53bb9cae58cb070d795db86bcb2f9fec105
|
||||
F ext/fts5/test/fts5phrase.test f6d1d464da5beb25dc56277aa4f1d6102f0d9a2f
|
||||
F ext/fts5/test/fts5plan.test 6a55ecbac9890765b0e16f8c421c7e0888cfe436
|
||||
F ext/fts5/test/fts5plan.test fb0ee60c9a092b17bb958dd742f01e3731b520d50b5d61b288c49c7acdc286cb
|
||||
F ext/fts5/test/fts5porter.test 7cdc07bef301d70eebbfa75dcaf45c3680e1d0e1
|
||||
F ext/fts5/test/fts5porter2.test 2e65633d58a1c525d5af0f6c01e5a59155bb3487
|
||||
F ext/fts5/test/fts5prefix.test 6ef7e875738412907b17687d25db39a25cbdaba4
|
||||
@@ -209,6 +210,7 @@ F ext/icu/icu.c 84900472a088a3a172c6c079f58a1d3a1952c332
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
|
||||
F ext/misc/amatch.c 211108e201105e4bb0c076527b8cfd34330fc234
|
||||
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
|
||||
F ext/misc/carray.c 40c27641010a4dc67e3690bdb7c9d36ca58b3c2d
|
||||
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
|
||||
F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
|
||||
@@ -218,7 +220,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
|
||||
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
|
||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||
F ext/misc/json1.c e54799e85461fc7d5456194f110bb967775949a4813d007f94c121284304cb1d
|
||||
F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984
|
||||
F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
|
||||
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
|
||||
@@ -236,7 +238,7 @@ F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vfsstat.c bf10ef0bc51e1ad6756629e1edb142f7a8db1178
|
||||
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rbu/rbu.c b2c0b5e6ae1a89affc0edfc127ebfa5f637a0ce4
|
||||
F ext/rbu/rbu.c ea7d1b7eb44c123a2a619332e19fe5313500705c4a58aaa1887905c0d83ffc2e
|
||||
F ext/rbu/rbu1.test 43836fac8c7179a358eaf38a8a1ef3d6e6285842
|
||||
F ext/rbu/rbu10.test 046b0980041d30700464a800bbf6733ed2df515d
|
||||
F ext/rbu/rbu11.test 9bc68c2d3dbeb1720153626e3bd0466dcc017702
|
||||
@@ -271,7 +273,7 @@ F ext/rbu/sqlite3rbu.c 2a89efba9eeba8e6c89a498dc195e8efbdde2694
|
||||
F ext/rbu/sqlite3rbu.h 6fb6294c34a9ca93b5894a33bca530c6f08decba
|
||||
F ext/rbu/test_rbu.c 5aa22616afac6f71ebd3d9bc9bf1006cfabcca88
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 37c603c6b8aed1a760661ceb5a025bd36bac14cf56d59949bd8de14b2a17e9ed
|
||||
F ext/rtree/rtree.c 8205d6e4466f766e57ce1b8aa38224ac9e1cec2d2bf4684cd1cc5a6ddf9b7014
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test d5f0ba215b3bd1d05269ada86e74073b8445852aa0d33a63e10ec63a09c39473
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
@@ -340,25 +342,25 @@ F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 3b23977620ce9662ac54443f65b87ba996e36121
|
||||
F src/analyze.c 0d0ccf7520a201d8747ea2f02c92c26e26f801bc161f714f27b9f7630dde0421
|
||||
F src/attach.c 8c476f8bd5d2afe11d925f890d30e527e5b0ce43
|
||||
F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792
|
||||
F src/auth.c 79f96c6f33bf0e5da8d1c282cee5ebb1852bb8a6ccca3e485d7c459b035d9c3c
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||
F src/btree.c 24ae5472bd0b53b4130ecdda389deb621af721d1fcb50890b878102b00bd10fa
|
||||
F src/btree.c 8c1fd4cfa2b0bf021386e0a1f4e30b64eea7a2c1bc2e0c3e5901a626b1ab6aa9
|
||||
F src/btree.h 80f518c0788be6cec8d9f8e13bd8e380df299d2b5e4ac340dc887b0642647cfc
|
||||
F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f610
|
||||
F src/build.c 4026a9c554b233e50c5e9ad46963e676cf54dd2306d952aa1eaa07a1bc9ce14f
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 47d91a25ad8f199a71a5b1b7b169d6dd0d6e98c5719eca801568798743d1161c
|
||||
F src/date.c ee676e7694dfadbdd2fde1a258a71be8360ba5ae
|
||||
F src/date.c cc42a41c7422389860d40419a5e3bce5eaf6e7835c3ba2677751dc653550a5c7
|
||||
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
||||
F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c
|
||||
F src/expr.c f6572c7690fa619e85b1192b683ccc30cd123363415963c061ada3770b18f6a7
|
||||
F src/delete.c bc2bfc227002ebe091e7cc321f09a48e52f86e1cd5ff9b028009db0671556749
|
||||
F src/expr.c c83f799f3e5e3f3863bd0716119383e4a062d00a1e34e7273a78555918840a7c
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c db65492ae549c3b548c9ef1f279ce1684f1c473b116e1c56a90878cd5dcf968d
|
||||
F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174
|
||||
F src/global.c 4a34512d82fc5aa13c802db06bcfff5e1d3de955
|
||||
F src/global.c 8a6ab6b4d91effb96ffa81b39f0d70c862abca157f8aaa194600a4a8b7923344
|
||||
F src/hash.c 63d0ee752a3b92d4695b2b1f5259c4621b2cfebd
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
@@ -366,7 +368,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c d4bb3a135948553d18cf992f76f7ed7b18aa0327f250607b5a6671e55d9947d5
|
||||
F src/legacy.c e88ed13c2d531decde75d42c2e35623fb9ce3cb0
|
||||
F src/loadext.c a72909474dadce771d3669bf84bf689424f6f87d471fee898589c3ef9b2acfd9
|
||||
F src/main.c 158326243c5ddc8b98a1e983fa488650cf76d760
|
||||
F src/main.c 1e448d204045c1dcd604853639d9d8fe253aa9ec302a2f1ffd2e22752fd6b708
|
||||
F src/malloc.c e20bb2b48abec52d3faf01cce12e8b4f95973755fafec98d45162dfdab111978
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@@ -388,30 +390,30 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c 30e2c43e4955db990e5b5a81e901f8aa74cc8820
|
||||
F src/os_win.c 2a6c73eef01c51a048cc4ddccd57f981afbec18a
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c ff1232b3088a39806035ecfac4fffeb22717d80b
|
||||
F src/pager.c 80893c0860199aebc6efa4f102ab11eebde338b7fdbb0c04d4b04647c2fd62d1
|
||||
F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa
|
||||
F src/parse.y 48b03113704ee8bd78ee6996d81de7fbee22e105
|
||||
F src/parse.y 0513387ce02fea97897d8caef82d45f347818593f24f1bdc48e0c530a8af122d
|
||||
F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870
|
||||
F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
|
||||
F src/pcache1.c 1195a21fe28e223e024f900b2011e80df53793f0356a24caace4188b098540dc
|
||||
F src/pragma.c 220474f113cade6a6b5bacd3e3a65eca339acbee804128bc5db13a9cad55fba5
|
||||
F src/pragma.c 2362670a9d28b71708aecb2b9b10b3f7be71f4c950961c07e81dc400e3ce6371
|
||||
F src/pragma.h 37a1311d0388db480388d7ec09054f7103045eff20d4971f8a433b77f40b9921
|
||||
F src/prepare.c b1140c3d0cf59bc85ace00ce363153041b424b7a
|
||||
F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c cc9129bc97d20f3c79b9dfcc555db37eed28a660cc6954bf3b282d8e1e5593a2
|
||||
F src/shell.c 70f4957b988572315e97c56941fdc81fd35907fee36b7b2e7be5ec4c7e9d065d
|
||||
F src/sqlite.h.in 40233103e3e4e10f8a63523498d0259d232e42aba478e2d3fb914799185aced6
|
||||
F src/select.c d74b1cde1d9ca6d08bec50b60a5be19440273646bc8ae16648d748c38161d5b7
|
||||
F src/shell.c a37d96b20b3644d0eb905df5aa7a0fcf9f6e73c15898337230c760a24a8df794
|
||||
F src/sqlite.h.in 8dd468837a4f6d76713e3a4cc65bea48095009038593d41040ab46c1b351197f
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
|
||||
F src/sqliteInt.h 9affb53bb405dcea1d86e85198ebaf6232a684cc2b2af6b3c181869f1c8f3e93
|
||||
F src/sqliteInt.h aea3aa1b81e0d07d5b1c39b8c5a54a1dc5e4f10136cb63da392aef9eb2a5108b
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
F src/tclsqlite.c 6c2151b6d8d98e183a04466d40df8889c0574d79
|
||||
F src/test1.c 8a98191a1da8e100f77cdb5cc716df67d405028d
|
||||
F src/tclsqlite.c c8cf60d0c5411d5e70e7c136470d29dbe760d250f55198b71682c67086524e4a
|
||||
F src/test1.c c99f0442918a7a5d5b68a95d6024c211989e6c782c15ced5a558994baaf76a5e
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c d03f5b5da9a2410b7a91c64b0d3306ed28ab6fee
|
||||
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
|
||||
@@ -427,7 +429,7 @@ F src/test_bestindex.c d23f80d334c59662af69191854c76b8d3d0c8c96
|
||||
F src/test_blob.c f65ac717da2618691cf9dad094e6da0219dcd208
|
||||
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
|
||||
F src/test_config.c edcba290248dc18736dd814c9b95863c6762e0b35753048d8cbe5bf65f7abfbb
|
||||
F src/test_delete.c af7eab5702f853fb1c62a5f7665e2234cf1ae17b
|
||||
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
|
||||
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
|
||||
F src/test_devsym.c 4e58dec2602d8e139ca08659f62a62450587cb58
|
||||
F src/test_fs.c e16cbe68d3b107e00a907c20a9a02629870eb69b
|
||||
@@ -462,29 +464,29 @@ F src/test_windirent.h 5d67483a55442e31e1bde0f4a230e6e932ad5906
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
|
||||
F src/treeview.c 84d0ac737e1231702679f0289180021e19c5cc186ec413e8dcb704a887c76ec8
|
||||
F src/treeview.c 6cf8d7fe9e63fae57dad1bb57f6615e14eac0c527e43d868e805042cae8ed1f7
|
||||
F src/trigger.c c9f0810043b265724fdb1bdd466894f984dfc182
|
||||
F src/update.c c443935c652af9365e033f756550b5032d02e1b06eb2cb890ed7511ae0c051dc
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6
|
||||
F src/util.c fc081ec6f63448dcd80d3dfad35baecfa104823254a815b081a4d9fe76e1db23
|
||||
F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569
|
||||
F src/vdbe.c 808fda3d50f544120d27c731449b524b4ec8f8b0f734b228831078f0ba53ecb9
|
||||
F src/vdbe.c 9bac2bc2313ed682e6f48ccff6644d3263341885bfcbb3cdea7b720c722be2d5
|
||||
F src/vdbe.h f7d1456e28875c2dcb964056589b5b7149ab7edf39edeca801596a39bb3d3848
|
||||
F src/vdbeInt.h c070bc5c8b913bda0ceaa995cd4d939ded5e4fc96cf7c3c1c602d41b871f8ade
|
||||
F src/vdbeapi.c 5b08d82592bcff4470601fe78aaabebd50837860
|
||||
F src/vdbeaux.c 6b3f6ce909e206d4c918988b13b7fa687e92b4471d137e0f2a37edac80ec60be
|
||||
F src/vdbeInt.h 1ecdacc1322fdd3241ec30c32a480e328a6f864e532dc53fae8e0ab68121aebf
|
||||
F src/vdbeapi.c dc904b3c5e459727993c2421e653e29d63223846d129fae98adc782b0a996481
|
||||
F src/vdbeaux.c 01dcf59b2a96bd3cc9db8c0d7f266518d113587459a2b3316279c4f9c90f28a9
|
||||
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
|
||||
F src/vdbemem.c 3122f5a21064198c10ee1b4686937aab27d5395712d9af905b7fa1affc47a453
|
||||
F src/vdbemem.c 2c70f8f5de6c71fb99a22c5b83be9fab5c47cdd8e279fa44a8c00cfed06d7e89
|
||||
F src/vdbesort.c e72fe02a2121386ba767ede8942e9450878b8fc873abf3d1b6824485f092570c
|
||||
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
|
||||
F src/vtab.c 007513c2ef52472fcdea6a741683d50662e82790
|
||||
F src/vtab.c 35b9bdc2b41de32a417141d12097bcc4e29a77ed7cdb8f836d1d2305d946b61b
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
|
||||
F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
|
||||
F src/walker.c b71a992b413b3a022572eccf29ef4b4890223791
|
||||
F src/where.c 10ae856aa4bcf7c6be39b6b53422fc94e713ab8a19383b4cf525bc05ae70d872
|
||||
F src/where.c c6352f15be5031907c68bcbde96cad1a6da20e9f4051d10168a59235de9a8566
|
||||
F src/whereInt.h 2a4b634d63ce488b46d4b0da8f2eaa8f9aeab202bc25ef76f007de5e3fba1f20
|
||||
F src/wherecode.c 943e32e9dccd0af802e0683ae11071c8bd808364e5908a5fb66758bd404c8681
|
||||
F src/wherecode.c 8ad48867660519e262a401720845dc76934f86f558ec9606335fafcd7a2554f8
|
||||
F src/whereexpr.c e913aaa7b73ffcce66abcea5f197e2c538d48b5df78d0b7bba8ff4d73cc2e745
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@@ -525,9 +527,9 @@ F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d
|
||||
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
|
||||
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
|
||||
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
|
||||
F test/auth.test c6ede04bee65637ff354b43fc1235aa560c0863e
|
||||
F test/auth.test 3d6cd8f3978ba55b1202574e6ecd79c6e00914ca44b9bfd6c1fe6fb873fcac88
|
||||
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
|
||||
F test/auth3.test 0d48b901cf111c14b4b1b5205c7d28f1a278190f
|
||||
F test/auth3.test db21405b95257c24d29273b6b31d0efc59e1d337e3d5804ba2d1fd4897b1ae49
|
||||
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
|
||||
F test/autoinc.test 6ae8fb69c9f656962464ae4e6667045d0dfc3b46
|
||||
F test/autoindex1.test 14b63a9f1e405fe6d5bfc8c8d00249c2ebaf13ea
|
||||
@@ -575,6 +577,7 @@ F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
|
||||
F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61
|
||||
F test/cachespill.test 895997f84a25b323b166aecb69baab2d6380ea98f9e0bcc688c4493c535cfab9
|
||||
F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738
|
||||
F test/capi3.test f0c66919e43d42e1572a69be039e4527a931b00f
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
@@ -602,7 +605,7 @@ F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
|
||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||
F test/conflict.test 029faa2d81a0d1cafb5f88614beb663d972c01db
|
||||
F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c
|
||||
F test/conflict3.test dec0634c0f31dec9a4b01c63063e939f0cd21b6b
|
||||
F test/conflict3.test a83db76a6c3503b2fa057c7bfb08c318d8a422202d8bc5b86226e078e5b49ff9
|
||||
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
|
||||
F test/corrupt.test 141c39ea650c1365e85a49e402fa05cb9617fb97
|
||||
F test/corrupt2.test e4964cee73dda57a90958e0087a6b388b1d9cb58
|
||||
@@ -707,7 +710,7 @@ F test/fkey1.test ba64806ff9a04eecab2679caad377ae99a5e94e4
|
||||
F test/fkey2.test 155809016fad6b2a1491facf2ac53a551bc57c2c
|
||||
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 5a373303f201ac03c22ba1ef17a733d3f56e611a
|
||||
F test/fkey5.test 24dd28eb3d9f1b5a174f47e9899ace5facb08373a4223593c8c631e6cf9f7d5a
|
||||
F test/fkey6.test d078a1e323a740062bed38df32b8a736fd320dc0
|
||||
F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13
|
||||
F test/fkey8.test e5372e32cdb4481f121ec3550703eeb7b4e0762c
|
||||
@@ -751,7 +754,7 @@ F test/fts2r.test b154c30b63061d8725e320fba1a39e2201cadd5e
|
||||
F test/fts2token.test d8070b241a15ff13592a9ae4a8b7c171af6f445a
|
||||
F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654
|
||||
F test/fts3_common.tcl 99cf6659b87c0f74f55963c2aea03b3a7d66ceb0
|
||||
F test/fts3aa.test 6c263a6f8845205ee02550981a94c2e8dc1e7058
|
||||
F test/fts3aa.test 39b65c11913d277c91d7426c62cfc1d147d1b4e9a48fecd9e38f60d0b5a5f505
|
||||
F test/fts3ab.test 7f6cf260ae80dda064023df8e8e503e9a412b91f
|
||||
F test/fts3ac.test 636ed7486043055d4f126a0e385f2d5a82ebbf63
|
||||
F test/fts3ad.test e40570cb6f74f059129ad48bcef3d7cbc20dda49
|
||||
@@ -776,6 +779,7 @@ F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
|
||||
F test/fts3conf.test 60317efd562080e198b5bdc9fcd222ce32cf01d7
|
||||
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
|
||||
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
|
||||
F test/fts3corrupt3.test 56e0ee83e90b57f5f3644cb7d1b36a067b7b8b19cdf0dedce45e5e13cf752f65
|
||||
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
|
||||
F test/fts3d.test d3e9c8fb75135ada06bf3bab4f9666224965d708
|
||||
F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963
|
||||
@@ -788,12 +792,13 @@ F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3expr3.test c4d4a7d6327418428c96e0a3a1137c251b8dfbf8
|
||||
F test/fts3expr4.test c39a15d676b14fc439d9bf845aa7bddcf4a74dc3
|
||||
F test/fts3expr5.test f9abfffbf5e53d48a33e12a1e8f8ba2c551c9b49
|
||||
F test/fts3fault.test da49627b280b210ebc6657f76344c7851f10ce66
|
||||
F test/fts3fault2.test f953bb3cf903988172270a9a0aafd5a890b0f98f
|
||||
F test/fts3fault.test 3764ecffb3d341c5b05b3abe64153f385880035e67706ca2fc719e5d3352aedb
|
||||
F test/fts3fault2.test 536bbe01fe2946ec24b063a5eee813e8fd90354a6ca0b8f941d299c405edd17e
|
||||
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
|
||||
F test/fts3join.test 34750f3ce1e29b2749eaf0f1be2fa6301c5d50da
|
||||
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
|
||||
F test/fts3matchinfo.test ce864e0bd92429df8008f31cf557269ba172482a
|
||||
F test/fts3misc.test 66e7b59576ce2c795f0baff6d47f7f6f57e6f41101cf85fad05989e43bb060dd
|
||||
F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905
|
||||
F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c
|
||||
F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2
|
||||
@@ -813,7 +818,7 @@ F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
|
||||
F test/fts4growth.test e5390da74619cacc389711bac9349640b32c4f9a
|
||||
F test/fts4growth2.test 13ad4e76451af6e6906c95cdc725d01b00044269
|
||||
F test/fts4incr.test 4e353a0bd886ea984e56fce9e77724fc923b8d0d
|
||||
F test/fts4langid.test 65a7332c9bc257919e259a304aa8a38c41655b9d
|
||||
F test/fts4langid.test 89a107d36710dc3f44dab0861a784ffab967bd1f32c8d700b031748b9d2703c6
|
||||
F test/fts4lastrowid.test fa5e157955a3121615ef3e16ff5196e96c9e1e64
|
||||
F test/fts4merge.test d2b39f6b1bd4a9738a13540e2d044cba11c43d47
|
||||
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
|
||||
@@ -846,6 +851,7 @@ F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
F test/having.test 30a02b8a9a47cba7bdb5281999c5cbff407c2ac296511ee64dd0b418fe38eb0f
|
||||
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
|
||||
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
|
||||
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
|
||||
@@ -857,7 +863,7 @@ F test/in.test 20c5529986998949908f889c8208b2cd894b2cc9
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
|
||||
F test/in5.test 6c006e0bcd7351b69350ef566e65f244023489e9
|
||||
F test/in5.test 7ae37fcd4a5e198291c6ab5f31a5bb3d15397efe8b75a6736d7a95a7b8dd9e08
|
||||
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
|
||||
F test/incrblob2.test a5ce5ed1d0b01e2ed347245a21170372528af0a5
|
||||
F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4
|
||||
@@ -879,7 +885,7 @@ F test/index7.test 7feababe16f2091b229c22aff2bcc1d4d6b9d2bb
|
||||
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
|
||||
F test/indexedby.test 9c4cd331224e57f79fbf411ae245e6272d415985
|
||||
F test/indexexpr1.test 038b3befa74e5a75126b6e9dd2ae5df61c1c7cf7
|
||||
F test/indexexpr2.test bcf694ae72efaaeb97691b990b61e39bf233884e27b9cc6b845a1f0c6bc9f0bb
|
||||
F test/indexexpr2.test 68ee9dbe83fcf85e50f4d0bd1f742a082496f2ee5153f4be2a1861db84462bf7
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
|
||||
@@ -1029,7 +1035,7 @@ F test/parser1.test 391b9bf9a229547a129c61ac345ed1a6f5eb1854
|
||||
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test af720e7d139e7e5417341d0f0eef2b911c0b067852138dc2f5b6a451b5725118
|
||||
F test/permutations.test 8aaa22a0f428a7e6b8446b97bc7691a273eaeff5dc290fb9129bf79fa9813a6e
|
||||
F test/pragma.test 1e94755164a3a3264cd39836de4bebcb7809e5f8
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
|
||||
@@ -1039,6 +1045,7 @@ F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
|
||||
F test/printf2.test 9e6db85f81c63f2367c34a9d7db384088bd374ad
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/pushdown.test a5d2e5e66cc94cfb0989a5dd23e77427dd6c4313019155ba9051f52dfc5326aa
|
||||
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26
|
||||
@@ -1162,6 +1169,7 @@ F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
|
||||
F test/stat.test f8f1279ffffabe6df825723af18cc6e0ae70a893
|
||||
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
|
||||
F test/stmt.test 64844332db69cf1a735fcb3e11548557fc95392f
|
||||
F test/subjournal.test 2121a93ef3d3e83d52bf236c8a02aef4009fbf52884754104b2b6cad9a041095
|
||||
F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f
|
||||
F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f
|
||||
F test/subselect.test 0966aa8e720224dbd6a5e769a3ec2a723e332303
|
||||
@@ -1484,7 +1492,7 @@ F test/zerodamage.test e59a56443d6298ecf7435f618f0b27654f0c849e
|
||||
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
|
||||
F tool/GetTclKit.bat 6afa640edc7810725aec61c3076ac617c4aaf0b7
|
||||
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
|
||||
F tool/addopcodes.tcl 10c889c4a65ec6c5604e4a47306fa77ff57ae189
|
||||
F tool/addopcodes.tcl edbd53806bf20e25af2373ad0c091be4385081c1aa1813b916bf093f94ed8380
|
||||
F tool/build-all-msvc.bat c12328d06c45fec8baada5949e3d5af54bf8c887 x
|
||||
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
|
||||
F tool/cg_anno.tcl f95b0006c52cf7f0496b506343415b6ee3cdcdd3 x
|
||||
@@ -1493,12 +1501,12 @@ F tool/dbhash.c a06228aa21ebc4e6ea8daa486601d938499238a5
|
||||
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
|
||||
F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1
|
||||
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
|
||||
F tool/fuzzershell.c dbf6c26eef936ec78cb0707570de3a4308b2507e
|
||||
F tool/fuzzershell.c e1d90a03ca790d7c331c2aae08ca46ff435f1ae1faa6cb9cc48f4687c18fdc6e
|
||||
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
|
||||
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
|
||||
F tool/lemon.c 5ccba178a8e8a4b21e1c9232944d23973da38ad7
|
||||
F tool/lemon.c f4f1045743e12f86b132253a3192ef92c94bfceb7f41ac41b8e3b373aa78474e
|
||||
F tool/lempar.c db1bdb4821f2d8fbd76e577cf3ab18642c8d08d1
|
||||
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
@@ -1506,7 +1514,7 @@ F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
|
||||
F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
|
||||
F tool/mkautoconfamal.sh e855df211ecbcc7131dee817110ff386cfb112f7
|
||||
F tool/mkkeywordhash.c f7f3b342211ac6a14258b9726d5b97cf4f548f22
|
||||
F tool/mkmsvcmin.tcl 95b37e202cbed873aa8ffdbb493b9db45927be2b
|
||||
F tool/mkmsvcmin.tcl cbd93f1cfa3a0a9ae56fc958510aa3fc3ac65e29cb111716199e3d0e66eefaa4
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl a01d2c1d8a6205b03fc635adf3735b4c523befd3
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
@@ -1514,11 +1522,11 @@ F tool/mkpragmatab.tcl 32bb40741df11bddc8451de9ea4d130e7b4476d8064794b1cf402ac11
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb
|
||||
F tool/mksqlite3c.tcl 06b2e6a0f21cc0a5d70fbbd136b3e0a96470645e
|
||||
F tool/mksqlite3h.tcl b9836752c3d08f9fab2dfc0017ca9fd5d90ac863
|
||||
F tool/mksqlite3h.tcl 51bd5e7e840a920388a5966c9f2ccc618f434c57bd68c1bab4085b2553e1e237
|
||||
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
|
||||
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
|
||||
F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
|
||||
F tool/omittest.tcl 34d7ac01fe4fd18e3637f64abe12c40eca0f6b97
|
||||
F tool/omittest.tcl dfc8b18a23e9e5289104145b712cdb887c2d840c2d70dc09ce5dbeba8ed8d47c
|
||||
F tool/opcodesum.tcl 740ed206ba8c5040018988129abbf3089a0ccf4a
|
||||
F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b
|
||||
F tool/replace.tcl 60f91e8dd06ab81f74d213ecbd9c9945f32ac048
|
||||
@@ -1529,7 +1537,7 @@ F tool/showdb.c e6bc9dba233bf1b57ca0a525a2bba762db4e223de84990739db3f09c46151b1e
|
||||
F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
|
||||
F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
|
||||
F tool/showstat4.c b14159aa062f661b394ba37b6b7b94bfb8012ab9
|
||||
F tool/showwal.c ec79959834f7b21f1e0a2aa52bb7c056d2203977
|
||||
F tool/showwal.c ad9d768f96ca6199ad3a8c9562d679680bd032dd01204ea3e5ea6fb931d81847
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/spaceanal.tcl ab7d9bf68062907282a64b3e12ccbfad47193c5a
|
||||
F tool/speed-check.sh 9630ba0468b609c52f48309243d4eb6e9c34deda
|
||||
@@ -1549,7 +1557,7 @@ F tool/varint.c 5d94cb5003db9dbbcbcc5df08d66f16071aee003
|
||||
F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c
|
||||
F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d9ded5274b3cb947e98e70d587f71d6263f803b5
|
||||
F tool/warnings.sh 8a4acea31e0f9c562949a2d767329533c0930d699ea19c6704c0ca0aa9154068
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F vsixtest/App.xaml b76d3b48860e7454775c47ea38ffea9c4abe3e85
|
||||
F vsixtest/App.xaml.cpp c465147f50871165c60ca16955219f6c5812d6d8
|
||||
@@ -1572,7 +1580,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 1aa0ea8db7580aff8bed2f78117ed50019e5545cef48cab782f512a2599fd0c5
|
||||
R 3d9cb85ec554ef29a594152d50b939c6
|
||||
P 7940bff32aa6ea868a53680822d148b7ec7a075c01ae9e0d5ad9859bcc339054
|
||||
R 7f4a731db0c6ec92ab37895dd85f915a
|
||||
T *branch * doc-type
|
||||
T *sym-doc-type *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z 8239a5dd23689b99a8a3e25f527fe60a
|
||||
Z 401c4b313e85ed363ad34cfb74831800
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
e50fd48969f99bc988389c53ff46714603b1d11de12c71b55c00cbee037f073c
|
||||
cfa4aa203646f44b303138c25672293bb87d97126fe2030d4709e8ad7814a807
|
||||
+12
@@ -216,6 +216,18 @@ int sqlite3AuthCheck(
|
||||
if( db->xAuth==0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the
|
||||
** callback are either NULL pointers or zero-terminated strings that
|
||||
** contain additional details about the action to be authorized.
|
||||
**
|
||||
** The following testcase() macros show that any of the 3rd through 6th
|
||||
** parameters can be either NULL or a string. */
|
||||
testcase( zArg1==0 );
|
||||
testcase( zArg2==0 );
|
||||
testcase( zArg3==0 );
|
||||
testcase( pParse->zAuthContext==0 );
|
||||
|
||||
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
,db->auth.zAuthUser
|
||||
|
||||
+2
-3
@@ -8124,9 +8124,6 @@ int sqlite3BtreeInsert(
|
||||
** btreeMoveto() call */
|
||||
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){
|
||||
loc = 0;
|
||||
}else if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0
|
||||
&& pCur->info.nKey==pX->nKey-1 ){
|
||||
loc = -1;
|
||||
}else if( loc==0 ){
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc);
|
||||
if( rc ) return rc;
|
||||
@@ -8193,6 +8190,7 @@ int sqlite3BtreeInsert(
|
||||
}else if( loc<0 && pPage->nCell>0 ){
|
||||
assert( pPage->leaf );
|
||||
idx = ++pCur->ix;
|
||||
pCur->curFlags &= ~BTCF_ValidNKey;
|
||||
}else{
|
||||
assert( pPage->leaf );
|
||||
}
|
||||
@@ -9317,6 +9315,7 @@ static int checkTreePage(
|
||||
checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey);
|
||||
}
|
||||
maxKey = info.nKey;
|
||||
keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */
|
||||
}
|
||||
|
||||
/* Check the content overflow list */
|
||||
|
||||
+3
-1
@@ -423,8 +423,10 @@ static void computeYMD(DateTime *p){
|
||||
p->Y = 2000;
|
||||
p->M = 1;
|
||||
p->D = 1;
|
||||
}else if( !validJulianDay(p->iJD) ){
|
||||
datetimeError(p);
|
||||
return;
|
||||
}else{
|
||||
assert( validJulianDay(p->iJD) );
|
||||
Z = (int)((p->iJD + 43200000)/86400000);
|
||||
A = (int)((Z - 1867216.25)/36524.25);
|
||||
A = Z + 1 + A - (A/4);
|
||||
|
||||
+8
-1
@@ -350,7 +350,14 @@ void sqlite3DeleteFrom(
|
||||
/* Special case: A DELETE without a WHERE clause deletes everything.
|
||||
** It is easier just to erase the whole table. Prior to version 3.6.5,
|
||||
** this optimization caused the row change count (the value returned by
|
||||
** API function sqlite3_count_changes) to be set incorrectly. */
|
||||
** API function sqlite3_count_changes) to be set incorrectly.
|
||||
**
|
||||
** The "rcauth==SQLITE_OK" terms is the
|
||||
** IMPLEMENTATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and
|
||||
** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but
|
||||
** the truncate optimization is disabled and all rows are deleted
|
||||
** individually.
|
||||
*/
|
||||
if( rcauth==SQLITE_OK
|
||||
&& pWhere==0
|
||||
&& !bComplex
|
||||
|
||||
+76
-6
@@ -352,7 +352,6 @@ int sqlite3ExprVectorSize(Expr *pExpr){
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
/*
|
||||
** Return a pointer to a subexpression of pVector that is the i-th
|
||||
** column of the vector (numbered starting with 0). The caller must
|
||||
@@ -380,9 +379,7 @@ Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){
|
||||
}
|
||||
return pVector;
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) */
|
||||
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
/*
|
||||
** Compute and return a new Expr object which when passed to
|
||||
** sqlite3ExprCode() will generate all necessary code to compute
|
||||
@@ -440,7 +437,6 @@ Expr *sqlite3ExprForVectorField(
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
#endif /* !define(SQLITE_OMIT_SUBQUERY) */
|
||||
|
||||
/*
|
||||
** If expression pExpr is of type TK_SELECT, generate code to evaluate
|
||||
@@ -956,7 +952,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){
|
||||
z = pExpr->u.zToken;
|
||||
assert( z!=0 );
|
||||
assert( z[0]!=0 );
|
||||
assert( n==sqlite3Strlen30(z) );
|
||||
assert( n==(u32)sqlite3Strlen30(z) );
|
||||
if( z[1]==0 ){
|
||||
/* Wildcard of the form "?". Assign the next variable number */
|
||||
assert( z[0]=='?' );
|
||||
@@ -1550,7 +1546,7 @@ ExprList *sqlite3ExprListAppendVector(
|
||||
}
|
||||
}
|
||||
|
||||
if( pExpr->op==TK_SELECT && pList ){
|
||||
if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){
|
||||
Expr *pFirst = pList->a[iFirst].pExpr;
|
||||
assert( pFirst!=0 );
|
||||
assert( pFirst->op==TK_SELECT_COLUMN );
|
||||
@@ -1815,6 +1811,65 @@ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
|
||||
return exprIsConst(p, 3, iCur);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
|
||||
*/
|
||||
static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
|
||||
ExprList *pGroupBy = pWalker->u.pGroupBy;
|
||||
int i;
|
||||
|
||||
/* Check if pExpr is identical to any GROUP BY term. If so, consider
|
||||
** it constant. */
|
||||
for(i=0; i<pGroupBy->nExpr; i++){
|
||||
Expr *p = pGroupBy->a[i].pExpr;
|
||||
if( sqlite3ExprCompare(pExpr, p, -1)<2 ){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p);
|
||||
if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){
|
||||
return WRC_Prune;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if pExpr is a sub-select. If so, consider it variable. */
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
pWalker->eCode = 0;
|
||||
return WRC_Abort;
|
||||
}
|
||||
|
||||
return exprNodeIsConstant(pWalker, pExpr);
|
||||
}
|
||||
|
||||
/*
|
||||
** Walk the expression tree passed as the first argument. Return non-zero
|
||||
** if the expression consists entirely of constants or copies of terms
|
||||
** in pGroupBy that sort with the BINARY collation sequence.
|
||||
**
|
||||
** This routine is used to determine if a term of the HAVING clause can
|
||||
** be promoted into the WHERE clause. In order for such a promotion to work,
|
||||
** the value of the HAVING clause term must be the same for all members of
|
||||
** a "group". The requirement that the GROUP BY term must be BINARY
|
||||
** assumes that no other collating sequence will have a finer-grained
|
||||
** grouping than binary. In other words (A=B COLLATE binary) implies
|
||||
** A=B in every other collating sequence. The requirement that the
|
||||
** GROUP BY be BINARY is stricter than necessary. It would also work
|
||||
** to promote HAVING clauses that use the same alternative collating
|
||||
** sequence as the GROUP BY term, but that is much harder to check,
|
||||
** alternative collating sequences are uncommon, and this is only an
|
||||
** optimization, so we take the easy way out and simply require the
|
||||
** GROUP BY to use the BINARY collating sequence.
|
||||
*/
|
||||
int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
|
||||
Walker w;
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.eCode = 1;
|
||||
w.xExprCallback = exprNodeIsConstantOrGroupBy;
|
||||
w.u.pGroupBy = pGroupBy;
|
||||
w.pParse = pParse;
|
||||
sqlite3WalkExpr(&w, p);
|
||||
return w.eCode;
|
||||
}
|
||||
|
||||
/*
|
||||
** Walk an expression tree. Return non-zero if the expression is constant
|
||||
** or a function call with constant arguments. Return and 0 if there
|
||||
@@ -3352,7 +3407,11 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
|
||||
}else{
|
||||
*piFreeable = 0;
|
||||
if( p->op==TK_SELECT ){
|
||||
#if SQLITE_OMIT_SUBQUERY
|
||||
iResult = 0;
|
||||
#else
|
||||
iResult = sqlite3CodeSubselect(pParse, p, 0, 0);
|
||||
#endif
|
||||
}else{
|
||||
int i;
|
||||
iResult = pParse->nMem+1;
|
||||
@@ -3889,6 +3948,17 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
break;
|
||||
}
|
||||
|
||||
case TK_IF_NULL_ROW: {
|
||||
int addrINR;
|
||||
addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
|
||||
sqlite3ExprCachePush(pParse);
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
sqlite3VdbeJumpHere(v, addrINR);
|
||||
sqlite3VdbeChangeP3(v, addrINR, inReg);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Form A:
|
||||
** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END
|
||||
|
||||
+8
-1
@@ -137,9 +137,16 @@ const unsigned char sqlite3CtypeMap[256] = {
|
||||
** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
|
||||
** disabled. The default value may be changed by compiling with the
|
||||
** SQLITE_USE_URI symbol defined.
|
||||
**
|
||||
** URI filenames are enabled by default if SQLITE_HAS_CODEC is
|
||||
** enabled.
|
||||
*/
|
||||
#ifndef SQLITE_USE_URI
|
||||
# define SQLITE_USE_URI 0
|
||||
# ifdef SQLITE_HAS_CODEC
|
||||
# define SQLITE_USE_URI 1
|
||||
# else
|
||||
# define SQLITE_USE_URI 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
|
||||
|
||||
+9
-7
@@ -3095,16 +3095,18 @@ opendb_out:
|
||||
#endif
|
||||
#if defined(SQLITE_HAS_CODEC)
|
||||
if( rc==SQLITE_OK ){
|
||||
const char *zHexKey = sqlite3_uri_parameter(zOpen, "hexkey");
|
||||
if( zHexKey && zHexKey[0] ){
|
||||
const char *zKey;
|
||||
if( (zKey = sqlite3_uri_parameter(zOpen, "hexkey"))!=0 && zKey[0] ){;
|
||||
u8 iByte;
|
||||
int i;
|
||||
char zKey[40];
|
||||
for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zHexKey[i]); i++){
|
||||
iByte = (iByte<<4) + sqlite3HexToInt(zHexKey[i]);
|
||||
if( (i&1)!=0 ) zKey[i/2] = iByte;
|
||||
char zDecoded[40];
|
||||
for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
|
||||
iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
|
||||
if( (i&1)!=0 ) zDecoded[i/2] = iByte;
|
||||
}
|
||||
sqlite3_key_v2(db, 0, zKey, i/2);
|
||||
sqlite3_key_v2(db, 0, zDecoded, i/2);
|
||||
}else if( (zKey = sqlite3_uri_parameter(zOpen, "key"))!=0 ){
|
||||
sqlite3_key_v2(db, 0, zKey, sqlite3Strlen30(zKey));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+37
-5
@@ -2258,6 +2258,11 @@ static int pager_playback_one_page(
|
||||
char *aData; /* Temporary storage for the page */
|
||||
sqlite3_file *jfd; /* The file descriptor for the journal file */
|
||||
int isSynced; /* True if journal page is synced */
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/* The jrnlEnc flag is true if Journal pages should be passed through
|
||||
** the codec. It is false for pure in-memory journals. */
|
||||
const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);
|
||||
#endif
|
||||
|
||||
assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */
|
||||
assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */
|
||||
@@ -2381,14 +2386,34 @@ static int pager_playback_one_page(
|
||||
i64 ofst = (pgno-1)*(i64)pPager->pageSize;
|
||||
testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
|
||||
assert( !pagerUseWal(pPager) );
|
||||
|
||||
/* Write the data read from the journal back into the database file.
|
||||
** This is usually safe even for an encrypted database - as the data
|
||||
** was encrypted before it was written to the journal file. The exception
|
||||
** is if the data was just read from an in-memory sub-journal. In that
|
||||
** case it must be encrypted here before it is copied into the database
|
||||
** file. */
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( !jrnlEnc ){
|
||||
CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
|
||||
rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
|
||||
CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
|
||||
}else
|
||||
#endif
|
||||
rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
|
||||
|
||||
if( pgno>pPager->dbFileSize ){
|
||||
pPager->dbFileSize = pgno;
|
||||
}
|
||||
if( pPager->pBackup ){
|
||||
CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( jrnlEnc ){
|
||||
CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
|
||||
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
|
||||
CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData);
|
||||
}else
|
||||
#endif
|
||||
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
|
||||
CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
|
||||
}
|
||||
}else if( !isMainJrnl && pPg==0 ){
|
||||
/* If this is a rollback of a savepoint and data was not written to
|
||||
@@ -2440,7 +2465,9 @@ static int pager_playback_one_page(
|
||||
}
|
||||
|
||||
/* Decode the page just read from disk */
|
||||
CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
|
||||
#if SQLITE_HAS_CODEC
|
||||
if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); }
|
||||
#endif
|
||||
sqlite3PcacheRelease(pPg);
|
||||
}
|
||||
return rc;
|
||||
@@ -4452,8 +4479,13 @@ static int subjournalPage(PgHdr *pPg){
|
||||
void *pData = pPg->pData;
|
||||
i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
|
||||
char *pData2;
|
||||
|
||||
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
if( !pPager->subjInMemory ){
|
||||
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
|
||||
}else
|
||||
#endif
|
||||
pData2 = pData;
|
||||
PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
|
||||
rc = write32bits(pPager->sjfd, offset, pPg->pgno);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
+17
-17
@@ -193,6 +193,23 @@ columnlist ::= columnlist COMMA columnname carglist.
|
||||
columnlist ::= columnname carglist.
|
||||
columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
|
||||
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
|
||||
// fallback to ID if they will not parse as their original value.
|
||||
// This obviates the need for the "id" nonterminal.
|
||||
//
|
||||
%fallback ID
|
||||
ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW
|
||||
CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
||||
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN
|
||||
QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW
|
||||
ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
|
||||
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
EXCEPT INTERSECT UNION
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
REINDEX RENAME CTIME_KW IF
|
||||
.
|
||||
%wildcard ANY.
|
||||
|
||||
// Define operator precedence early so that this is the first occurrence
|
||||
// of the operator tokens in the grammer. Keeping the operators together
|
||||
// causes them to be assigned integer values that are close together,
|
||||
@@ -222,23 +239,6 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
//
|
||||
%token_class id ID|INDEXED.
|
||||
|
||||
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
|
||||
// fallback to ID if they will not parse as their original value.
|
||||
// This obviates the need for the "id" nonterminal.
|
||||
//
|
||||
%fallback ID
|
||||
ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW
|
||||
CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
||||
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN
|
||||
QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW
|
||||
ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
|
||||
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
EXCEPT INTERSECT UNION
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
REINDEX RENAME CTIME_KW IF
|
||||
.
|
||||
%wildcard ANY.
|
||||
|
||||
|
||||
// And "ids" is an identifer-or-string.
|
||||
//
|
||||
|
||||
+30
-26
@@ -1329,33 +1329,37 @@ void sqlite3Pragma(
|
||||
assert( x==0 );
|
||||
}
|
||||
addrOk = sqlite3VdbeMakeLabel(v);
|
||||
if( pParent && pIdx==0 ){
|
||||
int iKey = pFK->aCol[0].iFrom;
|
||||
assert( iKey>=0 && iKey<pTab->nCol );
|
||||
if( iKey!=pTab->iPKey ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
|
||||
sqlite3ColumnDefault(v, pTab, iKey, regRow);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v);
|
||||
sqlite3VdbeGoto(v, addrOk);
|
||||
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
|
||||
}else{
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
|
||||
aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
|
||||
}
|
||||
if( pParent ){
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
|
||||
sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* Generate code to read the child key values into registers
|
||||
** regRow..regRow+n. If any of the child key values are NULL, this
|
||||
** row cannot cause an FK violation. Jump directly to addrOk in
|
||||
** this case. */
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* Generate code to query the parent index for a matching parent
|
||||
** key. If a match is found, jump to addrOk. */
|
||||
if( pIdx ){
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
|
||||
sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
|
||||
VdbeCoverage(v);
|
||||
}else if( pParent ){
|
||||
int jmp = sqlite3VdbeCurrentAddr(v)+2;
|
||||
sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v);
|
||||
sqlite3VdbeGoto(v, addrOk);
|
||||
assert( pFK->nCol==1 );
|
||||
}
|
||||
|
||||
/* Generate code to report an FK violation to the caller. */
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
|
||||
sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
|
||||
sqlite3VdbeResolveLabel(v, addrOk);
|
||||
|
||||
+229
-68
@@ -3144,9 +3144,24 @@ static int multiSelectOrderBy(
|
||||
#endif
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
|
||||
/* An instance of the SubstContext object describes an substitution edit
|
||||
** to be performed on a parse tree.
|
||||
**
|
||||
** All references to columns in table iTable are to be replaced by corresponding
|
||||
** expressions in pEList.
|
||||
*/
|
||||
typedef struct SubstContext {
|
||||
Parse *pParse; /* The parsing context */
|
||||
int iTable; /* Replace references to this table */
|
||||
int iNewTable; /* New table number */
|
||||
int isLeftJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
|
||||
ExprList *pEList; /* Replacement expressions */
|
||||
} SubstContext;
|
||||
|
||||
/* Forward Declarations */
|
||||
static void substExprList(Parse*, ExprList*, int, ExprList*);
|
||||
static void substSelect(Parse*, Select *, int, ExprList*, int);
|
||||
static void substExprList(SubstContext*, ExprList*);
|
||||
static void substSelect(SubstContext*, Select*, int);
|
||||
|
||||
/*
|
||||
** Scan through the expression pExpr. Replace every reference to
|
||||
@@ -3162,24 +3177,33 @@ static void substSelect(Parse*, Select *, int, ExprList*, int);
|
||||
** of the subquery rather the result set of the subquery.
|
||||
*/
|
||||
static Expr *substExpr(
|
||||
Parse *pParse, /* Report errors here */
|
||||
Expr *pExpr, /* Expr in which substitution occurs */
|
||||
int iTable, /* Table to be substituted */
|
||||
ExprList *pEList /* Substitute expressions */
|
||||
SubstContext *pSubst, /* Description of the substitution */
|
||||
Expr *pExpr /* Expr in which substitution occurs */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( pExpr==0 ) return 0;
|
||||
if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) && pExpr->iRightJoinTable==pSubst->iTable ){
|
||||
pExpr->iRightJoinTable = pSubst->iNewTable;
|
||||
}
|
||||
if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){
|
||||
if( pExpr->iColumn<0 ){
|
||||
pExpr->op = TK_NULL;
|
||||
}else{
|
||||
Expr *pNew;
|
||||
Expr *pCopy = pEList->a[pExpr->iColumn].pExpr;
|
||||
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
|
||||
Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
|
||||
Expr ifNullRow;
|
||||
assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
|
||||
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
||||
if( sqlite3ExprIsVector(pCopy) ){
|
||||
sqlite3VectorErrorMsg(pParse, pCopy);
|
||||
sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
|
||||
}else{
|
||||
sqlite3 *db = pSubst->pParse->db;
|
||||
if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){
|
||||
memset(&ifNullRow, 0, sizeof(ifNullRow));
|
||||
ifNullRow.op = TK_IF_NULL_ROW;
|
||||
ifNullRow.pLeft = pCopy;
|
||||
ifNullRow.iTable = pSubst->iNewTable;
|
||||
pCopy = &ifNullRow;
|
||||
}
|
||||
pNew = sqlite3ExprDup(db, pCopy, 0);
|
||||
if( pNew && (pExpr->flags & EP_FromJoin) ){
|
||||
pNew->iRightJoinTable = pExpr->iRightJoinTable;
|
||||
@@ -3190,51 +3214,47 @@ static Expr *substExpr(
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pExpr->pLeft = substExpr(pParse, pExpr->pLeft, iTable, pEList);
|
||||
pExpr->pRight = substExpr(pParse, pExpr->pRight, iTable, pEList);
|
||||
pExpr->pLeft = substExpr(pSubst, pExpr->pLeft);
|
||||
pExpr->pRight = substExpr(pSubst, pExpr->pRight);
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
substSelect(pParse, pExpr->x.pSelect, iTable, pEList, 1);
|
||||
substSelect(pSubst, pExpr->x.pSelect, 1);
|
||||
}else{
|
||||
substExprList(pParse, pExpr->x.pList, iTable, pEList);
|
||||
substExprList(pSubst, pExpr->x.pList);
|
||||
}
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
static void substExprList(
|
||||
Parse *pParse, /* Report errors here */
|
||||
ExprList *pList, /* List to scan and in which to make substitutes */
|
||||
int iTable, /* Table to be substituted */
|
||||
ExprList *pEList /* Substitute values */
|
||||
SubstContext *pSubst, /* Description of the substitution */
|
||||
ExprList *pList /* List to scan and in which to make substitutes */
|
||||
){
|
||||
int i;
|
||||
if( pList==0 ) return;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
pList->a[i].pExpr = substExpr(pParse, pList->a[i].pExpr, iTable, pEList);
|
||||
pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr);
|
||||
}
|
||||
}
|
||||
static void substSelect(
|
||||
Parse *pParse, /* Report errors here */
|
||||
Select *p, /* SELECT statement in which to make substitutions */
|
||||
int iTable, /* Table to be replaced */
|
||||
ExprList *pEList, /* Substitute values */
|
||||
int doPrior /* Do substitutes on p->pPrior too */
|
||||
SubstContext *pSubst, /* Description of the substitution */
|
||||
Select *p, /* SELECT statement in which to make substitutions */
|
||||
int doPrior /* Do substitutes on p->pPrior too */
|
||||
){
|
||||
SrcList *pSrc;
|
||||
struct SrcList_item *pItem;
|
||||
int i;
|
||||
if( !p ) return;
|
||||
do{
|
||||
substExprList(pParse, p->pEList, iTable, pEList);
|
||||
substExprList(pParse, p->pGroupBy, iTable, pEList);
|
||||
substExprList(pParse, p->pOrderBy, iTable, pEList);
|
||||
p->pHaving = substExpr(pParse, p->pHaving, iTable, pEList);
|
||||
p->pWhere = substExpr(pParse, p->pWhere, iTable, pEList);
|
||||
substExprList(pSubst, p->pEList);
|
||||
substExprList(pSubst, p->pGroupBy);
|
||||
substExprList(pSubst, p->pOrderBy);
|
||||
p->pHaving = substExpr(pSubst, p->pHaving);
|
||||
p->pWhere = substExpr(pSubst, p->pWhere);
|
||||
pSrc = p->pSrc;
|
||||
assert( pSrc!=0 );
|
||||
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
|
||||
substSelect(pParse, pItem->pSelect, iTable, pEList, 1);
|
||||
substSelect(pSubst, pItem->pSelect, 1);
|
||||
if( pItem->fg.isTabFunc ){
|
||||
substExprList(pParse, pItem->u1.pFuncArg, iTable, pEList);
|
||||
substExprList(pSubst, pItem->u1.pFuncArg);
|
||||
}
|
||||
}
|
||||
}while( doPrior && (p = p->pPrior)!=0 );
|
||||
@@ -3277,8 +3297,8 @@ static void substSelect(
|
||||
** FROM-clause subquery that is a candidate for flattening. (2b is
|
||||
** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
|
||||
**
|
||||
** (3) The subquery is not the right operand of a left outer join
|
||||
** (Originally ticket #306. Strengthened by ticket #3300)
|
||||
** (3) The subquery is not the right operand of a LEFT JOIN
|
||||
** or the subquery is not itself a join.
|
||||
**
|
||||
** (4) The subquery is not DISTINCT.
|
||||
**
|
||||
@@ -3290,7 +3310,7 @@ static void substSelect(
|
||||
** DISTINCT.
|
||||
**
|
||||
** (7) The subquery has a FROM clause. TODO: For subqueries without
|
||||
** A FROM clause, consider adding a FROM close with the special
|
||||
** A FROM clause, consider adding a FROM clause with the special
|
||||
** table sqlite_once that consists of a single row containing a
|
||||
** single NULL.
|
||||
**
|
||||
@@ -3396,6 +3416,8 @@ static int flattenSubquery(
|
||||
SrcList *pSubSrc; /* The FROM clause of the subquery */
|
||||
ExprList *pList; /* The result set of the outer query */
|
||||
int iParent; /* VDBE cursor number of the pSub result set temp table */
|
||||
int iNewParent = -1;/* Replacement table for iParent */
|
||||
int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */
|
||||
int i; /* Loop counter */
|
||||
Expr *pWhere; /* The WHERE clause */
|
||||
struct SrcList_item *pSubitem; /* The subquery */
|
||||
@@ -3422,7 +3444,7 @@ static int flattenSubquery(
|
||||
return 0; /* Restriction (2b) */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pSubSrc = pSub->pSrc;
|
||||
assert( pSubSrc );
|
||||
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
|
||||
@@ -3460,10 +3482,9 @@ static int flattenSubquery(
|
||||
return 0; /* Restriction (23) */
|
||||
}
|
||||
|
||||
/* OBSOLETE COMMENT 1:
|
||||
** Restriction 3: If the subquery is a join, make sure the subquery is
|
||||
** not used as the right operand of an outer join. Examples of why this
|
||||
** is not allowed:
|
||||
/*
|
||||
** If the subquery is the right operand of a LEFT JOIN, then the
|
||||
** subquery may not be a join itself. Example of why this is not allowed:
|
||||
**
|
||||
** t1 LEFT OUTER JOIN (t2 JOIN t3)
|
||||
**
|
||||
@@ -3473,27 +3494,13 @@ static int flattenSubquery(
|
||||
**
|
||||
** which is not at all the same thing.
|
||||
**
|
||||
** OBSOLETE COMMENT 2:
|
||||
** Restriction 12: If the subquery is the right operand of a left outer
|
||||
** join, make sure the subquery has no WHERE clause.
|
||||
** An examples of why this is not allowed:
|
||||
**
|
||||
** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
|
||||
**
|
||||
** If we flatten the above, we would get
|
||||
**
|
||||
** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
|
||||
**
|
||||
** But the t2.x>0 test will always fail on a NULL row of t2, which
|
||||
** effectively converts the OUTER JOIN into an INNER JOIN.
|
||||
**
|
||||
** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE:
|
||||
** Ticket #3300 shows that flattening the right term of a LEFT JOIN
|
||||
** is fraught with danger. Best to avoid the whole thing. If the
|
||||
** subquery is the right term of a LEFT JOIN, then do not flatten.
|
||||
** See also tickets #306, #350, and #3300.
|
||||
*/
|
||||
if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
|
||||
return 0;
|
||||
isLeftJoin = 1;
|
||||
if( pSubSrc->nSrc>1 ){
|
||||
return 0; /* Restriction (3) */
|
||||
}
|
||||
}
|
||||
|
||||
/* Restriction 17: If the sub-query is a compound SELECT, then it must
|
||||
@@ -3702,6 +3709,7 @@ static int flattenSubquery(
|
||||
sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing);
|
||||
assert( pSrc->a[i+iFrom].fg.isTabFunc==0 );
|
||||
pSrc->a[i+iFrom] = pSubSrc->a[i];
|
||||
iNewParent = pSubSrc->a[i].iCursor;
|
||||
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
|
||||
}
|
||||
pSrc->a[iFrom].fg.jointype = jointype;
|
||||
@@ -3747,6 +3755,9 @@ static int flattenSubquery(
|
||||
pSub->pOrderBy = 0;
|
||||
}
|
||||
pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
|
||||
if( isLeftJoin ){
|
||||
setJoinExpr(pWhere, iNewParent);
|
||||
}
|
||||
if( subqueryIsAgg ){
|
||||
assert( pParent->pHaving==0 );
|
||||
pParent->pHaving = pParent->pWhere;
|
||||
@@ -3760,7 +3771,13 @@ static int flattenSubquery(
|
||||
pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
|
||||
}
|
||||
if( db->mallocFailed==0 ){
|
||||
substSelect(pParse, pParent, iParent, pSub->pEList, 0);
|
||||
SubstContext x;
|
||||
x.pParse = pParse;
|
||||
x.iTable = iParent;
|
||||
x.iNewTable = iNewParent;
|
||||
x.isLeftJoin = isLeftJoin;
|
||||
x.pEList = pSub->pEList;
|
||||
substSelect(&x, pParent, 0);
|
||||
}
|
||||
|
||||
/* The flattened query is distinct if either the inner or the
|
||||
@@ -3863,8 +3880,14 @@ static int pushDownWhereTerms(
|
||||
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
|
||||
nChng++;
|
||||
while( pSubq ){
|
||||
SubstContext x;
|
||||
pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
|
||||
pNew = substExpr(pParse, pNew, iCursor, pSubq->pEList);
|
||||
x.pParse = pParse;
|
||||
x.iTable = iCursor;
|
||||
x.iNewTable = iCursor;
|
||||
x.isLeftJoin = 0;
|
||||
x.pEList = pSubq->pEList;
|
||||
pNew = substExpr(&x, pNew);
|
||||
pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
|
||||
pSubq = pSubq->pPrior;
|
||||
}
|
||||
@@ -4856,6 +4879,103 @@ static void explainSimpleCount(
|
||||
# define explainSimpleCount(a,b,c)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Context object for havingToWhereExprCb().
|
||||
*/
|
||||
struct HavingToWhereCtx {
|
||||
Expr **ppWhere;
|
||||
ExprList *pGroupBy;
|
||||
};
|
||||
|
||||
/*
|
||||
** sqlite3WalkExpr() callback used by havingToWhere().
|
||||
**
|
||||
** If the node passed to the callback is a TK_AND node, return
|
||||
** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes.
|
||||
**
|
||||
** Otherwise, return WRC_Prune. In this case, also check if the
|
||||
** sub-expression matches the criteria for being moved to the WHERE
|
||||
** clause. If so, add it to the WHERE clause and replace the sub-expression
|
||||
** within the HAVING expression with a constant "1".
|
||||
*/
|
||||
static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op!=TK_AND ){
|
||||
struct HavingToWhereCtx *p = pWalker->u.pHavingCtx;
|
||||
if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, p->pGroupBy) ){
|
||||
sqlite3 *db = pWalker->pParse->db;
|
||||
Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0);
|
||||
if( pNew ){
|
||||
Expr *pWhere = *(p->ppWhere);
|
||||
SWAP(Expr, *pNew, *pExpr);
|
||||
pNew = sqlite3ExprAnd(db, pWhere, pNew);
|
||||
*(p->ppWhere) = pNew;
|
||||
}
|
||||
}
|
||||
return WRC_Prune;
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Transfer eligible terms from the HAVING clause of a query, which is
|
||||
** processed after grouping, to the WHERE clause, which is processed before
|
||||
** grouping. For example, the query:
|
||||
**
|
||||
** SELECT * FROM <tables> WHERE a=? GROUP BY b HAVING b=? AND c=?
|
||||
**
|
||||
** can be rewritten as:
|
||||
**
|
||||
** SELECT * FROM <tables> WHERE a=? AND b=? GROUP BY b HAVING c=?
|
||||
**
|
||||
** A term of the HAVING expression is eligible for transfer if it consists
|
||||
** entirely of constants and expressions that are also GROUP BY terms that
|
||||
** use the "BINARY" collation sequence.
|
||||
*/
|
||||
static void havingToWhere(
|
||||
Parse *pParse,
|
||||
ExprList *pGroupBy,
|
||||
Expr *pHaving,
|
||||
Expr **ppWhere
|
||||
){
|
||||
struct HavingToWhereCtx sCtx;
|
||||
Walker sWalker;
|
||||
|
||||
sCtx.ppWhere = ppWhere;
|
||||
sCtx.pGroupBy = pGroupBy;
|
||||
|
||||
memset(&sWalker, 0, sizeof(sWalker));
|
||||
sWalker.pParse = pParse;
|
||||
sWalker.xExprCallback = havingToWhereExprCb;
|
||||
sWalker.u.pHavingCtx = &sCtx;
|
||||
sqlite3WalkExpr(&sWalker, pHaving);
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if the pThis entry of pTabList is a self-join of a prior view.
|
||||
** If it is, then return the SrcList_item for the prior view. If it is not,
|
||||
** then return 0.
|
||||
*/
|
||||
static struct SrcList_item *isSelfJoinView(
|
||||
SrcList *pTabList, /* Search for self-joins in this FROM clause */
|
||||
struct SrcList_item *pThis /* Search for prior reference to this subquery */
|
||||
){
|
||||
struct SrcList_item *pItem;
|
||||
for(pItem = pTabList->a; pItem<pThis; pItem++){
|
||||
if( pItem->pSelect==0 ) continue;
|
||||
if( pItem->fg.viaCoroutine ) continue;
|
||||
if( pItem->zName==0 ) continue;
|
||||
if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue;
|
||||
if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
|
||||
if( sqlite3ExprCompare(pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) ){
|
||||
/* The view was modified by some other optimization such as
|
||||
** pushDownWhereTerms() */
|
||||
continue;
|
||||
}
|
||||
return pItem;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for the SELECT statement given in the p argument.
|
||||
**
|
||||
@@ -4995,13 +5115,38 @@ int sqlite3Select(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate code for all sub-queries in the FROM clause
|
||||
/* For each term in the FROM clause, do two things:
|
||||
** (1) Authorized unreferenced tables
|
||||
** (2) Generate code for all sub-queries
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pTabList->a[i];
|
||||
SelectDest dest;
|
||||
Select *pSub = pItem->pSelect;
|
||||
Select *pSub;
|
||||
|
||||
/* Issue SQLITE_READ authorizations with a fake column name for any tables that
|
||||
** are referenced but from which no values are extracted. Examples of where these
|
||||
** kinds of null SQLITE_READ authorizations would occur:
|
||||
**
|
||||
** SELECT count(*) FROM t1; -- SQLITE_READ t1.""
|
||||
** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2.""
|
||||
**
|
||||
** The fake column name is an empty string. It is possible for a table to
|
||||
** have a column named by the empty string, in which case there is no way to
|
||||
** distinguish between an unreferenced table and an actual reference to the
|
||||
** "" column. The original design was for the fake column name to be a NULL,
|
||||
** which would be unambiguous. But legacy authorization callbacks might
|
||||
** 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 ){
|
||||
sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
/* Generate code for all sub-queries in the FROM clause
|
||||
*/
|
||||
pSub = pItem->pSelect;
|
||||
if( pSub==0 ) continue;
|
||||
|
||||
/* Sometimes the code for a subquery will be generated more than
|
||||
@@ -5012,6 +5157,10 @@ int sqlite3Select(
|
||||
** to be invoked again. */
|
||||
if( pItem->addrFillSub ){
|
||||
if( pItem->fg.viaCoroutine==0 ){
|
||||
/* The subroutine that manifests the view might be a one-time routine,
|
||||
** or it might need to be rerun on each iteration because it
|
||||
** encodes a correlated subquery. */
|
||||
testcase( sqlite3VdbeGetOp(v, pItem->addrFillSub)->opcode==OP_Once );
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
|
||||
}
|
||||
continue;
|
||||
@@ -5086,6 +5235,8 @@ int sqlite3Select(
|
||||
int topAddr;
|
||||
int onceAddr = 0;
|
||||
int retAddr;
|
||||
struct SrcList_item *pPrior;
|
||||
|
||||
assert( pItem->addrFillSub==0 );
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||
@@ -5099,9 +5250,14 @@ int sqlite3Select(
|
||||
}else{
|
||||
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pPrior = isSelfJoinView(pTabList, pItem);
|
||||
if( pPrior ){
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
|
||||
}else{
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
}
|
||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
||||
@@ -5111,8 +5267,8 @@ int sqlite3Select(
|
||||
}
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
pParse->nHeight -= sqlite3SelectExprHeight(p);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Various elements of the SELECT copied into local variables for
|
||||
** convenience */
|
||||
@@ -5320,6 +5476,11 @@ int sqlite3Select(
|
||||
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
||||
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
||||
if( pHaving ){
|
||||
if( pGroupBy ){
|
||||
assert( pWhere==p->pWhere );
|
||||
havingToWhere(pParse, pGroupBy, pHaving, &p->pWhere);
|
||||
pWhere = p->pWhere;
|
||||
}
|
||||
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
||||
}
|
||||
sAggInfo.nAccumulator = sAggInfo.nColumn;
|
||||
|
||||
+38
-16
@@ -427,6 +427,36 @@ static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Output string zUtf to stream pOut as w characters. If w is negative,
|
||||
** then right-justify the text. W is the width in UTF-8 characters, not
|
||||
** in bytes. This is different from the %*.*s specification in printf
|
||||
** since with %*.*s the width is measured in bytes, not characters.
|
||||
*/
|
||||
static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
|
||||
int i;
|
||||
int n;
|
||||
int aw = w<0 ? -w : w;
|
||||
char zBuf[1000];
|
||||
if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3;
|
||||
for(i=n=0; zUtf[i]; i++){
|
||||
if( (zUtf[i]&0xc0)!=0x80 ){
|
||||
n++;
|
||||
if( n==aw ){
|
||||
do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( n>=aw ){
|
||||
utf8_printf(pOut, "%.*s", i, zUtf);
|
||||
}else if( w<0 ){
|
||||
utf8_printf(pOut, "%*s%s", aw-n, "", zUtf);
|
||||
}else{
|
||||
utf8_printf(pOut, "%s%*s", zUtf, aw-n, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Determines if a string is a number of not.
|
||||
@@ -714,6 +744,10 @@ struct SHA3Context {
|
||||
unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
|
||||
};
|
||||
|
||||
/* Allow the following routine to use the B0 variable, which is also
|
||||
** a macro in the termios.h header file */
|
||||
#undef B0
|
||||
|
||||
/*
|
||||
** A single step of the Keccak mixing function for a 1600-bit state
|
||||
*/
|
||||
@@ -1878,13 +1912,8 @@ static int shell_callback(
|
||||
p->actualWidth[i] = w;
|
||||
}
|
||||
if( showHdr ){
|
||||
if( w<0 ){
|
||||
utf8_printf(p->out,"%*.*s%s",-w,-w,azCol[i],
|
||||
i==nArg-1 ? rowSep : " ");
|
||||
}else{
|
||||
utf8_printf(p->out,"%-*.*s%s",w,w,azCol[i],
|
||||
i==nArg-1 ? rowSep : " ");
|
||||
}
|
||||
utf8_width_print(p->out, w, azCol[i]);
|
||||
utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
|
||||
}
|
||||
}
|
||||
if( showHdr ){
|
||||
@@ -1920,15 +1949,8 @@ static int shell_callback(
|
||||
}
|
||||
p->iIndent++;
|
||||
}
|
||||
if( w<0 ){
|
||||
utf8_printf(p->out,"%*.*s%s",-w,-w,
|
||||
azArg[i] ? azArg[i] : p->nullValue,
|
||||
i==nArg-1 ? rowSep : " ");
|
||||
}else{
|
||||
utf8_printf(p->out,"%-*.*s%s",w,w,
|
||||
azArg[i] ? azArg[i] : p->nullValue,
|
||||
i==nArg-1 ? rowSep : " ");
|
||||
}
|
||||
utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
|
||||
utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+19
-7
@@ -857,7 +857,7 @@ struct sqlite3_io_methods {
|
||||
** opcode allows these two values (10 retries and 25 milliseconds of delay)
|
||||
** to be adjusted. The values are changed for all database connections
|
||||
** within the same process. The argument is a pointer to an array of two
|
||||
** integers where the first integer i the new retry count and the second
|
||||
** integers where the first integer is the new retry count and the second
|
||||
** integer is the delay. If either integer is negative, then the setting
|
||||
** is not changed but instead the prior value of that setting is written
|
||||
** into the array entry, allowing the current retry settings to be
|
||||
@@ -2673,6 +2673,7 @@ void sqlite3_randomness(int N, void *P);
|
||||
/*
|
||||
** CAPI3REF: Compile-Time Authorization Callbacks
|
||||
** METHOD: sqlite3
|
||||
** KEYWORDS: {authorizer callback}
|
||||
**
|
||||
** ^This routine registers an authorizer callback with a particular
|
||||
** [database connection], supplied in the first argument.
|
||||
@@ -2700,8 +2701,10 @@ void sqlite3_randomness(int N, void *P);
|
||||
** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
|
||||
** to the callback is an integer [SQLITE_COPY | action code] that specifies
|
||||
** the particular action to be authorized. ^The third through sixth parameters
|
||||
** to the callback are zero-terminated strings that contain additional
|
||||
** details about the action to be authorized.
|
||||
** to the callback are either NULL pointers or zero-terminated strings
|
||||
** that contain additional details about the action to be authorized.
|
||||
** Applications must always be prepared to encounter a NULL pointer in any
|
||||
** of the third through the sixth parameters of the authorization callback.
|
||||
**
|
||||
** ^If the action code is [SQLITE_READ]
|
||||
** and the callback returns [SQLITE_IGNORE] then the
|
||||
@@ -2710,6 +2713,10 @@ void sqlite3_randomness(int N, void *P);
|
||||
** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
|
||||
** return can be used to deny an untrusted user access to individual
|
||||
** columns of a table.
|
||||
** ^When a table is referenced by a [SELECT] but no column values are
|
||||
** extracted from that table (for example in a query like
|
||||
** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
|
||||
** is invoked once for that table with a column name that is an empty string.
|
||||
** ^If the action code is [SQLITE_DELETE] and the callback returns
|
||||
** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
|
||||
** [truncate optimization] is disabled and all rows are deleted individually.
|
||||
@@ -4756,10 +4763,11 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
||||
** the compiled regular expression can be reused on multiple
|
||||
** invocations of the same function.
|
||||
**
|
||||
** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
|
||||
** associated by the sqlite3_set_auxdata() function with the Nth argument
|
||||
** value to the application-defined function. ^If there is no metadata
|
||||
** associated with the function argument, this sqlite3_get_auxdata() interface
|
||||
** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
|
||||
** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
|
||||
** value to the application-defined function. ^N is zero for the left-most
|
||||
** function argument. ^If there is no metadata
|
||||
** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
|
||||
** returns a NULL pointer.
|
||||
**
|
||||
** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
|
||||
@@ -4790,6 +4798,10 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
||||
** function parameters that are compile-time constants, including literal
|
||||
** values and [parameters] and expressions composed from the same.)^
|
||||
**
|
||||
** The value of the N parameter to these interfaces should be non-negative.
|
||||
** Future enhancements may make use of negative N values to define new
|
||||
** kinds of function caching behavior.
|
||||
**
|
||||
** These routines must be called from the same thread in which
|
||||
** the SQL function is running.
|
||||
*/
|
||||
|
||||
+12
-9
@@ -3316,15 +3316,17 @@ struct Walker {
|
||||
int walkerDepth; /* Number of subqueries */
|
||||
u8 eCode; /* A small processing code */
|
||||
union { /* Extra data for callback */
|
||||
NameContext *pNC; /* Naming context */
|
||||
int n; /* A counter */
|
||||
int iCur; /* A cursor number */
|
||||
SrcList *pSrcList; /* FROM clause */
|
||||
struct SrcCount *pSrcCount; /* Counting column references */
|
||||
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
|
||||
int *aiCol; /* array of column indexes */
|
||||
struct IdxCover *pIdxCover; /* Check for index coverage */
|
||||
struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */
|
||||
NameContext *pNC; /* Naming context */
|
||||
int n; /* A counter */
|
||||
int iCur; /* A cursor number */
|
||||
SrcList *pSrcList; /* FROM clause */
|
||||
struct SrcCount *pSrcCount; /* Counting column references */
|
||||
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
|
||||
int *aiCol; /* array of column indexes */
|
||||
struct IdxCover *pIdxCover; /* Check for index coverage */
|
||||
struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */
|
||||
ExprList *pGroupBy; /* GROUP BY clause */
|
||||
struct HavingToWhereCtx *pHavingCtx; /* HAVING to WHERE clause ctx */
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -3794,6 +3796,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
|
||||
int sqlite3ExprIsConstant(Expr*);
|
||||
int sqlite3ExprIsConstantNotJoin(Expr*);
|
||||
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
|
||||
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
|
||||
int sqlite3ExprIsTableConstant(Expr*,int);
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
int sqlite3ExprContainsSubquery(Expr*);
|
||||
|
||||
@@ -1033,9 +1033,16 @@ static int auth_callback(
|
||||
Tcl_DString str;
|
||||
int rc;
|
||||
const char *zReply;
|
||||
/* EVIDENCE-OF: R-38590-62769 The first parameter to the authorizer
|
||||
** callback is a copy of the third parameter to the
|
||||
** sqlite3_set_authorizer() interface.
|
||||
*/
|
||||
SqliteDb *pDb = (SqliteDb*)pArg;
|
||||
if( pDb->disableAuth ) return SQLITE_OK;
|
||||
|
||||
/* EVIDENCE-OF: R-56518-44310 The second parameter to the callback is an
|
||||
** integer action code that specifies the particular action to be
|
||||
** authorized. */
|
||||
switch( code ){
|
||||
case SQLITE_COPY : zCode="SQLITE_COPY"; break;
|
||||
case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break;
|
||||
|
||||
-47
@@ -4949,52 +4949,6 @@ static int SQLITE_TCLAPI test_interrupt(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static u8 *sqlite3_stack_baseline = 0;
|
||||
|
||||
/*
|
||||
** Fill the stack with a known bitpattern.
|
||||
*/
|
||||
static void prepStack(void){
|
||||
int i;
|
||||
u32 bigBuf[65536];
|
||||
for(i=0; i<sizeof(bigBuf)/sizeof(bigBuf[0]); i++) bigBuf[i] = 0xdeadbeef;
|
||||
sqlite3_stack_baseline = (u8*)&bigBuf[65536];
|
||||
}
|
||||
|
||||
/*
|
||||
** Get the current stack depth. Used for debugging only.
|
||||
*/
|
||||
u64 sqlite3StackDepth(void){
|
||||
u8 x;
|
||||
return (u64)(sqlite3_stack_baseline - &x);
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_stack_used DB SQL
|
||||
**
|
||||
** Try to measure the amount of stack space used by a call to sqlite3_exec
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_stack_used(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int argc,
|
||||
char **argv
|
||||
){
|
||||
sqlite3 *db;
|
||||
int i;
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" DB SQL", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
prepStack();
|
||||
(void)sqlite3_exec(db, argv[2], 0, 0, 0);
|
||||
for(i=65535; i>=0 && ((u32*)sqlite3_stack_baseline)[-i]==0xdeadbeef; i--){}
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(i*4));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite_delete_function DB function-name
|
||||
**
|
||||
@@ -7473,7 +7427,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite_delete_function", (Tcl_CmdProc*)delete_function },
|
||||
{ "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation },
|
||||
{ "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit },
|
||||
{ "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used },
|
||||
{ "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout },
|
||||
{ "printf", (Tcl_CmdProc*)test_printf },
|
||||
{ "sqlite3IoTrace", (Tcl_CmdProc*)test_io_trace },
|
||||
|
||||
+36
-18
@@ -19,14 +19,12 @@
|
||||
** above.
|
||||
*/
|
||||
|
||||
#if SQLITE_OS_WIN
|
||||
# include <io.h>
|
||||
# define F_OK 0
|
||||
#else
|
||||
#ifndef SQLITE_OS_WIN
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/* The following #defines are copied from test_multiplex.c */
|
||||
@@ -57,23 +55,37 @@ static void sqlite3Delete83Name(char *z){
|
||||
** set *pbExists to true and unlink it. Or, if the file does not exist,
|
||||
** set *pbExists to false before returning.
|
||||
**
|
||||
** If an error occurs, the value of errno is returned. Or, if no error
|
||||
** occurs, zero is returned.
|
||||
** If an error occurs, non-zero is returned. Or, if no error occurs, zero.
|
||||
*/
|
||||
static int sqlite3DeleteUnlinkIfExists(const char *zFile, int *pbExists){
|
||||
int rc;
|
||||
static int sqlite3DeleteUnlinkIfExists(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zFile,
|
||||
int *pbExists
|
||||
){
|
||||
int rc = SQLITE_ERROR;
|
||||
#if SQLITE_OS_WIN
|
||||
if( pVfs ){
|
||||
if( pbExists ) *pbExists = 1;
|
||||
rc = pVfs->xDelete(pVfs, zFile, 0);
|
||||
if( rc==SQLITE_IOERR_DELETE_NOENT ){
|
||||
if( pbExists ) *pbExists = 0;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
#else
|
||||
assert( pVfs==0 );
|
||||
rc = access(zFile, F_OK);
|
||||
if( rc ){
|
||||
if( errno==ENOENT ){
|
||||
if( pbExists ) *pbExists = 0;
|
||||
return 0;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return errno;
|
||||
}else{
|
||||
if( pbExists ) *pbExists = 1;
|
||||
rc = unlink(zFile);
|
||||
}
|
||||
if( pbExists ) *pbExists = 1;
|
||||
rc = unlink(zFile);
|
||||
if( rc ) return errno;
|
||||
return 0;
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -103,6 +115,12 @@ SQLITE_API int sqlite3_delete_database(
|
||||
{ "%s-wal%03d", SQLITE_MULTIPLEX_WAL_8_3_OFFSET, 1 },
|
||||
};
|
||||
|
||||
#ifdef SQLITE_OS_WIN
|
||||
sqlite3_vfs *pVfs = sqlite3_vfs_find("win32");
|
||||
#else
|
||||
sqlite3_vfs *pVfs = 0;
|
||||
#endif
|
||||
|
||||
/* Allocate a buffer large enough for any of the files that need to be
|
||||
** deleted. */
|
||||
nBuf = (int)strlen(zFile) + 100;
|
||||
@@ -113,10 +131,10 @@ SQLITE_API int sqlite3_delete_database(
|
||||
** journal, wal and shm files. */
|
||||
for(i=0; rc==0 && i<sizeof(azFmt)/sizeof(azFmt[0]); i++){
|
||||
sqlite3_snprintf(nBuf, zBuf, azFmt[i], zFile);
|
||||
rc = sqlite3DeleteUnlinkIfExists(zBuf, 0);
|
||||
rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, 0);
|
||||
if( rc==0 && i!=0 ){
|
||||
sqlite3Delete83Name(zBuf);
|
||||
rc = sqlite3DeleteUnlinkIfExists(zBuf, 0);
|
||||
rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +146,7 @@ SQLITE_API int sqlite3_delete_database(
|
||||
int bExists;
|
||||
sqlite3_snprintf(nBuf, zBuf, p->zFmt, zFile, iChunk+p->iOffset);
|
||||
if( p->b83 ) sqlite3Delete83Name(zBuf);
|
||||
rc = sqlite3DeleteUnlinkIfExists(zBuf, &bExists);
|
||||
rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, &bExists);
|
||||
if( bExists==0 || rc!=0 ) break;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-2
@@ -238,7 +238,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
const char *zBinOp = 0; /* Binary operator */
|
||||
const char *zUniOp = 0; /* Unary operator */
|
||||
char zFlgs[30];
|
||||
char zFlgs[60];
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
if( pExpr==0 ){
|
||||
sqlite3TreeViewLine(pView, "nil");
|
||||
@@ -246,7 +246,12 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
return;
|
||||
}
|
||||
if( pExpr->flags ){
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x iRJT=%d",
|
||||
pExpr->flags, pExpr->iRightJoinTable);
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
|
||||
}
|
||||
}else{
|
||||
zFlgs[0] = 0;
|
||||
}
|
||||
@@ -465,6 +470,11 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0);
|
||||
break;
|
||||
}
|
||||
case TK_IF_NULL_ROW: {
|
||||
sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
|
||||
break;
|
||||
|
||||
@@ -713,6 +713,7 @@ int sqlite3GetInt32(const char *zNum, int *pValue){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( !sqlite3Isdigit(zNum[0]) ) return 0;
|
||||
while( zNum[0]=='0' ) zNum++;
|
||||
for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
|
||||
v = v*10 + c;
|
||||
|
||||
+73
-23
@@ -486,6 +486,7 @@ static void registerTrace(int iReg, Mem *p){
|
||||
printf("REG[%d] = ", iReg);
|
||||
memTracePrint(p);
|
||||
printf("\n");
|
||||
sqlite3VdbeCheckMemInvariants(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -763,7 +764,7 @@ jump_to_p2_and_check_for_interrupt:
|
||||
pOp = &aOp[pOp->p2 - 1];
|
||||
|
||||
/* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
|
||||
** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon
|
||||
** OP_VNext, or OP_SorterNext) all jump here upon
|
||||
** completion. Check to see if sqlite3_interrupt() has been called
|
||||
** or if the progress callback needs to be invoked.
|
||||
**
|
||||
@@ -1151,7 +1152,7 @@ case OP_Null: { /* out2 */
|
||||
case OP_SoftNull: {
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
|
||||
pOut = &aMem[pOp->p1];
|
||||
pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined;
|
||||
pOut->flags = (pOut->flags&~(MEM_Undefined|MEM_AffMask))|MEM_Null;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1494,7 +1495,6 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
type2 = numericType(pIn2);
|
||||
pOut = &aMem[pOp->p3];
|
||||
flags = pIn1->flags | pIn2->flags;
|
||||
if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
|
||||
if( (type1 & type2 & MEM_Int)!=0 ){
|
||||
iA = pIn1->u.i;
|
||||
iB = pIn2->u.i;
|
||||
@@ -1518,6 +1518,8 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
}
|
||||
pOut->u.i = iB;
|
||||
MemSetTypeFlag(pOut, MEM_Int);
|
||||
}else if( (flags & MEM_Null)!=0 ){
|
||||
goto arithmetic_result_is_null;
|
||||
}else{
|
||||
bIntint = 0;
|
||||
fp_math:
|
||||
@@ -1565,7 +1567,7 @@ arithmetic_result_is_null:
|
||||
|
||||
/* Opcode: CollSeq P1 * * P4
|
||||
**
|
||||
** P4 is a pointer to a CollSeq struct. If the next call to a user function
|
||||
** P4 is a pointer to a CollSeq object. If the next call to a user function
|
||||
** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
|
||||
** be returned. This is used by the built-in min(), max() and nullif()
|
||||
** functions.
|
||||
@@ -1846,11 +1848,11 @@ case OP_RealAffinity: { /* in1 */
|
||||
** Force the value in register P1 to be the type defined by P2.
|
||||
**
|
||||
** <ul>
|
||||
** <li value="97"> TEXT
|
||||
** <li value="98"> BLOB
|
||||
** <li value="99"> NUMERIC
|
||||
** <li value="100"> INTEGER
|
||||
** <li value="101"> REAL
|
||||
** <li> P2=='A' → BLOB
|
||||
** <li> P2=='B' → TEXT
|
||||
** <li> P2=='C' → NUMERIC
|
||||
** <li> P2=='D' → INTEGER
|
||||
** <li> P2=='E' → REAL
|
||||
** </ul>
|
||||
**
|
||||
** A NULL value is not changed by this routine. It remains NULL.
|
||||
@@ -2429,6 +2431,23 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IfNullRow P1 P2 P3 * *
|
||||
** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2
|
||||
**
|
||||
** Check the cursor P1 to see if it is currently pointing at a NULL row.
|
||||
** If it is, then set register P3 to NULL and jump immediately to P2.
|
||||
** If P1 is not on a NULL row, then fall through without making any
|
||||
** changes.
|
||||
*/
|
||||
case OP_IfNullRow: { /* jump */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
if( p->apCsr[pOp->p1]->nullRow ){
|
||||
sqlite3VdbeMemSetNull(aMem + pOp->p3);
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Column P1 P2 P3 P4 P5
|
||||
** Synopsis: r[P3]=PX
|
||||
**
|
||||
@@ -2704,8 +2723,8 @@ op_column_out:
|
||||
**
|
||||
** Apply affinities to a range of P2 registers starting with P1.
|
||||
**
|
||||
** P4 is a string that is P2 characters long. The nth character of the
|
||||
** string indicates the column affinity that should be used for the nth
|
||||
** P4 is a string that is P2 characters long. The N-th character of the
|
||||
** string indicates the column affinity that should be used for the N-th
|
||||
** memory cell in the range.
|
||||
*/
|
||||
case OP_Affinity: {
|
||||
@@ -2732,8 +2751,8 @@ case OP_Affinity: {
|
||||
** use as a data record in a database table or as a key
|
||||
** in an index. The OP_Column opcode can decode the record later.
|
||||
**
|
||||
** P4 may be a string that is P2 characters long. The nth character of the
|
||||
** string indicates the column affinity that should be used for the nth
|
||||
** P4 may be a string that is P2 characters long. The N-th character of the
|
||||
** string indicates the column affinity that should be used for the N-th
|
||||
** field of the index key.
|
||||
**
|
||||
** The mapping from character to affinity is given by the SQLITE_AFF_
|
||||
@@ -3521,6 +3540,37 @@ open_cursor_set_hints:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: OpenDup P1 P2 * * *
|
||||
**
|
||||
** Open a new cursor P1 that points to the same ephemeral table as
|
||||
** cursor P2. The P2 cursor must have been opened by a prior OP_OpenEphemeral
|
||||
** opcode. Only ephemeral cursors may be duplicated.
|
||||
**
|
||||
** Duplicate ephemeral cursors are used for self-joins of materialized views.
|
||||
*/
|
||||
case OP_OpenDup: {
|
||||
VdbeCursor *pOrig; /* The original cursor to be duplicated */
|
||||
VdbeCursor *pCx; /* The new cursor */
|
||||
|
||||
pOrig = p->apCsr[pOp->p2];
|
||||
assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */
|
||||
|
||||
pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
pCx->isEphemeral = 1;
|
||||
pCx->pKeyInfo = pOrig->pKeyInfo;
|
||||
pCx->isTable = pOrig->isTable;
|
||||
rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR,
|
||||
pCx->pKeyInfo, pCx->uc.pCursor);
|
||||
/* The sqlite3BtreeCursor() routine can only fail for the first cursor
|
||||
** opened for a database. Since there is already an open cursor when this
|
||||
** opcode is run, the sqlite3BtreeCursor() cannot fail */
|
||||
assert( rc==SQLITE_OK );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Opcode: OpenEphemeral P1 P2 * P4 P5
|
||||
** Synopsis: nColumn=P2
|
||||
**
|
||||
@@ -5729,7 +5779,7 @@ case OP_IntegrityCk: {
|
||||
/* Opcode: RowSetAdd P1 P2 * * *
|
||||
** Synopsis: rowset(P1)=r[P2]
|
||||
**
|
||||
** Insert the integer value held by register P2 into a boolean index
|
||||
** Insert the integer value held by register P2 into a RowSet object
|
||||
** held in register P1.
|
||||
**
|
||||
** An assertion fails if P2 is not an integer.
|
||||
@@ -5749,8 +5799,9 @@ case OP_RowSetAdd: { /* in1, in2 */
|
||||
/* Opcode: RowSetRead P1 P2 P3 * *
|
||||
** Synopsis: r[P3]=rowset(P1)
|
||||
**
|
||||
** Extract the smallest value from boolean index P1 and put that value into
|
||||
** register P3. Or, if boolean index P1 is initially empty, leave P3
|
||||
** Extract the smallest value from the RowSet object in P1
|
||||
** and put that value into register P3.
|
||||
** Or, if RowSet object P1 is initially empty, leave P3
|
||||
** unchanged and jump to instruction P2.
|
||||
*/
|
||||
case OP_RowSetRead: { /* jump, in1, out3 */
|
||||
@@ -5781,15 +5832,14 @@ case OP_RowSetRead: { /* jump, in1, out3 */
|
||||
** integer in P3 into the RowSet and continue on to the
|
||||
** next opcode.
|
||||
**
|
||||
** The RowSet object is optimized for the case where successive sets
|
||||
** of integers, where each set contains no duplicates. Each set
|
||||
** of values is identified by a unique P4 value. The first set
|
||||
** must have P4==0, the final set P4=-1. P4 must be either -1 or
|
||||
** non-negative. For non-negative values of P4 only the lower 4
|
||||
** bits are significant.
|
||||
** The RowSet object is optimized for the case where sets of integers
|
||||
** are inserted in distinct phases, which each set contains no duplicates.
|
||||
** Each set is identified by a unique P4 value. The first set
|
||||
** must have P4==0, the final set must have P4==-1, and for all other sets
|
||||
** must have P4>0.
|
||||
**
|
||||
** This allows optimizations: (a) when P4==0 there is no need to test
|
||||
** the rowset object for P3, as it is guaranteed not to contain it,
|
||||
** the RowSet object for P3, as it is guaranteed not to contain it,
|
||||
** (b) when P4==-1 there is no need to insert the value, as it will
|
||||
** never be tested for, and (c) when a value that is part of set X is
|
||||
** inserted, there is no need to search to see if the same value was
|
||||
|
||||
+4
-4
@@ -287,11 +287,11 @@ struct sqlite3_value {
|
||||
** when the VM is halted (if not before).
|
||||
*/
|
||||
struct AuxData {
|
||||
int iOp; /* Instruction number of OP_Function opcode */
|
||||
int iArg; /* Index of function argument. */
|
||||
int iAuxOp; /* Instruction number of OP_Function opcode */
|
||||
int iAuxArg; /* Index of function argument. */
|
||||
void *pAux; /* Aux data pointer */
|
||||
void (*xDelete)(void *); /* Destructor for the aux data */
|
||||
AuxData *pNext; /* Next element in list */
|
||||
void (*xDeleteAux)(void*); /* Destructor for the aux data */
|
||||
AuxData *pNextAux; /* Next element in list */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+27
-13
@@ -804,6 +804,12 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
|
||||
/*
|
||||
** Return the auxiliary data pointer, if any, for the iArg'th argument to
|
||||
** the user-function defined by pCtx.
|
||||
**
|
||||
** The left-most argument is 0.
|
||||
**
|
||||
** Undocumented behavior: If iArg is negative then access a cache of
|
||||
** auxiliary data pointers that is available to all functions within a
|
||||
** single prepared statement. The iArg values must match.
|
||||
*/
|
||||
void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
|
||||
AuxData *pAuxData;
|
||||
@@ -814,17 +820,24 @@ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
|
||||
#else
|
||||
assert( pCtx->pVdbe!=0 );
|
||||
#endif
|
||||
for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
|
||||
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
|
||||
for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
|
||||
if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
|
||||
return pAuxData->pAux;
|
||||
}
|
||||
}
|
||||
|
||||
return (pAuxData ? pAuxData->pAux : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the auxiliary data pointer and delete function, for the iArg'th
|
||||
** argument to the user-function defined by pCtx. Any previous value is
|
||||
** deleted by calling the delete function specified when it was set.
|
||||
**
|
||||
** The left-most argument is 0.
|
||||
**
|
||||
** Undocumented behavior: If iArg is negative then make the data available
|
||||
** to all functions within the current prepared statement using iArg as an
|
||||
** access code.
|
||||
*/
|
||||
void sqlite3_set_auxdata(
|
||||
sqlite3_context *pCtx,
|
||||
@@ -836,33 +849,34 @@ void sqlite3_set_auxdata(
|
||||
Vdbe *pVdbe = pCtx->pVdbe;
|
||||
|
||||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
if( iArg<0 ) goto failed;
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( pVdbe==0 ) goto failed;
|
||||
#else
|
||||
assert( pVdbe!=0 );
|
||||
#endif
|
||||
|
||||
for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
|
||||
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
|
||||
for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
|
||||
if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( pAuxData==0 ){
|
||||
pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
|
||||
if( !pAuxData ) goto failed;
|
||||
pAuxData->iOp = pCtx->iOp;
|
||||
pAuxData->iArg = iArg;
|
||||
pAuxData->pNext = pVdbe->pAuxData;
|
||||
pAuxData->iAuxOp = pCtx->iOp;
|
||||
pAuxData->iAuxArg = iArg;
|
||||
pAuxData->pNextAux = pVdbe->pAuxData;
|
||||
pVdbe->pAuxData = pAuxData;
|
||||
if( pCtx->fErrorOrAux==0 ){
|
||||
pCtx->isError = 0;
|
||||
pCtx->fErrorOrAux = 1;
|
||||
}
|
||||
}else if( pAuxData->xDelete ){
|
||||
pAuxData->xDelete(pAuxData->pAux);
|
||||
}else if( pAuxData->xDeleteAux ){
|
||||
pAuxData->xDeleteAux(pAuxData->pAux);
|
||||
}
|
||||
|
||||
pAuxData->pAux = pAux;
|
||||
pAuxData->xDelete = xDelete;
|
||||
pAuxData->xDeleteAux = xDelete;
|
||||
return;
|
||||
|
||||
failed:
|
||||
|
||||
+10
-8
@@ -2035,8 +2035,8 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
break;
|
||||
}
|
||||
case CURTYPE_BTREE: {
|
||||
if( pCx->pBtx ){
|
||||
sqlite3BtreeClose(pCx->pBtx);
|
||||
if( pCx->isEphemeral ){
|
||||
if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx);
|
||||
/* The pCx->pCursor will be close automatically, if it exists, by
|
||||
** the call above. */
|
||||
}else{
|
||||
@@ -2968,16 +2968,18 @@ void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){
|
||||
while( *pp ){
|
||||
AuxData *pAux = *pp;
|
||||
if( (iOp<0)
|
||||
|| (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg))))
|
||||
|| (pAux->iAuxOp==iOp
|
||||
&& pAux->iAuxArg>=0
|
||||
&& (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg))))
|
||||
){
|
||||
testcase( pAux->iArg==31 );
|
||||
if( pAux->xDelete ){
|
||||
pAux->xDelete(pAux->pAux);
|
||||
testcase( pAux->iAuxArg==31 );
|
||||
if( pAux->xDeleteAux ){
|
||||
pAux->xDeleteAux(pAux->pAux);
|
||||
}
|
||||
*pp = pAux->pNext;
|
||||
*pp = pAux->pNextAux;
|
||||
sqlite3DbFree(db, pAux);
|
||||
}else{
|
||||
pp= &pAux->pNext;
|
||||
pp= &pAux->pNextAux;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,10 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
|
||||
/* Cannot be both MEM_Int and MEM_Real at the same time */
|
||||
assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
|
||||
|
||||
/* Cannot be both MEM_Null and some other type */
|
||||
assert( (p->flags & MEM_Null)==0 ||
|
||||
(p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob))==0 );
|
||||
|
||||
/* The szMalloc field holds the correct memory allocation size */
|
||||
assert( p->szMalloc==0
|
||||
|| p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) );
|
||||
|
||||
+1
-1
@@ -1053,7 +1053,7 @@ FuncDef *sqlite3VtabOverloadFunction(
|
||||
if( NEVER(pExpr==0) ) return pDef;
|
||||
if( pExpr->op!=TK_COLUMN ) return pDef;
|
||||
pTab = pExpr->pTab;
|
||||
if( NEVER(pTab==0) ) return pDef;
|
||||
if( pTab==0 ) return pDef;
|
||||
if( !IsVirtual(pTab) ) return pDef;
|
||||
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
|
||||
assert( pVtab!=0 );
|
||||
|
||||
@@ -5009,6 +5009,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
}else if( pOp->opcode==OP_Rowid ){
|
||||
pOp->p1 = pLevel->iIdxCur;
|
||||
pOp->opcode = OP_IdxRowid;
|
||||
}else if( pOp->opcode==OP_IfNullRow ){
|
||||
pOp->p1 = pLevel->iIdxCur;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+48
-33
@@ -1129,6 +1129,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
int addrCont; /* Jump here to continue with next cycle */
|
||||
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
|
||||
int iReleaseReg = 0; /* Temp register to free before returning */
|
||||
Index *pIdx = 0; /* Index used by loop (if any) */
|
||||
int loopAgain; /* True if constraint generator loop should repeat */
|
||||
|
||||
pParse = pWInfo->pParse;
|
||||
v = pParse->pVdbe;
|
||||
@@ -1454,7 +1456,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
int endEq; /* True if range end uses ==, >= or <= */
|
||||
int start_constraints; /* Start of range is constrained */
|
||||
int nConstraint; /* Number of constraint terms */
|
||||
Index *pIdx; /* The index we will be using */
|
||||
int iIdxCur; /* The VDBE cursor for the index */
|
||||
int nExtraReg = 0; /* Number of extra registers needed */
|
||||
int op; /* Instruction opcode */
|
||||
@@ -1705,6 +1706,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
}else{
|
||||
assert( pLevel->p5==0 );
|
||||
}
|
||||
if( omitTable ) pIdx = 0;
|
||||
}else
|
||||
|
||||
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
|
||||
@@ -2022,43 +2024,56 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
|
||||
/* Insert code to test every subexpression that can be completely
|
||||
** computed using the current set of tables.
|
||||
**
|
||||
** This loop may run either once (pIdx==0) or twice (pIdx!=0). If
|
||||
** it is run twice, then the first iteration codes those sub-expressions
|
||||
** that can be computed using columns from pIdx only (without seeking
|
||||
** the main table cursor).
|
||||
*/
|
||||
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
||||
Expr *pE;
|
||||
int skipLikeAddr = 0;
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
|
||||
testcase( pWInfo->untestedTerms==0
|
||||
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
|
||||
pWInfo->untestedTerms = 1;
|
||||
continue;
|
||||
}
|
||||
pE = pTerm->pExpr;
|
||||
assert( pE!=0 );
|
||||
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
||||
continue;
|
||||
}
|
||||
if( pTerm->wtFlags & TERM_LIKECOND ){
|
||||
/* If the TERM_LIKECOND flag is set, that means that the range search
|
||||
** is sufficient to guarantee that the LIKE operator is true, so we
|
||||
** can skip the call to the like(A,B) function. But this only works
|
||||
** for strings. So do not skip the call to the function on the pass
|
||||
** that compares BLOBs. */
|
||||
do{
|
||||
loopAgain = 0;
|
||||
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
||||
Expr *pE;
|
||||
int skipLikeAddr = 0;
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
|
||||
testcase( pWInfo->untestedTerms==0
|
||||
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
|
||||
pWInfo->untestedTerms = 1;
|
||||
continue;
|
||||
}
|
||||
pE = pTerm->pExpr;
|
||||
assert( pE!=0 );
|
||||
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
||||
continue;
|
||||
}
|
||||
if( pIdx && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
|
||||
loopAgain = 1;
|
||||
continue;
|
||||
}
|
||||
if( pTerm->wtFlags & TERM_LIKECOND ){
|
||||
/* If the TERM_LIKECOND flag is set, that means that the range search
|
||||
** is sufficient to guarantee that the LIKE operator is true, so we
|
||||
** can skip the call to the like(A,B) function. But this only works
|
||||
** for strings. So do not skip the call to the function on the pass
|
||||
** that compares BLOBs. */
|
||||
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||
continue;
|
||||
continue;
|
||||
#else
|
||||
u32 x = pLevel->iLikeRepCntr;
|
||||
assert( x>0 );
|
||||
skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1));
|
||||
VdbeCoverage(v);
|
||||
u32 x = pLevel->iLikeRepCntr;
|
||||
assert( x>0 );
|
||||
skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If, (int)(x>>1));
|
||||
VdbeCoverage(v);
|
||||
#endif
|
||||
}
|
||||
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
|
||||
if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
}
|
||||
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
|
||||
if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
}
|
||||
pIdx = 0;
|
||||
}while( loopAgain );
|
||||
|
||||
/* Insert code to test for implied constraints based on transitivity
|
||||
** of the "==" operator.
|
||||
|
||||
@@ -36,12 +36,20 @@ proc_real proc {name arguments script} {
|
||||
do_test auth-1.1.1 {
|
||||
db close
|
||||
set ::DB [sqlite3 db test.db]
|
||||
proc authx {code arg1 arg2 arg3 arg4 args} {return SQLITE_DENY}
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
|
||||
return SQLITE_DENY
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
db authorizer ::authx
|
||||
# EVIDENCE-OF: R-03993-24285 Only a single authorizer can be in place on
|
||||
# a database connection at a time. Each call to sqlite3_set_authorizer
|
||||
# overrides the previous call.
|
||||
#
|
||||
# The authx authorizer above is overridden by the auth authorizer below
|
||||
# authx is never invoked.
|
||||
db authorizer ::auth
|
||||
catchsql {CREATE TABLE t1(a,b,c)}
|
||||
} {1 {not authorized}}
|
||||
@@ -60,6 +68,9 @@ do_test auth-1.1.4 {
|
||||
do_test auth-1.2 {
|
||||
execsql {SELECT name FROM sqlite_master}
|
||||
} {}
|
||||
# EVIDENCE-OF: R-04452-49349 When the callback returns SQLITE_DENY, the
|
||||
# sqlite3_prepare_v2() or equivalent call that triggered the authorizer
|
||||
# will fail with an error message explaining that access is denied.
|
||||
do_test auth-1.3.1 {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_CREATE_TABLE"} {
|
||||
@@ -312,6 +323,10 @@ ifcapable attach {
|
||||
} {1 {access to two.t2.b is prohibited}}
|
||||
execsql {DETACH DATABASE two}
|
||||
}
|
||||
# EVIDENCE-OF: R-38392-49970 If the action code is SQLITE_READ and the
|
||||
# callback returns SQLITE_IGNORE then the prepared statement statement
|
||||
# is constructed to substitute a NULL value in place of the table column
|
||||
# that would have been read if SQLITE_OK had been returned.
|
||||
do_test auth-1.36 {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
|
||||
@@ -1606,6 +1621,8 @@ do_test auth-1.248 {
|
||||
set ::authargs
|
||||
} {COMMIT {} {} {}}
|
||||
do_test auth-1.249 {
|
||||
# EVIDENCE-OF: R-52112-44167 Disable the authorizer by installing a NULL
|
||||
# callback.
|
||||
db authorizer {}
|
||||
catchsql {ROLLBACK}
|
||||
} {0 {}}
|
||||
@@ -2478,6 +2495,57 @@ do_test auth-7.4 {
|
||||
SQLITE_READ t7 c main {} \
|
||||
]
|
||||
|
||||
# If a table is referenced but no columns are read from the table,
|
||||
# that causes a single SQLITE_READ authorization with a NULL column
|
||||
# name.
|
||||
#
|
||||
# EVIDENCE-OF: R-31520-16302 When a table is referenced by a SELECT but
|
||||
# no column values are extracted from that table (for example in a query
|
||||
# like "SELECT count(*) FROM tab") then the SQLITE_READ authorizer
|
||||
# callback is invoked once for that table with a column name that is an
|
||||
# empty string.
|
||||
#
|
||||
set ::authargs [list]
|
||||
do_test auth-8.1 {
|
||||
execsql {SELECT count(*) FROM t7}
|
||||
set ::authargs
|
||||
} [list \
|
||||
SQLITE_SELECT {} {} {} {} \
|
||||
SQLITE_FUNCTION {} count {} {} \
|
||||
SQLITE_READ t7 {} {} {} \
|
||||
]
|
||||
set ::authargs [list]
|
||||
|
||||
do_test auth-8.2 {
|
||||
execsql {SELECT t6.a FROM t6, t7}
|
||||
set ::authargs
|
||||
} [list \
|
||||
SQLITE_SELECT {} {} {} {} \
|
||||
SQLITE_READ t6 a main {} \
|
||||
SQLITE_READ t7 {} {} {} \
|
||||
]
|
||||
|
||||
# Test also that if SQLITE_DENY is returned from an SQLITE_READ authorizer
|
||||
# invocation with no column name specified, compilation fails.
|
||||
#
|
||||
set ::authargs [list]
|
||||
proc auth {op a b c d} {
|
||||
lappend ::authargs $op $a $b $c $d
|
||||
if {$op == "SQLITE_READ"} { return "SQLITE_DENY" }
|
||||
return "SQLITE_OK"
|
||||
}
|
||||
set ::authargs [list]
|
||||
do_catchsql_test auth-8.3 {
|
||||
SELECT count(*) FROM t7
|
||||
} {1 {not authorized}}
|
||||
do_test auth-8.4 {
|
||||
set ::authargs
|
||||
} [list \
|
||||
SQLITE_SELECT {} {} {} {} \
|
||||
SQLITE_FUNCTION {} count {} {} \
|
||||
SQLITE_READ t7 {} {} {} \
|
||||
]
|
||||
|
||||
|
||||
rename proc {}
|
||||
rename proc_real proc
|
||||
|
||||
@@ -53,6 +53,10 @@ do_test auth3.1.2 {
|
||||
set ::authcode SQLITE_DENY
|
||||
catchsql { DELETE FROM t1 }
|
||||
} {1 {not authorized}}
|
||||
# EVIDENCE-OF: R-64962-58611 If the authorizer callback returns any
|
||||
# value other than SQLITE_IGNORE, SQLITE_OK, or SQLITE_DENY then the
|
||||
# sqlite3_prepare_v2() or equivalent call that triggered the authorizer
|
||||
# will fail with an error message.
|
||||
do_test auth3.1.3 {
|
||||
set ::authcode SQLITE_INVALID
|
||||
catchsql { DELETE FROM t1 }
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# 2017 April 26
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix cachespill
|
||||
|
||||
ifcapable !pager_pragmas {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that "PRAGMA cache_spill = 0" completely disables cache spilling.
|
||||
#
|
||||
do_execsql_test 1.1 {
|
||||
PRAGMA auto_vacuum = 0;
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA cache_size = 100;
|
||||
CREATE TABLE t1(a);
|
||||
}
|
||||
|
||||
do_test 1.2 {
|
||||
file size test.db
|
||||
} {2048}
|
||||
|
||||
do_test 1.3 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<200
|
||||
) INSERT INTO t1 SELECT randomblob(900) FROM s;
|
||||
}
|
||||
expr {[file size test.db] > 50000}
|
||||
} {1}
|
||||
|
||||
do_test 1.4 {
|
||||
execsql ROLLBACK
|
||||
file size test.db
|
||||
} {2048}
|
||||
|
||||
do_test 1.5 {
|
||||
execsql {
|
||||
PRAGMA cache_spill = 0;
|
||||
BEGIN;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<200
|
||||
) INSERT INTO t1 SELECT randomblob(900) FROM s;
|
||||
}
|
||||
file size test.db
|
||||
} {2048}
|
||||
|
||||
do_test 1.5 {
|
||||
execsql {
|
||||
ROLLBACK;
|
||||
PRAGMA cache_spill = 1;
|
||||
BEGIN;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<200
|
||||
) INSERT INTO t1 SELECT randomblob(900) FROM s;
|
||||
}
|
||||
expr {[file size test.db] > 50000}
|
||||
} {1}
|
||||
|
||||
do_execsql_test 1.6 { ROLLBACK }
|
||||
|
||||
|
||||
finish_test
|
||||
+58
-44
@@ -19,13 +19,14 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix conflict3
|
||||
|
||||
ifcapable !conflict {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test conflict-1.1 {
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(
|
||||
a INTEGER PRIMARY KEY ON CONFLICT REPLACE,
|
||||
b UNIQUE ON CONFLICT IGNORE,
|
||||
@@ -37,7 +38,7 @@ do_execsql_test conflict-1.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-1.2 {
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -45,16 +46,16 @@ do_execsql_test conflict-1.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-1.3 {
|
||||
do_test 1.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-1.4 {
|
||||
do_execsql_test 1.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Replete the tests above, but this time on a table non-INTEGER primary key.
|
||||
#
|
||||
do_execsql_test conflict-2.1 {
|
||||
do_execsql_test 2.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a INT PRIMARY KEY ON CONFLICT REPLACE,
|
||||
@@ -67,7 +68,7 @@ do_execsql_test conflict-2.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-2.2 {
|
||||
do_execsql_test 2.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -75,16 +76,16 @@ do_execsql_test conflict-2.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-2.3 {
|
||||
do_test 2.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-2.4 {
|
||||
do_execsql_test 2.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Replete again on a WITHOUT ROWID table.
|
||||
#
|
||||
do_execsql_test conflict-3.1 {
|
||||
do_execsql_test 3.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a INT PRIMARY KEY ON CONFLICT REPLACE,
|
||||
@@ -97,7 +98,7 @@ do_execsql_test conflict-3.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-3.2 {
|
||||
do_execsql_test 3.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -105,16 +106,16 @@ do_execsql_test conflict-3.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-3.3 {
|
||||
do_test 3.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-3.4 {
|
||||
do_execsql_test 3.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Arrange the table rows in a different order and repeat.
|
||||
#
|
||||
do_execsql_test conflict-4.1 {
|
||||
do_execsql_test 4.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
b UNIQUE ON CONFLICT IGNORE,
|
||||
@@ -127,7 +128,7 @@ do_execsql_test conflict-4.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-4.2 {
|
||||
do_execsql_test 4.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -135,16 +136,16 @@ do_execsql_test conflict-4.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-4.3 {
|
||||
do_test 4.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-4.4 {
|
||||
do_execsql_test 4.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Arrange the table rows in a different order and repeat.
|
||||
#
|
||||
do_execsql_test conflict-5.1 {
|
||||
do_execsql_test 5.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
b UNIQUE ON CONFLICT IGNORE,
|
||||
@@ -157,7 +158,7 @@ do_execsql_test conflict-5.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-5.2 {
|
||||
do_execsql_test 5.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -165,16 +166,16 @@ do_execsql_test conflict-5.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-5.3 {
|
||||
do_test 5.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-5.4 {
|
||||
do_execsql_test 5.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Arrange the table rows in a different order and repeat.
|
||||
#
|
||||
do_execsql_test conflict-6.1 {
|
||||
do_execsql_test 6.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
c UNIQUE ON CONFLICT FAIL,
|
||||
@@ -187,7 +188,7 @@ do_execsql_test conflict-6.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-6.2 {
|
||||
do_execsql_test 6.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -195,16 +196,16 @@ do_execsql_test conflict-6.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-6.3 {
|
||||
do_test 6.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-6.4 {
|
||||
do_execsql_test 6.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Change which column is the PRIMARY KEY
|
||||
#
|
||||
do_execsql_test conflict-7.1 {
|
||||
do_execsql_test 7.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a UNIQUE ON CONFLICT REPLACE,
|
||||
@@ -217,7 +218,7 @@ do_execsql_test conflict-7.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-7.2 {
|
||||
do_execsql_test 7.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -225,16 +226,16 @@ do_execsql_test conflict-7.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-7.3 {
|
||||
do_test 7.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-7.4 {
|
||||
do_execsql_test 7.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Change which column is the PRIMARY KEY
|
||||
#
|
||||
do_execsql_test conflict-8.1 {
|
||||
do_execsql_test 8.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a UNIQUE ON CONFLICT REPLACE,
|
||||
@@ -247,7 +248,7 @@ do_execsql_test conflict-8.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-8.2 {
|
||||
do_execsql_test 8.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -255,16 +256,16 @@ do_execsql_test conflict-8.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-8.3 {
|
||||
do_test 8.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-8.4 {
|
||||
do_execsql_test 8.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Change which column is the PRIMARY KEY
|
||||
#
|
||||
do_execsql_test conflict-9.1 {
|
||||
do_execsql_test 9.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a UNIQUE ON CONFLICT REPLACE,
|
||||
@@ -277,7 +278,7 @@ do_execsql_test conflict-9.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-9.2 {
|
||||
do_execsql_test 9.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -285,16 +286,16 @@ do_execsql_test conflict-9.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-9.3 {
|
||||
do_test 9.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-9.4 {
|
||||
do_execsql_test 9.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Change which column is the PRIMARY KEY
|
||||
#
|
||||
do_execsql_test conflict-10.1 {
|
||||
do_execsql_test 10.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a UNIQUE ON CONFLICT REPLACE,
|
||||
@@ -307,7 +308,7 @@ do_execsql_test conflict-10.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-10.2 {
|
||||
do_execsql_test 10.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -315,16 +316,16 @@ do_execsql_test conflict-10.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-10.3 {
|
||||
do_test 10.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-10.4 {
|
||||
do_execsql_test 10.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Change which column is the PRIMARY KEY
|
||||
#
|
||||
do_execsql_test conflict-11.1 {
|
||||
do_execsql_test 11.1 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
a UNIQUE ON CONFLICT REPLACE,
|
||||
@@ -337,7 +338,7 @@ do_execsql_test conflict-11.1 {
|
||||
|
||||
# Insert a row that conflicts on column B. The insert should be ignored.
|
||||
#
|
||||
do_execsql_test conflict-11.2 {
|
||||
do_execsql_test 11.2 {
|
||||
INSERT INTO t1(a,b,c) VALUES(3,2,5);
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4}
|
||||
@@ -345,12 +346,25 @@ do_execsql_test conflict-11.2 {
|
||||
# Insert two rows where the second conflicts on C. The first row show go
|
||||
# and and then there should be a constraint error.
|
||||
#
|
||||
do_test conflict-11.3 {
|
||||
do_test 11.3 {
|
||||
catchsql {INSERT INTO t1(a,b,c) VALUES(4,5,6), (5,6,4);}
|
||||
} {1 {UNIQUE constraint failed: t1.c}}
|
||||
do_execsql_test conflict-11.4 {
|
||||
do_execsql_test 11.4 {
|
||||
SELECT a,b,c FROM t1 ORDER BY a;
|
||||
} {1 2 3 2 3 4 4 5 6}
|
||||
|
||||
# Check that ticket [f68dc596c4] has been fixed.
|
||||
#
|
||||
do_execsql_test 12.1 {
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b TEXT);
|
||||
INSERT INTO t2 VALUES(111, '111');
|
||||
}
|
||||
do_execsql_test 12.2 {
|
||||
REPLACE INTO t2 VALUES(NULL, '112'), (111, '111B');
|
||||
}
|
||||
do_execsql_test 12.3 {
|
||||
SELECT * FROM t2;
|
||||
} {111 111B 112 112}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+43
-2
@@ -115,8 +115,11 @@ do_test fkey5-1.6 {
|
||||
# EVIDENCE-OF: R-55672-01620 The first column is the name of the table
|
||||
# that contains the REFERENCES clause.
|
||||
#
|
||||
# EVIDENCE-OF: R-25219-25618 The second column is the rowid of the row
|
||||
# that contains the invalid REFERENCES clause.
|
||||
# EVIDENCE-OF: R-00471-55166 The second column is the rowid of the row
|
||||
# that contains the invalid REFERENCES clause, or NULL if the child
|
||||
# table is a WITHOUT ROWID table.
|
||||
#
|
||||
# The second clause in the previous is tested by fkey5-10.3.
|
||||
#
|
||||
# EVIDENCE-OF: R-40482-20265 The third column is the name of the table
|
||||
# that is referred to.
|
||||
@@ -388,5 +391,43 @@ do_execsql_test 9.4 {
|
||||
PRAGMA foreign_key_check(k2);
|
||||
} {k2 3 s1 0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test using a WITHOUT ROWID table as the child table with an INTEGER
|
||||
# PRIMARY KEY as the parent key.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 10.1 {
|
||||
CREATE TABLE p30 (id INTEGER PRIMARY KEY);
|
||||
CREATE TABLE IF NOT EXISTS c30 (
|
||||
line INTEGER,
|
||||
master REFERENCES p30(id),
|
||||
PRIMARY KEY(master)
|
||||
) WITHOUT ROWID;
|
||||
|
||||
INSERT INTO p30 (id) VALUES (1);
|
||||
INSERT INTO c30 (master, line) VALUES (1, 999);
|
||||
}
|
||||
do_execsql_test 10.2 {
|
||||
PRAGMA foreign_key_check;
|
||||
}
|
||||
# EVIDENCE-OF: R-00471-55166 The second column is the rowid of the row
|
||||
# that contains the invalid REFERENCES clause, or NULL if the child
|
||||
# table is a WITHOUT ROWID table.
|
||||
do_execsql_test 10.3 {
|
||||
INSERT INTO c30 VALUES(45, 45);
|
||||
PRAGMA foreign_key_check;
|
||||
} {c30 {} p30 0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test "foreign key mismatch" errors.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.0 {
|
||||
CREATE TABLE tt(y);
|
||||
CREATE TABLE c11(x REFERENCES tt(y));
|
||||
}
|
||||
do_catchsql_test 11.1 {
|
||||
PRAGMA foreign_key_check;
|
||||
} {1 {foreign key mismatch - "c11" referencing "tt"}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -243,5 +243,11 @@ do_execsql_test 8.5 {
|
||||
SELECT docid FROM t0 WHERE t0 MATCH '"abc abc"';
|
||||
} {}
|
||||
|
||||
do_execsql_test 9.1 {
|
||||
CREATE VIRTUAL TABLE t9 USING fts4(a, "", '---');
|
||||
}
|
||||
do_execsql_test 9.2 {
|
||||
CREATE VIRTUAL TABLE t10 USING fts3(<, b, c);
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# 2010 October 27
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# Test that the FTS3 extension does not crash when it encounters a
|
||||
# corrupt data structure on disk.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
|
||||
set ::testprefix fts3corrupt3
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that fts3 does not choke on an oversized varint.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA page_size = 512;
|
||||
CREATE VIRTUAL TABLE t1 USING fts3;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('one');
|
||||
INSERT INTO t1 VALUES('one');
|
||||
INSERT INTO t1 VALUES('one');
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 1.1 {
|
||||
SELECT quote(root) from t1_segdir;
|
||||
} {X'00036F6E6509010200010200010200'}
|
||||
do_execsql_test 1.2 {
|
||||
UPDATE t1_segdir SET root = X'00036F6E650EFFFFFFFFFFFFFFFFFFFFFFFF0200';
|
||||
}
|
||||
do_catchsql_test 1.3 {
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH 'one'
|
||||
} {0 -1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Interior node with the prefix or suffix count of an entry set to a
|
||||
# negative value.
|
||||
#
|
||||
set doc1 [string repeat "x " 600]
|
||||
set doc2 [string repeat "y " 600]
|
||||
set doc3 [string repeat "z " 600]
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts3;
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES($doc1);
|
||||
INSERT INTO t2 VALUES($doc2);
|
||||
INSERT INTO t2 VALUES($doc3);
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 2.1 {
|
||||
SELECT quote(root) from t2_segdir;
|
||||
} {X'0101017900017A'}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
+17
-11
@@ -18,8 +18,6 @@ set ::testprefix fts3fault
|
||||
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
|
||||
if 0 {
|
||||
|
||||
# Test error handling in the sqlite3Fts3Init() function. This is the
|
||||
# function that registers the FTS3 module and various support functions
|
||||
# with SQLite.
|
||||
@@ -160,8 +158,6 @@ do_faultsim_test 7.3 -prep {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
proc mit {blob} {
|
||||
set scan(littleEndian) i*
|
||||
set scan(bigEndian) I*
|
||||
@@ -181,13 +177,15 @@ do_test 8.0 {
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
|
||||
do_faultsim_test 8.1 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db func mit mit
|
||||
} -body {
|
||||
execsql { SELECT mit(matchinfo(t8, 'x')) FROM t8 WHERE t8 MATCH 'a b c' }
|
||||
} -test {
|
||||
faultsim_test_result {0 {{1 1 1 1 4 2 1 5 5}}}
|
||||
ifcapable fts4_deferred {
|
||||
do_faultsim_test 8.1 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db func mit mit
|
||||
} -body {
|
||||
execsql { SELECT mit(matchinfo(t8, 'x')) FROM t8 WHERE t8 MATCH 'a b c' }
|
||||
} -test {
|
||||
faultsim_test_result {0 {{1 1 1 1 4 2 1 5 5}}}
|
||||
}
|
||||
}
|
||||
|
||||
do_faultsim_test 8.2 -faults oom-t* -prep {
|
||||
@@ -234,4 +232,12 @@ do_faultsim_test 9.1 -prep {
|
||||
faultsim_test_result {0 {{0 0 20 39 0 0 64 2}}}
|
||||
}
|
||||
|
||||
do_faultsim_test 10.1 -prep {
|
||||
faultsim_delete_and_reopen
|
||||
} -body {
|
||||
execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, languageid=d) }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -174,4 +174,76 @@ do_faultsim_test 6.1 -faults oom* -prep {
|
||||
faultsim_test_result {0 -1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Inject faults into a query for an N-byte prefix that uses a prefix=N+1
|
||||
# index.
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE VIRTUAL TABLE t7 USING fts4(x,prefix=2);
|
||||
INSERT INTO t7 VALUES('the quick brown fox');
|
||||
INSERT INTO t7 VALUES('jumped over the');
|
||||
INSERT INTO t7 VALUES('lazy dog');
|
||||
}
|
||||
do_faultsim_test 7.1 -faults oom* -body {
|
||||
execsql { SELECT docid FROM t7 WHERE t7 MATCH 't*' }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Inject faults into a opening an existing fts3 table that has been
|
||||
# upgraded to add an %_stat table.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.0 {
|
||||
CREATE VIRTUAL TABLE t8 USING fts3;
|
||||
INSERT INTO t8 VALUES('the quick brown fox');
|
||||
INSERT INTO t8 VALUES('jumped over the');
|
||||
INSERT INTO t8 VALUES('lazy dog');
|
||||
INSERT INTO t8(t8) VALUES('automerge=8');
|
||||
SELECT name FROM sqlite_master WHERE name LIKE 't8%';
|
||||
} {
|
||||
t8 t8_content t8_segments t8_segdir t8_stat
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 8.1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { INSERT INTO t8 VALUES('one two three') }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
do_faultsim_test 8.2 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { ALTER TABLE t8 RENAME TO t8ii }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
set chunkconfig [fts3_configure_incr_load 1 1]
|
||||
do_execsql_test 9.0 {
|
||||
PRAGMA page_size = 512;
|
||||
CREATE VIRTUAL TABLE t9 USING fts3;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50
|
||||
)
|
||||
INSERT INTO t9 SELECT 'one two three' FROM s;
|
||||
}
|
||||
|
||||
do_faultsim_test 8.2 -faults io* -body {
|
||||
execsql { SELECT count(*) FROM t9 WHERE t9 MATCH '"one two three"' }
|
||||
} -test {
|
||||
faultsim_test_result {0 50}
|
||||
}
|
||||
|
||||
eval fts3_configure_incr_load $chunkconfig
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
# 2017 March 22
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS3 module.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix fts3misc
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# A self-join.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts3(a, b);
|
||||
INSERT INTO t1 VALUES('one', 'i');
|
||||
INSERT INTO t1 VALUES('one', 'ii');
|
||||
INSERT INTO t1 VALUES('two', 'i');
|
||||
INSERT INTO t1 VALUES('two', 'ii');
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT a.a, b.b FROM t1 a, t1 b WHERE a.t1 MATCH 'two' AND b.t1 MATCH 'i'
|
||||
} {two i two i two i two i}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# FTS tables with 128 or more columns.
|
||||
#
|
||||
proc v1 {v} {
|
||||
set vector [list a b c d e f g h]
|
||||
set res [list]
|
||||
for {set i 0} {$i<8} {incr i} {
|
||||
if {$v & (1 << $i)} { lappend res [lindex $vector $i] }
|
||||
}
|
||||
set res
|
||||
}
|
||||
proc v2 {v} {
|
||||
set vector [list d e f g h i j k]
|
||||
set res [list]
|
||||
for {set i 0} {$i<8} {incr i} {
|
||||
if {$v & (1 << $i)} { lappend res [lindex $vector $i] }
|
||||
}
|
||||
set res
|
||||
}
|
||||
db func v1 v1
|
||||
db func v2 v2
|
||||
|
||||
do_test 2.0 {
|
||||
set cols [list]
|
||||
for {set i 0} {$i<200} {incr i} {
|
||||
lappend cols "c$i"
|
||||
}
|
||||
execsql "CREATE VIRTUAL TABLE t2 USING fts3([join $cols ,])"
|
||||
execsql {
|
||||
WITH data(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM data WHERE i<200
|
||||
)
|
||||
INSERT INTO t2(c198, c199) SELECT v1(i), v2(i) FROM data;
|
||||
}
|
||||
} {}
|
||||
do_execsql_test 2.1 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH '"a b c"'
|
||||
} {
|
||||
7 15 23 31 39 47 55 63 71 79 87 95 103 111
|
||||
119 127 135 143 151 159 167 175 183 191 199
|
||||
}
|
||||
do_execsql_test 2.2 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH '"g h i"'
|
||||
} {
|
||||
56 57 58 59 60 61 62 63 120 121 122 123 124
|
||||
125 126 127 184 185 186 187 188 189 190 191
|
||||
}
|
||||
do_execsql_test 2.3 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH '"i h"'
|
||||
} {
|
||||
}
|
||||
do_execsql_test 2.4 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH '"f e"'
|
||||
} {
|
||||
}
|
||||
do_execsql_test 2.5 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH '"e f"'
|
||||
} {
|
||||
6 7 14 15 22 23 30 31 38 39 46 47 48 49 50 51 52 53 54 55 56
|
||||
57 58 59 60 61 62 63 70 71 78 79 86 87 94 95 102 103 110
|
||||
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
||||
134 135 142 143 150 151 158 159 166 167 174 175 176 177 178 179 180
|
||||
181 182 183 184 185 186 187 188 189 190 191 198 199
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Range constraints on the docid using non-integer values.
|
||||
#
|
||||
do_execsql_test 2.6 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'e' AND rowid BETWEEN NULL AND 45;
|
||||
} {}
|
||||
do_execsql_test 2.7 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'e' AND rowid BETWEEN 11.5 AND 48.2;
|
||||
} {
|
||||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
||||
29 30 31 34 35 38 39 42 43 46 47 48
|
||||
}
|
||||
do_execsql_test 2.8 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'e' AND rowid BETWEEN '11.5' AND '48.2';
|
||||
} {
|
||||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
||||
29 30 31 34 35 38 39 42 43 46 47 48
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Phrase query tests.
|
||||
#
|
||||
do_execsql_test 3.1.1 {
|
||||
CREATE VIRTUAL TABLE t3 USING fts3;
|
||||
INSERT INTO t3 VALUES('a b c');
|
||||
INSERT INTO t3 VALUES('d e f');
|
||||
INSERT INTO t3 VALUES('a b d');
|
||||
INSERT INTO t3 VALUES('1 2 3 4 5 6 7 8 9 10 11');
|
||||
}
|
||||
do_execsql_test 3.1.2 {
|
||||
SELECT * FROM t3 WHERE t3 MATCH '"a b x y"' ORDER BY docid DESC
|
||||
}
|
||||
do_execsql_test 3.1.3 {
|
||||
SELECT * FROM t3 WHERE t3 MATCH '"a b c" OR "a b x y"' ORDER BY docid DESC
|
||||
} {{a b c}}
|
||||
do_execsql_test 3.1.4 {
|
||||
SELECT * FROM t3 WHERE t3 MATCH '"a* b* x* a*"'
|
||||
}
|
||||
do_execsql_test 3.1.5 {
|
||||
SELECT rowid FROM t3 WHERE t3 MATCH '"2 3 4 5 6 7 8 9"'
|
||||
} {4}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
ifcapable fts4_deferred {
|
||||
do_execsql_test 4.0 {
|
||||
PRAGMA page_size = 512;
|
||||
CREATE VIRTUAL TABLE t4 USING fts4;
|
||||
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<8000 )
|
||||
INSERT INTO t4 SELECT 'a b c a b c a b c' FROM s;
|
||||
}
|
||||
do_execsql_test 4.1 {
|
||||
SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"'
|
||||
} {8000}
|
||||
do_execsql_test 4.2 {
|
||||
SELECT quote(value) from t4_stat where id=0
|
||||
} {X'C03EC0B204C0A608'}
|
||||
do_execsql_test 4.3 {
|
||||
UPDATE t4_stat SET value = X'C03EC0B204C0A60800' WHERE id=0;
|
||||
}
|
||||
do_catchsql_test 4.4 {
|
||||
SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"'
|
||||
} {1 {database disk image is malformed}}
|
||||
do_execsql_test 4.5 {
|
||||
UPDATE t4_stat SET value = X'00C03EC0B204C0A608' WHERE id=0;
|
||||
}
|
||||
do_catchsql_test 4.6 {
|
||||
SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"'
|
||||
} {1 {database disk image is malformed}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE t5 USING fts4;
|
||||
INSERT INTO t5 VALUES('a x x x x b x x x x c');
|
||||
INSERT INTO t5 VALUES('a x x x x b x x x x c');
|
||||
INSERT INTO t5 VALUES('a x x x x b x x x x c');
|
||||
}
|
||||
do_execsql_test 5.1 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'a NEAR/4 b NEAR/4 c'
|
||||
} {1 2 3}
|
||||
do_execsql_test 5.2 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'a NEAR/3 b NEAR/4 c'
|
||||
} {}
|
||||
do_execsql_test 5.3 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'a NEAR/4 b NEAR/3 c'
|
||||
} {}
|
||||
do_execsql_test 5.4 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'y NEAR/4 b NEAR/4 c'
|
||||
} {}
|
||||
do_execsql_test 5.5 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'x OR a NEAR/3 b NEAR/3 c'
|
||||
} {1 2 3}
|
||||
do_execsql_test 5.5 {
|
||||
SELECT rowid FROM t5 WHERE t5 MATCH 'x OR y NEAR/3 b NEAR/3 c'
|
||||
} {1 2 3}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE t6 USING fts4;
|
||||
|
||||
BEGIN;
|
||||
WITH s(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000)
|
||||
INSERT INTO t6 SELECT 'x x x x x x x x x x x' FROM s;
|
||||
|
||||
INSERT INTO t6 VALUES('x x x x x x x x x x x A');
|
||||
INSERT INTO t6 VALUES('x x x x x x x x x x x B');
|
||||
INSERT INTO t6 VALUES('x x x x x x x x x x x A');
|
||||
INSERT INTO t6 VALUES('x x x x x x x x x x x B');
|
||||
|
||||
WITH s(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000)
|
||||
INSERT INTO t6 SELECT 'x x x x x x x x x x x' FROM s;
|
||||
COMMIT;
|
||||
}
|
||||
breakpoint
|
||||
do_execsql_test 6.1 {
|
||||
SELECT rowid FROM t6 WHERE t6 MATCH 'b OR "x a"'
|
||||
} {50001 50002 50003 50004}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix fts4content
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
||||
ifcapable !fts3 {
|
||||
@@ -341,6 +340,13 @@ do_test_query1 3.3.4 {"zero one" OR "one two"} {
|
||||
or_merge_lists [rowid_list "zero one"] [rowid_list "one two"]
|
||||
}
|
||||
|
||||
do_execsql_test 3.4 {
|
||||
CREATE TABLE t8c(a, b);
|
||||
CREATE VIRTUAL TABLE t8 USING fts4(content=t8c, languageid=langid);
|
||||
INSERT INTO t8(docid, a, b) VALUES(-1, 'one two three', 'x y z');
|
||||
SELECT docid FROM t8 WHERE t8 MATCH 'one x' AND langid=0
|
||||
} {-1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test cases 4.*
|
||||
#
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
# 2017 April 30
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test the HAVING->WHERE optimization.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix having
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t2(c, d);
|
||||
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2);
|
||||
INSERT INTO t1 VALUES(1, 3);
|
||||
INSERT INTO t1 VALUES(2, 4);
|
||||
INSERT INTO t1 VALUES(1, 5);
|
||||
INSERT INTO t1 VALUES(2, 6);
|
||||
} {}
|
||||
|
||||
foreach {tn sql res} {
|
||||
1 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2" {2 12}
|
||||
2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2 AND sum(b)>10" {2 12}
|
||||
3 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING sum(b)>12" {}
|
||||
} {
|
||||
do_execsql_test 1.$tn $sql $res
|
||||
}
|
||||
|
||||
# Run an EXPLAIN command for both SQL statements. Return true if
|
||||
# the outputs are identical, or false otherwise.
|
||||
#
|
||||
proc compare_vdbe {sql1 sql2} {
|
||||
set r1 [list]
|
||||
set r2 [list]
|
||||
db eval "explain $sql1" { lappend r1 $opcode $p1 $p2 $p3 $p4 $p5}
|
||||
db eval "explain $sql2" { lappend r2 $opcode $p1 $p2 $p3 $p4 $p5}
|
||||
return [expr {$r1==$r2}]
|
||||
}
|
||||
|
||||
proc do_compare_vdbe_test {tn sql1 sql2 res} {
|
||||
uplevel [list do_test $tn [list compare_vdbe $sql1 $sql2] $res]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that various statements that are eligible for the optimization
|
||||
# produce the same VDBE code as optimizing by hand does.
|
||||
#
|
||||
foreach {tn sql1 sql2} {
|
||||
1 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2"
|
||||
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a"
|
||||
|
||||
2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING sum(b)>5 AND a=2"
|
||||
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a HAVING sum(b)>5"
|
||||
|
||||
3 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING a=2"
|
||||
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE binary"
|
||||
|
||||
4 {
|
||||
SELECT x,y FROM (
|
||||
SELECT a AS x, sum(b) AS y FROM t1
|
||||
GROUP BY a
|
||||
) WHERE x BETWEEN 8888 AND 9999
|
||||
} {
|
||||
SELECT x,y FROM (
|
||||
SELECT a AS x, sum(b) AS y FROM t1
|
||||
WHERE x BETWEEN 8888 AND 9999
|
||||
GROUP BY a
|
||||
)
|
||||
}
|
||||
|
||||
5 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING 0"
|
||||
"SELECT a, sum(b) FROM t1 WHERE 0 GROUP BY a COLLATE binary"
|
||||
|
||||
6 "SELECT count(*) FROM t1,t2 WHERE a=c GROUP BY b, d HAVING b=d"
|
||||
"SELECT count(*) FROM t1,t2 WHERE a=c AND b=d GROUP BY b, d"
|
||||
|
||||
7 {
|
||||
SELECT count(*) FROM t1,t2 WHERE a=c GROUP BY b, d
|
||||
HAVING b=d COLLATE nocase
|
||||
} {
|
||||
SELECT count(*) FROM t1,t2 WHERE a=c AND b=d COLLATE nocase
|
||||
GROUP BY b, d
|
||||
}
|
||||
|
||||
8 "SELECT a, sum(b) FROM t1 GROUP BY a||b HAVING substr(a||b, 1, 1)='a'"
|
||||
"SELECT a, sum(b) FROM t1 WHERE substr(a||b, 1, 1)='a' GROUP BY a||b"
|
||||
} {
|
||||
do_compare_vdbe_test 2.$tn $sql1 $sql2 1
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# 1: Test that the optimization is only applied if the GROUP BY term
|
||||
# uses BINARY collation.
|
||||
#
|
||||
# 2: Not applied if there is a non-deterministic function in the HAVING
|
||||
# term.
|
||||
#
|
||||
foreach {tn sql1 sql2} {
|
||||
1 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE nocase HAVING a=2"
|
||||
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE nocase"
|
||||
|
||||
2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING randomblob(a)<X'88'"
|
||||
"SELECT a, sum(b) FROM t1 WHERE randomblob(a)<X'88' GROUP BY a"
|
||||
} {
|
||||
do_compare_vdbe_test 3.$tn $sql1 $sql2 0
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that non-deterministic functions disqualify a term from being
|
||||
# moved from the HAVING to WHERE clause.
|
||||
#
|
||||
do_execsql_test 4.1 {
|
||||
CREATE TABLE t3(a, b);
|
||||
INSERT INTO t3 VALUES(1, 1);
|
||||
INSERT INTO t3 VALUES(1, 2);
|
||||
INSERT INTO t3 VALUES(1, 3);
|
||||
INSERT INTO t3 VALUES(2, 1);
|
||||
INSERT INTO t3 VALUES(2, 2);
|
||||
INSERT INTO t3 VALUES(2, 3);
|
||||
}
|
||||
|
||||
proc nondeter {args} {
|
||||
incr ::nondeter_ret
|
||||
expr {$::nondeter_ret % 2}
|
||||
}
|
||||
db func nondeter nondeter
|
||||
|
||||
set ::nondeter_ret 0
|
||||
do_execsql_test 4.2 {
|
||||
SELECT a, sum(b) FROM t3 GROUP BY a HAVING nondeter(a)
|
||||
} {1 6}
|
||||
|
||||
# If the term where moved, the query above would return the same
|
||||
# result as the following. But it does not.
|
||||
#
|
||||
set ::nondeter_ret 0
|
||||
do_execsql_test 4.3 {
|
||||
SELECT a, sum(b) FROM t3 WHERE nondeter(a) GROUP BY a
|
||||
} {1 4 2 2}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -237,4 +237,16 @@ do_execsql_test 8.4 {
|
||||
SELECT count(*) FROM n1 WHERE a IN (SELECT +a FROM n1)
|
||||
} 3
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that ticket 61fe97454c is fixed.
|
||||
#
|
||||
do_execsql_test 9.0 {
|
||||
CREATE TABLE t9(a INTEGER PRIMARY KEY);
|
||||
INSERT INTO t9 VALUES (44), (45);
|
||||
}
|
||||
do_execsql_test 9.1 {
|
||||
SELECT * FROM t9 WHERE a IN (44, 45, 44, 45)
|
||||
} {44 45}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -32,5 +32,13 @@ do_execsql_test 1.2 {
|
||||
SELECT 'TWOX' == (b || 'x') COLLATE nocase FROM t1 WHERE (b || 'x')>'onex'
|
||||
} {0 1}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE INDEX i2 ON t1(a+1);
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT a+1, quote(a+1) FROM t1 ORDER BY 1;
|
||||
} {2 2 3 3 4 4}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -265,6 +265,8 @@ test_suite "fts3" -prefix "" -description {
|
||||
fts4incr.test fts4langid.test fts4lastrowid.test fts4merge2.test
|
||||
fts4merge4.test fts4merge.test fts4noti.test fts4onepass.test
|
||||
fts4opt.test fts4unicode.test
|
||||
fts3corrupt3.test
|
||||
fts3misc.test
|
||||
}
|
||||
|
||||
test_suite "fts5" -prefix "" -description {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# 2017 April 29
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix pushdown
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1 VALUES(1, 'b1', 'c1');
|
||||
INSERT INTO t1 VALUES(2, 'b2', 'c2');
|
||||
INSERT INTO t1 VALUES(3, 'b3', 'c3');
|
||||
INSERT INTO t1 VALUES(4, 'b4', 'c4');
|
||||
CREATE INDEX i1 ON t1(a, c);
|
||||
}
|
||||
|
||||
proc f {val} {
|
||||
lappend ::L $val
|
||||
return 0
|
||||
}
|
||||
db func f f
|
||||
|
||||
do_test 1.1 {
|
||||
set L [list]
|
||||
execsql { SELECT * FROM t1 WHERE a=2 AND f(b) AND f(c) }
|
||||
set L
|
||||
} {c2}
|
||||
|
||||
do_test 1.2 {
|
||||
set L [list]
|
||||
execsql { SELECT * FROM t1 WHERE a=3 AND f(c) AND f(b) }
|
||||
set L
|
||||
} {c3}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
DROP INDEX i1;
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
}
|
||||
do_test 1.4 {
|
||||
set L [list]
|
||||
execsql { SELECT * FROM t1 WHERE a=2 AND f(b) AND f(c) }
|
||||
set L
|
||||
} {b2}
|
||||
|
||||
do_test 1.5 {
|
||||
set L [list]
|
||||
execsql { SELECT * FROM t1 WHERE a=3 AND f(c) AND f(b) }
|
||||
set L
|
||||
} {b3}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,70 @@
|
||||
# 2017 May 9
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix subjournal
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA temp_store = memory;
|
||||
CREATE TABLE t1(a,b,c);
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
} {}
|
||||
do_execsql_test 1.1 {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
SAVEPOINT one;
|
||||
INSERT INTO t1 VALUES(7, 8, 9);
|
||||
ROLLBACK TO one;
|
||||
SELECT * FROM t1;
|
||||
} {1 2 3 4 5 6}
|
||||
do_execsql_test 1.2 {
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
PRAGMA cache_size = 5;
|
||||
CREATE TABLE t2(a BLOB);
|
||||
CREATE INDEX i2 ON t2(a);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
) INSERT INTO t2 SELECT randomblob(500) FROM s;
|
||||
}
|
||||
|
||||
do_test 2.1 {
|
||||
forcedelete test.db2
|
||||
sqlite3 db2 test2.db
|
||||
sqlite3_backup B db2 main db main
|
||||
set nPage [db one {PRAGMA page_count}]
|
||||
B step [expr $nPage-10]
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
BEGIN;
|
||||
UPDATE t2 SET a=randomblob(499);
|
||||
SAVEPOINT two;
|
||||
UPDATE t2 SET a=randomblob(498);
|
||||
ROLLBACK TO two;
|
||||
COMMIT;
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
do_test 2.3 {
|
||||
B step 1000
|
||||
} {SQLITE_DONE}
|
||||
do_test 2.4 {
|
||||
B finish
|
||||
execsql { PRAGMA integrity_check } db2
|
||||
} {ok}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -39,6 +39,7 @@ set extras {
|
||||
REGISTER
|
||||
VECTOR
|
||||
SELECT_COLUMN
|
||||
IF_NULL_ROW
|
||||
ASTERISK
|
||||
SPAN
|
||||
SPACE
|
||||
|
||||
+7
-7
@@ -250,7 +250,7 @@ static void StrAppend(Str *p, const char *z){
|
||||
sqlite3_uint64 nNew;
|
||||
if( p->oomErr ) return;
|
||||
nNew = p->nAlloc*2 + 100 + n;
|
||||
zNew = sqlite3_realloc(p->z, nNew);
|
||||
zNew = sqlite3_realloc(p->z, (int)nNew);
|
||||
if( zNew==0 ){
|
||||
sqlite3_free(p->z);
|
||||
memset(p, 0, sizeof(*p));
|
||||
@@ -260,7 +260,7 @@ static void StrAppend(Str *p, const char *z){
|
||||
p->z = zNew;
|
||||
p->nAlloc = nNew;
|
||||
}
|
||||
memcpy(p->z + p->n, z, n);
|
||||
memcpy(p->z + p->n, z, (size_t)n);
|
||||
p->n += n;
|
||||
p->z[p->n] = 0;
|
||||
}
|
||||
@@ -1116,15 +1116,15 @@ int main(int argc, char **argv){
|
||||
** if the database file is the input being fuzzed, the SQL text is
|
||||
** fuzzed at the same time. */
|
||||
if( sqlite3_table_column_metadata(db,0,"autoexec","sql",0,0,0,0,0)==0 ){
|
||||
sqlite3_stmt *pStmt;
|
||||
rc = sqlite3_prepare_v2(db, "SELECT sql FROM autoexec", -1, &pStmt, 0);
|
||||
sqlite3_stmt *pStmt2;
|
||||
rc = sqlite3_prepare_v2(db,"SELECT sql FROM autoexec",-1,&pStmt2,0);
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
StrAppend(&sql, (const char*)sqlite3_column_text(pStmt, 0));
|
||||
while( sqlite3_step(pStmt2)==SQLITE_ROW ){
|
||||
StrAppend(&sql, (const char*)sqlite3_column_text(pStmt2, 0));
|
||||
StrAppend(&sql, "\n");
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_finalize(pStmt2);
|
||||
zSql = StrStr(&sql);
|
||||
}
|
||||
|
||||
|
||||
+49
-49
@@ -168,12 +168,12 @@ static struct action *Action_new(void);
|
||||
static struct action *Action_sort(struct action *);
|
||||
|
||||
/********** From the file "build.h" ************************************/
|
||||
void FindRulePrecedences();
|
||||
void FindFirstSets();
|
||||
void FindStates();
|
||||
void FindLinks();
|
||||
void FindFollowSets();
|
||||
void FindActions();
|
||||
void FindRulePrecedences(struct lemon*);
|
||||
void FindFirstSets(struct lemon*);
|
||||
void FindStates(struct lemon*);
|
||||
void FindLinks(struct lemon*);
|
||||
void FindFollowSets(struct lemon*);
|
||||
void FindActions(struct lemon*);
|
||||
|
||||
/********* From the file "configlist.h" *********************************/
|
||||
void Configlist_init(void);
|
||||
@@ -457,7 +457,7 @@ struct state *State_new(void);
|
||||
void State_init(void);
|
||||
int State_insert(struct state *, struct config *);
|
||||
struct state *State_find(struct config *);
|
||||
struct state **State_arrayof(/* */);
|
||||
struct state **State_arrayof(void);
|
||||
|
||||
/* Routines used for efficiency in Configlist_add */
|
||||
|
||||
@@ -561,8 +561,8 @@ void Action_add(
|
||||
** default action for the state_number is returned.
|
||||
**
|
||||
** All actions associated with a single state_number are first entered
|
||||
** into aLookahead[] using multiple calls to acttab_action(). Then the
|
||||
** actions for that single state_number are placed into the aAction[]
|
||||
** into aLookahead[] using multiple calls to acttab_action(). Then the
|
||||
** actions for that single state_number are placed into the aAction[]
|
||||
** array with a single call to acttab_insert(). The acttab_insert() call
|
||||
** also resets the aLookahead[] array in preparation for the next
|
||||
** state number.
|
||||
@@ -612,7 +612,7 @@ acttab *acttab_alloc(void){
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Add a new action to the current transaction set.
|
||||
/* Add a new action to the current transaction set.
|
||||
**
|
||||
** This routine is called once for each lookahead for a particular
|
||||
** state.
|
||||
@@ -674,7 +674,7 @@ int acttab_insert(acttab *p){
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan the existing action table looking for an offset that is a
|
||||
/* Scan the existing action table looking for an offset that is a
|
||||
** duplicate of the current transaction set. Fall out of the loop
|
||||
** if and when the duplicate is found.
|
||||
**
|
||||
@@ -752,7 +752,7 @@ int acttab_insert(acttab *p){
|
||||
*/
|
||||
|
||||
/* Find a precedence symbol of every rule in the grammar.
|
||||
**
|
||||
**
|
||||
** Those rules which have a precedence symbol coded in the input
|
||||
** grammar using the "[symbol]" construct will already have the
|
||||
** rp->precsym field filled. Other rules take as their precedence
|
||||
@@ -1072,7 +1072,7 @@ void FindFollowSets(struct lemon *lemp)
|
||||
cfp->status = INCOMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
do{
|
||||
progress = 0;
|
||||
for(i=0; i<lemp->nstate; i++){
|
||||
@@ -1103,7 +1103,7 @@ void FindActions(struct lemon *lemp)
|
||||
struct symbol *sp;
|
||||
struct rule *rp;
|
||||
|
||||
/* Add all of the reduce actions
|
||||
/* Add all of the reduce actions
|
||||
** A reduce action is added for each element of the followset of
|
||||
** a configuration which has its dot at the extreme right.
|
||||
*/
|
||||
@@ -1220,7 +1220,7 @@ static int resolve_conflict(
|
||||
apx->type = RD_RESOLVED;
|
||||
}
|
||||
}else{
|
||||
assert(
|
||||
assert(
|
||||
apx->type==SH_RESOLVED ||
|
||||
apx->type==RD_RESOLVED ||
|
||||
apx->type==SSCONFLICT ||
|
||||
@@ -1251,7 +1251,7 @@ static struct config *basis = 0; /* Top of list of basis configs */
|
||||
static struct config **basisend = 0; /* End of list of basis configs */
|
||||
|
||||
/* Return a pointer to a new configuration */
|
||||
PRIVATE struct config *newconfig(){
|
||||
PRIVATE struct config *newconfig(void){
|
||||
struct config *newcfg;
|
||||
if( freelist==0 ){
|
||||
int i;
|
||||
@@ -1277,7 +1277,7 @@ PRIVATE void deleteconfig(struct config *old)
|
||||
}
|
||||
|
||||
/* Initialized the configuration list builder */
|
||||
void Configlist_init(){
|
||||
void Configlist_init(void){
|
||||
current = 0;
|
||||
currentend = ¤t;
|
||||
basis = 0;
|
||||
@@ -1287,7 +1287,7 @@ void Configlist_init(){
|
||||
}
|
||||
|
||||
/* Initialized the configuration list builder */
|
||||
void Configlist_reset(){
|
||||
void Configlist_reset(void){
|
||||
current = 0;
|
||||
currentend = ¤t;
|
||||
basis = 0;
|
||||
@@ -1397,7 +1397,7 @@ void Configlist_closure(struct lemon *lemp)
|
||||
}
|
||||
|
||||
/* Sort the configuration list */
|
||||
void Configlist_sort(){
|
||||
void Configlist_sort(void){
|
||||
current = (struct config*)msort((char*)current,(char**)&(current->next),
|
||||
Configcmp);
|
||||
currentend = 0;
|
||||
@@ -1405,7 +1405,7 @@ void Configlist_sort(){
|
||||
}
|
||||
|
||||
/* Sort the basis configuration list */
|
||||
void Configlist_sortbasis(){
|
||||
void Configlist_sortbasis(void){
|
||||
basis = (struct config*)msort((char*)current,(char**)&(current->bp),
|
||||
Configcmp);
|
||||
basisend = 0;
|
||||
@@ -1414,7 +1414,7 @@ void Configlist_sortbasis(){
|
||||
|
||||
/* Return a pointer to the head of the configuration list and
|
||||
** reset the list */
|
||||
struct config *Configlist_return(){
|
||||
struct config *Configlist_return(void){
|
||||
struct config *old;
|
||||
old = current;
|
||||
current = 0;
|
||||
@@ -1424,7 +1424,7 @@ struct config *Configlist_return(){
|
||||
|
||||
/* Return a pointer to the head of the configuration list and
|
||||
** reset the list */
|
||||
struct config *Configlist_basis(){
|
||||
struct config *Configlist_basis(void){
|
||||
struct config *old;
|
||||
old = basis;
|
||||
basis = 0;
|
||||
@@ -1466,7 +1466,7 @@ void ErrorMsg(const char *filename, int lineno, const char *format, ...){
|
||||
/* Report an out-of-memory condition and abort. This function
|
||||
** is used mostly by the "MemoryCheck" macro in struct.h
|
||||
*/
|
||||
void memory_error(){
|
||||
void memory_error(void){
|
||||
fprintf(stderr,"Out of memory. Aborting...\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -1606,7 +1606,7 @@ int main(int argc, char **argv)
|
||||
OptInit(argv,options,stderr);
|
||||
if( version ){
|
||||
printf("Lemon version 1.0\n");
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
if( OptNArgs()!=1 ){
|
||||
fprintf(stderr,"Exactly one filename argument is required.\n");
|
||||
@@ -2051,7 +2051,7 @@ int OptInit(char **a, struct s_options *o, FILE *err)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OptNArgs(){
|
||||
int OptNArgs(void){
|
||||
int cnt = 0;
|
||||
int dashdash = 0;
|
||||
int i;
|
||||
@@ -2078,7 +2078,7 @@ void OptErr(int n)
|
||||
if( i>=0 ) errline(i,0,errstream);
|
||||
}
|
||||
|
||||
void OptPrint(){
|
||||
void OptPrint(void){
|
||||
int i;
|
||||
int max, len;
|
||||
max = 0;
|
||||
@@ -2307,7 +2307,7 @@ to follow the previous rule.");
|
||||
case IN_RHS:
|
||||
if( x[0]=='.' ){
|
||||
struct rule *rp;
|
||||
rp = (struct rule *)calloc( sizeof(struct rule) +
|
||||
rp = (struct rule *)calloc( sizeof(struct rule) +
|
||||
sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1);
|
||||
if( rp==0 ){
|
||||
ErrorMsg(psp->filename,psp->tokenlineno,
|
||||
@@ -2896,7 +2896,7 @@ void Parse(struct lemon *gp)
|
||||
static struct plink *plink_freelist = 0;
|
||||
|
||||
/* Allocate a new plink */
|
||||
struct plink *Plink_new(){
|
||||
struct plink *Plink_new(void){
|
||||
struct plink *newlink;
|
||||
|
||||
if( plink_freelist==0 ){
|
||||
@@ -2997,7 +2997,7 @@ PRIVATE FILE *file_open(
|
||||
return fp;
|
||||
}
|
||||
|
||||
/* Duplicate the input file without comments and without actions
|
||||
/* Duplicate the input file without comments and without actions
|
||||
** on rules */
|
||||
void Reprint(struct lemon *lemp)
|
||||
{
|
||||
@@ -3148,7 +3148,7 @@ int PrintAction(
|
||||
indent,ap->sp->name,ap->x.rp->iRule);
|
||||
break;
|
||||
case SSCONFLICT:
|
||||
fprintf(fp,"%*s shift %-7d ** Parsing conflict **",
|
||||
fprintf(fp,"%*s shift %-7d ** Parsing conflict **",
|
||||
indent,ap->sp->name,ap->x.stp->statenum);
|
||||
break;
|
||||
case SH_RESOLVED:
|
||||
@@ -3421,7 +3421,7 @@ PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int *lineno)
|
||||
(*lineno)++;
|
||||
}
|
||||
if (!lemp->nolinenosflag) {
|
||||
(*lineno)++; tplt_linedir(out,*lineno,lemp->outname);
|
||||
(*lineno)++; tplt_linedir(out,*lineno,lemp->outname);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -3466,8 +3466,8 @@ void emit_destructor_code(
|
||||
fputc(*cp,out);
|
||||
}
|
||||
fprintf(out,"\n"); (*lineno)++;
|
||||
if (!lemp->nolinenosflag) {
|
||||
(*lineno)++; tplt_linedir(out,*lineno,lemp->outname);
|
||||
if (!lemp->nolinenosflag) {
|
||||
(*lineno)++; tplt_linedir(out,*lineno,lemp->outname);
|
||||
}
|
||||
fprintf(out,"}\n"); (*lineno)++;
|
||||
return;
|
||||
@@ -3590,7 +3590,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
|
||||
/* There is no LHS value symbol. */
|
||||
lhsdirect = 1;
|
||||
}else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){
|
||||
/* The LHS symbol and the left-most RHS symbol are the same, so
|
||||
/* The LHS symbol and the left-most RHS symbol are the same, so
|
||||
** direct writing is allowed */
|
||||
lhsdirect = 1;
|
||||
lhsused = 1;
|
||||
@@ -3601,7 +3601,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
|
||||
"different datatypes.",
|
||||
rp->lhs->name, rp->lhsalias, rp->rhs[0]->name, rp->rhsalias[0]);
|
||||
lemp->errorcnt++;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
lemon_sprintf(zOvwrt, "/*%s-overwrites-%s*/",
|
||||
rp->lhsalias, rp->rhsalias[0]);
|
||||
@@ -3740,7 +3740,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
** Generate code which executes when the rule "rp" is reduced. Write
|
||||
** the code to "out". Make sure lineno stays up-to-date.
|
||||
*/
|
||||
@@ -4161,7 +4161,7 @@ void ReportTable(
|
||||
for(i=0; i<lemp->nxstate; i++){
|
||||
for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
|
||||
if( ap->type==REDUCE || ap->type==SHIFTREDUCE ){
|
||||
ap->x.rp->doesReduce = i;
|
||||
ap->x.rp->doesReduce = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4237,7 +4237,7 @@ void ReportTable(
|
||||
fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++;
|
||||
fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++;
|
||||
fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++;
|
||||
fprintf(out, "static const %s yy_shift_ofst[] = {\n",
|
||||
fprintf(out, "static const %s yy_shift_ofst[] = {\n",
|
||||
minimum_size_type(mnTknOfst, lemp->nterminal+lemp->nactiontab, &sz));
|
||||
lineno++;
|
||||
lemp->tablesize += n*sz;
|
||||
@@ -4264,7 +4264,7 @@ void ReportTable(
|
||||
fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++;
|
||||
fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++;
|
||||
fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++;
|
||||
fprintf(out, "static const %s yy_reduce_ofst[] = {\n",
|
||||
fprintf(out, "static const %s yy_reduce_ofst[] = {\n",
|
||||
minimum_size_type(mnNtOfst-1, mxNtOfst, &sz)); lineno++;
|
||||
lemp->tablesize += n*sz;
|
||||
for(i=j=0; i<n; i++){
|
||||
@@ -4343,7 +4343,7 @@ void ReportTable(
|
||||
tplt_xfer(lemp->name,in,out,&lineno);
|
||||
|
||||
/* Generate code which executes every time a symbol is popped from
|
||||
** the stack while processing errors or while destroying the parser.
|
||||
** the stack while processing errors or while destroying the parser.
|
||||
** (In other words, generate the %destructor actions)
|
||||
*/
|
||||
if( lemp->tokendest ){
|
||||
@@ -4409,7 +4409,7 @@ void ReportTable(
|
||||
tplt_print(out,lemp,lemp->overflow,&lineno);
|
||||
tplt_xfer(lemp->name,in,out,&lineno);
|
||||
|
||||
/* Generate the table of rule information
|
||||
/* Generate the table of rule information
|
||||
**
|
||||
** Note: This code depends on the fact that rules are number
|
||||
** sequentually beginning with 0.
|
||||
@@ -4520,7 +4520,7 @@ void ReportHeader(struct lemon *lemp)
|
||||
for(i=1; i<lemp->nterminal; i++){
|
||||
fprintf(out,"#define %s%-30s %3d\n",prefix,lemp->symbols[i]->name,i);
|
||||
}
|
||||
fclose(out);
|
||||
fclose(out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -4567,7 +4567,7 @@ void CompressTables(struct lemon *lemp)
|
||||
rbest = rp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Do not make a default if the number of rules to default
|
||||
** is not at least 1 or if the wildcard token is a possible
|
||||
** lookahead.
|
||||
@@ -4724,7 +4724,7 @@ void SetSize(int n)
|
||||
}
|
||||
|
||||
/* Allocate a new set */
|
||||
char *SetNew(){
|
||||
char *SetNew(void){
|
||||
char *s;
|
||||
s = (char*)calloc( size, 1);
|
||||
if( s==0 ){
|
||||
@@ -4830,7 +4830,7 @@ typedef struct s_x1node {
|
||||
static struct s_x1 *x1a;
|
||||
|
||||
/* Allocate a new associative array */
|
||||
void Strsafe_init(){
|
||||
void Strsafe_init(void){
|
||||
if( x1a ) return;
|
||||
x1a = (struct s_x1*)malloc( sizeof(struct s_x1) );
|
||||
if( x1a ){
|
||||
@@ -4997,7 +4997,7 @@ typedef struct s_x2node {
|
||||
static struct s_x2 *x2a;
|
||||
|
||||
/* Allocate a new associative array */
|
||||
void Symbol_init(){
|
||||
void Symbol_init(void){
|
||||
if( x2a ) return;
|
||||
x2a = (struct s_x2*)malloc( sizeof(struct s_x2) );
|
||||
if( x2a ){
|
||||
@@ -5194,7 +5194,7 @@ typedef struct s_x3node {
|
||||
static struct s_x3 *x3a;
|
||||
|
||||
/* Allocate a new associative array */
|
||||
void State_init(){
|
||||
void State_init(void){
|
||||
if( x3a ) return;
|
||||
x3a = (struct s_x3*)malloc( sizeof(struct s_x3) );
|
||||
if( x3a ){
|
||||
@@ -5288,7 +5288,7 @@ struct state *State_find(struct config *key)
|
||||
/* Return an array of pointers to all data in the table.
|
||||
** The array is obtained from malloc. Return NULL if memory allocation
|
||||
** problems, or if the array is empty. */
|
||||
struct state **State_arrayof()
|
||||
struct state **State_arrayof(void)
|
||||
{
|
||||
struct state **array;
|
||||
int i,arrSize;
|
||||
@@ -5334,7 +5334,7 @@ typedef struct s_x4node {
|
||||
static struct s_x4 *x4a;
|
||||
|
||||
/* Allocate a new associative array */
|
||||
void Configtable_init(){
|
||||
void Configtable_init(void){
|
||||
if( x4a ) return;
|
||||
x4a = (struct s_x4*)malloc( sizeof(struct s_x4) );
|
||||
if( x4a ){
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ Replace.exe:
|
||||
sqlite3.def: Replace.exe $(LIBOBJ)
|
||||
echo EXPORTS > sqlite3.def
|
||||
dumpbin /all $(LIBOBJ) \\
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \\
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \\
|
||||
| sort >> sqlite3.def
|
||||
}]]
|
||||
|
||||
|
||||
+5
-1
@@ -81,6 +81,9 @@ set declpattern2 \
|
||||
set declpattern3 \
|
||||
{^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3changeset_[_a-zA-Z0-9]+)(\(.*)$}
|
||||
|
||||
set declpattern4 \
|
||||
{^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3changegroup_[_a-zA-Z0-9]+)(\(.*)$}
|
||||
|
||||
# Force the output to use unix line endings, even on Windows.
|
||||
fconfigure stdout -translation lf
|
||||
|
||||
@@ -129,7 +132,8 @@ foreach file $filelist {
|
||||
} else {
|
||||
if {[regexp $declpattern1 $line all rettype funcname rest] || \
|
||||
[regexp $declpattern2 $line all rettype funcname rest] || \
|
||||
[regexp $declpattern3 $line all rettype funcname rest]} {
|
||||
[regexp $declpattern3 $line all rettype funcname rest] || \
|
||||
[regexp $declpattern4 $line all rettype funcname rest]} {
|
||||
set line SQLITE_API
|
||||
append line " " [string trim $rettype]
|
||||
if {[string index $rettype end] ne "*"} {
|
||||
|
||||
+16
-8
@@ -1,6 +1,3 @@
|
||||
|
||||
set rcsid {$Id: omittest.tcl,v 1.8 2008/10/13 15:35:09 drh Exp $}
|
||||
|
||||
# Documentation for this script. This may be output to stderr
|
||||
# if the script is invoked incorrectly.
|
||||
set ::USAGE_MESSAGE {
|
||||
@@ -134,26 +131,37 @@ proc process_options {argv} {
|
||||
set ::TARGET testfixture ;# Default thing to build
|
||||
|
||||
for {set i 0} {$i < [llength $argv]} {incr i} {
|
||||
switch -- [lindex $argv $i] {
|
||||
-makefile {
|
||||
switch -regexp -- [lindex $argv $i] {
|
||||
-{1,2}makefile {
|
||||
incr i
|
||||
set ::MAKEFILE [lindex $argv $i]
|
||||
}
|
||||
|
||||
-nmake {
|
||||
-{1,2}nmake {
|
||||
set ::MAKEBIN nmake
|
||||
set ::MAKEFILE ./Makefile.msc
|
||||
}
|
||||
|
||||
-target {
|
||||
-{1,2}target {
|
||||
incr i
|
||||
set ::TARGET [lindex $argv $i]
|
||||
}
|
||||
|
||||
-skip_run {
|
||||
-{1,2}skip_run {
|
||||
set ::SKIP_RUN 1
|
||||
}
|
||||
|
||||
-{1,2}help {
|
||||
puts $::USAGE_MESSAGE
|
||||
exit
|
||||
}
|
||||
|
||||
-.* {
|
||||
puts stderr "Unknown option: [lindex $argv i]"
|
||||
puts stderr $::USAGE_MESSAGE
|
||||
exit 1
|
||||
}
|
||||
|
||||
default {
|
||||
if {[info exists ::SYMBOL]} {
|
||||
puts stderr [string trim $::USAGE_MESSAGE]
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
@@ -579,6 +580,14 @@ int main(int argc, char **argv){
|
||||
decode_btree_page(a, iStart, hdrSize, zLeft+1);
|
||||
free(a);
|
||||
continue;
|
||||
#if !defined(_MSC_VER)
|
||||
}else if( zLeft && strcmp(zLeft,"truncate")==0 ){
|
||||
/* Frame number followed by "truncate" truncates the WAL file
|
||||
** after that frame */
|
||||
off_t newSize = 32 + iStart*(pagesize+24);
|
||||
truncate(argv[1], newSize);
|
||||
continue;
|
||||
#endif
|
||||
}else{
|
||||
iEnd = iStart;
|
||||
}
|
||||
|
||||
+9
-7
@@ -4,13 +4,15 @@
|
||||
# compiler warnings in SQLite.
|
||||
#
|
||||
|
||||
# Use these for testing on Linux and Mac OSX:
|
||||
WARNING_OPTS="-Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long"
|
||||
WARNING_ANDROID_OPTS="-Wshadow -Wall -Wextra"
|
||||
|
||||
# Use these for testing on OpenBSD:
|
||||
# WARNING_OPTS=-Wall
|
||||
# WARNING_ANDROID_OPTS=-Wall
|
||||
if uname | grep -i openbsd ; then
|
||||
# Use these for testing on OpenBSD:
|
||||
WARNING_OPTS=-Wall
|
||||
WARNING_ANDROID_OPTS=-Wall
|
||||
else
|
||||
# Use these for testing on Linux and Mac OSX:
|
||||
WARNING_OPTS="-Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long"
|
||||
WARNING_ANDROID_OPTS="-Wshadow -Wall -Wextra"
|
||||
fi
|
||||
|
||||
rm -f sqlite3.c
|
||||
make sqlite3.c
|
||||
|
||||
Reference in New Issue
Block a user