summaryrefslogtreecommitdiffstats
path: root/lib/libsqlite3/ext
diff options
context:
space:
mode:
authorjturner <jturner@openbsd.org>2015-12-23 20:07:36 +0000
committerjturner <jturner@openbsd.org>2015-12-23 20:07:36 +0000
commit454f2601b89e8c6c8f927b542b09b36ffb6763a8 (patch)
tree3aeb7f1535c5a957952029d1542c4f4ecd85a695 /lib/libsqlite3/ext
parentDo undo. (diff)
downloadwireguard-openbsd-454f2601b89e8c6c8f927b542b09b36ffb6763a8.tar.xz
wireguard-openbsd-454f2601b89e8c6c8f927b542b09b36ffb6763a8.zip
Update sqlite3 to 3.9.2. Bump major, regen .pc and header. Changes
available here: http://sqlite.org/changes.html Tested in bulk by aja@. ok landry@
Diffstat (limited to 'lib/libsqlite3/ext')
-rw-r--r--lib/libsqlite3/ext/async/sqlite3async.c18
-rw-r--r--lib/libsqlite3/ext/fts3/fts3.c16
-rw-r--r--lib/libsqlite3/ext/fts3/fts3Int.h1
-rw-r--r--lib/libsqlite3/ext/fts3/fts3_expr.c216
-rw-r--r--lib/libsqlite3/ext/fts3/fts3_write.c36
-rw-r--r--lib/libsqlite3/ext/misc/spellfix.c99
-rw-r--r--lib/libsqlite3/ext/rtree/rtree1.test55
7 files changed, 283 insertions, 158 deletions
diff --git a/lib/libsqlite3/ext/async/sqlite3async.c b/lib/libsqlite3/ext/async/sqlite3async.c
index 9810c56f5a6..7affbfe02f0 100644
--- a/lib/libsqlite3/ext/async/sqlite3async.c
+++ b/lib/libsqlite3/ext/async/sqlite3async.c
@@ -10,7 +10,7 @@
**
*************************************************************************
**
-** $Id: sqlite3async.c,v 1.1.1.2 2013/03/18 10:45:29 espie Exp $
+** $Id: sqlite3async.c,v 1.2 2015/12/23 20:07:36 jturner Exp $
**
** This file contains the implementation of an asynchronous IO backend
** for SQLite.
@@ -1636,6 +1636,7 @@ void sqlite3async_run(void){
** Control/configure the asynchronous IO system.
*/
int sqlite3async_control(int op, ...){
+ int rc = SQLITE_OK;
va_list ap;
va_start(ap, op);
switch( op ){
@@ -1645,7 +1646,8 @@ int sqlite3async_control(int op, ...){
&& eWhen!=SQLITEASYNC_HALT_NOW
&& eWhen!=SQLITEASYNC_HALT_IDLE
){
- return SQLITE_MISUSE;
+ rc = SQLITE_MISUSE;
+ break;
}
async.eHalt = eWhen;
async_mutex_enter(ASYNC_MUTEX_QUEUE);
@@ -1657,7 +1659,8 @@ int sqlite3async_control(int op, ...){
case SQLITEASYNC_DELAY: {
int iDelay = va_arg(ap, int);
if( iDelay<0 ){
- return SQLITE_MISUSE;
+ rc = SQLITE_MISUSE;
+ break;
}
async.ioDelay = iDelay;
break;
@@ -1668,7 +1671,8 @@ int sqlite3async_control(int op, ...){
async_mutex_enter(ASYNC_MUTEX_QUEUE);
if( async.nFile || async.pQueueFirst ){
async_mutex_leave(ASYNC_MUTEX_QUEUE);
- return SQLITE_MISUSE;
+ rc = SQLITE_MISUSE;
+ break;
}
async.bLockFiles = bLock;
async_mutex_leave(ASYNC_MUTEX_QUEUE);
@@ -1692,9 +1696,11 @@ int sqlite3async_control(int op, ...){
}
default:
- return SQLITE_ERROR;
+ rc = SQLITE_ERROR;
+ break;
}
- return SQLITE_OK;
+ va_end(ap);
+ return rc;
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO) */
diff --git a/lib/libsqlite3/ext/fts3/fts3.c b/lib/libsqlite3/ext/fts3/fts3.c
index 6a9b507fc0d..748faefec5a 100644
--- a/lib/libsqlite3/ext/fts3/fts3.c
+++ b/lib/libsqlite3/ext/fts3/fts3.c
@@ -1517,6 +1517,19 @@ static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
#endif
}
+/*
+** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
+** extension is currently being used by a version of SQLite too old to
+** support index-info flags. In that case this function is a no-op.
+*/
+static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){
+#if SQLITE_VERSION_NUMBER>=3008012
+ if( sqlite3_libversion_number()>=3008012 ){
+ pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
+ }
+#endif
+}
+
/*
** Implementation of the xBestIndex method for FTS3 tables. There
** are three possible strategies, in order of preference:
@@ -1607,6 +1620,9 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
}
}
+ /* If using a docid=? or rowid=? strategy, set the UNIQUE flag. */
+ if( pInfo->idxNum==FTS3_DOCID_SEARCH ) fts3SetUniqueFlag(pInfo);
+
iIdx = 1;
if( iCons>=0 ){
pInfo->aConstraintUsage[iCons].argvIndex = iIdx++;
diff --git a/lib/libsqlite3/ext/fts3/fts3Int.h b/lib/libsqlite3/ext/fts3/fts3Int.h
index 981c37deee5..06bcc7202e1 100644
--- a/lib/libsqlite3/ext/fts3/fts3Int.h
+++ b/lib/libsqlite3/ext/fts3/fts3Int.h
@@ -264,6 +264,7 @@ struct Fts3Table {
int nPendingData; /* Current bytes of pending data */
sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */
int iPrevLangid; /* Langid of recently inserted document */
+ int bPrevDelete; /* True if last operation was a delete */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
/* State variables used for validating that the transaction control
diff --git a/lib/libsqlite3/ext/fts3/fts3_expr.c b/lib/libsqlite3/ext/fts3/fts3_expr.c
index d7cabd99195..788e5021ec2 100644
--- a/lib/libsqlite3/ext/fts3/fts3_expr.c
+++ b/lib/libsqlite3/ext/fts3/fts3_expr.c
@@ -793,125 +793,151 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
rc = SQLITE_ERROR;
}
- if( rc==SQLITE_OK && (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
- Fts3Expr **apLeaf;
- apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
- if( 0==apLeaf ){
- rc = SQLITE_NOMEM;
- }else{
- memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
- }
-
- if( rc==SQLITE_OK ){
- int i;
- Fts3Expr *p;
-
- /* Set $p to point to the left-most leaf in the tree of eType nodes. */
- for(p=pRoot; p->eType==eType; p=p->pLeft){
- assert( p->pParent==0 || p->pParent->pLeft==p );
- assert( p->pLeft && p->pRight );
+ if( rc==SQLITE_OK ){
+ if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
+ Fts3Expr **apLeaf;
+ apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
+ if( 0==apLeaf ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
}
- /* This loop runs once for each leaf in the tree of eType nodes. */
- while( 1 ){
- int iLvl;
- Fts3Expr *pParent = p->pParent; /* Current parent of p */
+ if( rc==SQLITE_OK ){
+ int i;
+ Fts3Expr *p;
- assert( pParent==0 || pParent->pLeft==p );
- p->pParent = 0;
- if( pParent ){
- pParent->pLeft = 0;
- }else{
- pRoot = 0;
+ /* Set $p to point to the left-most leaf in the tree of eType nodes. */
+ for(p=pRoot; p->eType==eType; p=p->pLeft){
+ assert( p->pParent==0 || p->pParent->pLeft==p );
+ assert( p->pLeft && p->pRight );
}
- rc = fts3ExprBalance(&p, nMaxDepth-1);
- if( rc!=SQLITE_OK ) break;
- for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
- if( apLeaf[iLvl]==0 ){
- apLeaf[iLvl] = p;
- p = 0;
+ /* This loop runs once for each leaf in the tree of eType nodes. */
+ while( 1 ){
+ int iLvl;
+ Fts3Expr *pParent = p->pParent; /* Current parent of p */
+
+ assert( pParent==0 || pParent->pLeft==p );
+ p->pParent = 0;
+ if( pParent ){
+ pParent->pLeft = 0;
}else{
- assert( pFree );
- pFree->pLeft = apLeaf[iLvl];
- pFree->pRight = p;
- pFree->pLeft->pParent = pFree;
- pFree->pRight->pParent = pFree;
-
- p = pFree;
- pFree = pFree->pParent;
- p->pParent = 0;
- apLeaf[iLvl] = 0;
+ pRoot = 0;
}
- }
- if( p ){
- sqlite3Fts3ExprFree(p);
- rc = SQLITE_TOOBIG;
- break;
- }
-
- /* If that was the last leaf node, break out of the loop */
- if( pParent==0 ) break;
-
- /* Set $p to point to the next leaf in the tree of eType nodes */
- for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
-
- /* Remove pParent from the original tree. */
- assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
- pParent->pRight->pParent = pParent->pParent;
- if( pParent->pParent ){
- pParent->pParent->pLeft = pParent->pRight;
- }else{
- assert( pParent==pRoot );
- pRoot = pParent->pRight;
- }
+ rc = fts3ExprBalance(&p, nMaxDepth-1);
+ if( rc!=SQLITE_OK ) break;
- /* Link pParent into the free node list. It will be used as an
- ** internal node of the new tree. */
- pParent->pParent = pFree;
- pFree = pParent;
- }
-
- if( rc==SQLITE_OK ){
- p = 0;
- for(i=0; i<nMaxDepth; i++){
- if( apLeaf[i] ){
- if( p==0 ){
- p = apLeaf[i];
- p->pParent = 0;
+ for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
+ if( apLeaf[iLvl]==0 ){
+ apLeaf[iLvl] = p;
+ p = 0;
}else{
- assert( pFree!=0 );
+ assert( pFree );
+ pFree->pLeft = apLeaf[iLvl];
pFree->pRight = p;
- pFree->pLeft = apLeaf[i];
pFree->pLeft->pParent = pFree;
pFree->pRight->pParent = pFree;
p = pFree;
pFree = pFree->pParent;
p->pParent = 0;
+ apLeaf[iLvl] = 0;
}
}
+ if( p ){
+ sqlite3Fts3ExprFree(p);
+ rc = SQLITE_TOOBIG;
+ break;
+ }
+
+ /* If that was the last leaf node, break out of the loop */
+ if( pParent==0 ) break;
+
+ /* Set $p to point to the next leaf in the tree of eType nodes */
+ for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
+
+ /* Remove pParent from the original tree. */
+ assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
+ pParent->pRight->pParent = pParent->pParent;
+ if( pParent->pParent ){
+ pParent->pParent->pLeft = pParent->pRight;
+ }else{
+ assert( pParent==pRoot );
+ pRoot = pParent->pRight;
+ }
+
+ /* Link pParent into the free node list. It will be used as an
+ ** internal node of the new tree. */
+ pParent->pParent = pFree;
+ pFree = pParent;
}
- pRoot = p;
- }else{
- /* An error occurred. Delete the contents of the apLeaf[] array
- ** and pFree list. Everything else is cleaned up by the call to
- ** sqlite3Fts3ExprFree(pRoot) below. */
- Fts3Expr *pDel;
- for(i=0; i<nMaxDepth; i++){
- sqlite3Fts3ExprFree(apLeaf[i]);
- }
- while( (pDel=pFree)!=0 ){
- pFree = pDel->pParent;
- sqlite3_free(pDel);
+
+ if( rc==SQLITE_OK ){
+ p = 0;
+ for(i=0; i<nMaxDepth; i++){
+ if( apLeaf[i] ){
+ if( p==0 ){
+ p = apLeaf[i];
+ p->pParent = 0;
+ }else{
+ assert( pFree!=0 );
+ pFree->pRight = p;
+ pFree->pLeft = apLeaf[i];
+ pFree->pLeft->pParent = pFree;
+ pFree->pRight->pParent = pFree;
+
+ p = pFree;
+ pFree = pFree->pParent;
+ p->pParent = 0;
+ }
+ }
+ }
+ pRoot = p;
+ }else{
+ /* An error occurred. Delete the contents of the apLeaf[] array
+ ** and pFree list. Everything else is cleaned up by the call to
+ ** sqlite3Fts3ExprFree(pRoot) below. */
+ Fts3Expr *pDel;
+ for(i=0; i<nMaxDepth; i++){
+ sqlite3Fts3ExprFree(apLeaf[i]);
+ }
+ while( (pDel=pFree)!=0 ){
+ pFree = pDel->pParent;
+ sqlite3_free(pDel);
+ }
}
+
+ assert( pFree==0 );
+ sqlite3_free( apLeaf );
+ }
+ }else if( eType==FTSQUERY_NOT ){
+ Fts3Expr *pLeft = pRoot->pLeft;
+ Fts3Expr *pRight = pRoot->pRight;
+
+ pRoot->pLeft = 0;
+ pRoot->pRight = 0;
+ pLeft->pParent = 0;
+ pRight->pParent = 0;
+
+ rc = fts3ExprBalance(&pLeft, nMaxDepth-1);
+ if( rc==SQLITE_OK ){
+ rc = fts3ExprBalance(&pRight, nMaxDepth-1);
}
- assert( pFree==0 );
- sqlite3_free( apLeaf );
+ if( rc!=SQLITE_OK ){
+ sqlite3Fts3ExprFree(pRight);
+ sqlite3Fts3ExprFree(pLeft);
+ }else{
+ assert( pLeft && pRight );
+ pRoot->pLeft = pLeft;
+ pLeft->pParent = pRoot;
+ pRoot->pRight = pRight;
+ pRight->pParent = pRoot;
+ }
}
}
-
+
if( rc!=SQLITE_OK ){
sqlite3Fts3ExprFree(pRoot);
pRoot = 0;
diff --git a/lib/libsqlite3/ext/fts3/fts3_write.c b/lib/libsqlite3/ext/fts3/fts3_write.c
index 4cd2aebf6a8..d5a408222ec 100644
--- a/lib/libsqlite3/ext/fts3/fts3_write.c
+++ b/lib/libsqlite3/ext/fts3/fts3_write.c
@@ -860,10 +860,12 @@ static int fts3PendingTermsAdd(
*/
static int fts3PendingTermsDocid(
Fts3Table *p, /* Full-text table handle */
+ int bDelete, /* True if this op is a delete */
int iLangid, /* Language id of row being written */
sqlite_int64 iDocid /* Docid of row being written */
){
assert( iLangid>=0 );
+ assert( bDelete==1 || bDelete==0 );
/* TODO(shess) Explore whether partially flushing the buffer on
** forced-flush would provide better performance. I suspect that if
@@ -871,7 +873,8 @@ static int fts3PendingTermsDocid(
** buffer was half empty, that would let the less frequent terms
** generate longer doclists.
*/
- if( iDocid<=p->iPrevDocid
+ if( iDocid<p->iPrevDocid
+ || (iDocid==p->iPrevDocid && p->bPrevDelete==0)
|| p->iPrevLangid!=iLangid
|| p->nPendingData>p->nMaxPendingData
){
@@ -880,6 +883,7 @@ static int fts3PendingTermsDocid(
}
p->iPrevDocid = iDocid;
p->iPrevLangid = iLangid;
+ p->bPrevDelete = bDelete;
return SQLITE_OK;
}
@@ -1069,7 +1073,8 @@ static void fts3DeleteTerms(
if( SQLITE_ROW==sqlite3_step(pSelect) ){
int i;
int iLangid = langidFromSelect(p, pSelect);
- rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pSelect, 0));
+ i64 iDocid = sqlite3_column_int64(pSelect, 0);
+ rc = fts3PendingTermsDocid(p, 1, iLangid, iDocid);
for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){
int iCol = i-1;
if( p->abNotindexed[iCol]==0 ){
@@ -1317,14 +1322,19 @@ static int fts3SegReaderNext(
if( fts3SegReaderIsPending(pReader) ){
Fts3HashElem *pElem = *(pReader->ppNextElem);
- if( pElem==0 ){
- pReader->aNode = 0;
- }else{
+ sqlite3_free(pReader->aNode);
+ pReader->aNode = 0;
+ if( pElem ){
+ char *aCopy;
PendingList *pList = (PendingList *)fts3HashData(pElem);
+ int nCopy = pList->nData+1;
pReader->zTerm = (char *)fts3HashKey(pElem);
pReader->nTerm = fts3HashKeysize(pElem);
- pReader->nNode = pReader->nDoclist = pList->nData + 1;
- pReader->aNode = pReader->aDoclist = pList->aData;
+ aCopy = (char*)sqlite3_malloc(nCopy);
+ if( !aCopy ) return SQLITE_NOMEM;
+ memcpy(aCopy, pList->aData, nCopy);
+ pReader->nNode = pReader->nDoclist = nCopy;
+ pReader->aNode = pReader->aDoclist = aCopy;
pReader->ppNextElem++;
assert( pReader->aNode );
}
@@ -1564,12 +1574,14 @@ int sqlite3Fts3MsrOvfl(
** second argument.
*/
void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
- if( pReader && !fts3SegReaderIsPending(pReader) ){
- sqlite3_free(pReader->zTerm);
+ if( pReader ){
+ if( !fts3SegReaderIsPending(pReader) ){
+ sqlite3_free(pReader->zTerm);
+ }
if( !fts3SegReaderIsRootOnly(pReader) ){
sqlite3_free(pReader->aNode);
- sqlite3_blob_close(pReader->pBlob);
}
+ sqlite3_blob_close(pReader->pBlob);
}
sqlite3_free(pReader);
}
@@ -3512,7 +3524,7 @@ static int fts3DoRebuild(Fts3Table *p){
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
int iCol;
int iLangid = langidFromSelect(p, pStmt);
- rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pStmt, 0));
+ rc = fts3PendingTermsDocid(p, 0, iLangid, sqlite3_column_int64(pStmt, 0));
memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1));
for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
if( p->abNotindexed[iCol]==0 ){
@@ -5617,7 +5629,7 @@ int sqlite3Fts3UpdateMethod(
}
}
if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
- rc = fts3PendingTermsDocid(p, iLangid, *pRowid);
+ rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid);
}
if( rc==SQLITE_OK ){
assert( p->iPrevDocid==*pRowid );
diff --git a/lib/libsqlite3/ext/misc/spellfix.c b/lib/libsqlite3/ext/misc/spellfix.c
index b9514427cf9..336203433ec 100644
--- a/lib/libsqlite3/ext/misc/spellfix.c
+++ b/lib/libsqlite3/ext/misc/spellfix.c
@@ -1770,6 +1770,7 @@ struct spellfix1_cursor {
sqlite3_vtab_cursor base; /* Base class - must be first */
spellfix1_vtab *pVTab; /* The table to which this cursor belongs */
char *zPattern; /* rhs of MATCH clause */
+ int idxNum; /* idxNum value passed to xFilter() */
int nRow; /* Number of rows of content */
int nAlloc; /* Number of allocated rows */
int iRow; /* Current row of content */
@@ -2040,26 +2041,19 @@ static int spellfix1Close(sqlite3_vtab_cursor *cur){
return SQLITE_OK;
}
+#define SPELLFIX_IDXNUM_MATCH 0x01 /* word MATCH $str */
+#define SPELLFIX_IDXNUM_LANGID 0x02 /* langid == $langid */
+#define SPELLFIX_IDXNUM_TOP 0x04 /* top = $top */
+#define SPELLFIX_IDXNUM_SCOPE 0x08 /* scope = $scope */
+#define SPELLFIX_IDXNUM_DISTLT 0x10 /* distance < $distance */
+#define SPELLFIX_IDXNUM_DISTLE 0x20 /* distance <= $distance */
+#define SPELLFIX_IDXNUM_ROWID 0x40 /* rowid = $rowid */
+#define SPELLFIX_IDXNUM_DIST (0x10|0x20) /* DISTLT and DISTLE */
+
/*
-** Search for terms of these forms:
-**
-** (A) word MATCH $str
-** (B) langid == $langid
-** (C) top = $top
-** (D) scope = $scope
-** (E) distance < $distance
-** (F) distance <= $distance
-** (G) rowid = $rowid
-**
-** The plan number is a bit mask formed with these bits:
**
-** 0x01 (A) is found
-** 0x02 (B) is found
-** 0x04 (C) is found
-** 0x08 (D) is found
-** 0x10 (E) is found
-** 0x20 (F) is found
-** 0x40 (G) is found
+** The plan number is a bitmask of the SPELLFIX_IDXNUM_* values defined
+** above.
**
** filter.argv[*] values contains $str, $langid, $top, $scope and $rowid
** if specified and in that order.
@@ -2078,62 +2072,66 @@ static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
if( pConstraint->usable==0 ) continue;
/* Terms of the form: word MATCH $str */
- if( (iPlan & 1)==0
+ if( (iPlan & SPELLFIX_IDXNUM_MATCH)==0
&& pConstraint->iColumn==SPELLFIX_COL_WORD
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH
){
- iPlan |= 1;
+ iPlan |= SPELLFIX_IDXNUM_MATCH;
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
pIdxInfo->aConstraintUsage[i].omit = 1;
}
/* Terms of the form: langid = $langid */
- if( (iPlan & 2)==0
+ if( (iPlan & SPELLFIX_IDXNUM_LANGID)==0
&& pConstraint->iColumn==SPELLFIX_COL_LANGID
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
){
- iPlan |= 2;
+ iPlan |= SPELLFIX_IDXNUM_LANGID;
iLangTerm = i;
}
/* Terms of the form: top = $top */
- if( (iPlan & 4)==0
+ if( (iPlan & SPELLFIX_IDXNUM_TOP)==0
&& pConstraint->iColumn==SPELLFIX_COL_TOP
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
){
- iPlan |= 4;
+ iPlan |= SPELLFIX_IDXNUM_TOP;
iTopTerm = i;
}
/* Terms of the form: scope = $scope */
- if( (iPlan & 8)==0
+ if( (iPlan & SPELLFIX_IDXNUM_SCOPE)==0
&& pConstraint->iColumn==SPELLFIX_COL_SCOPE
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
){
- iPlan |= 8;
+ iPlan |= SPELLFIX_IDXNUM_SCOPE;
iScopeTerm = i;
}
/* Terms of the form: distance < $dist or distance <= $dist */
- if( (iPlan & (16|32))==0
+ if( (iPlan & SPELLFIX_IDXNUM_DIST)==0
&& pConstraint->iColumn==SPELLFIX_COL_DISTANCE
&& (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
|| pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE)
){
- iPlan |= pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ? 16 : 32;
+ if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){
+ iPlan |= SPELLFIX_IDXNUM_DISTLT;
+ }else{
+ iPlan |= SPELLFIX_IDXNUM_DISTLE;
+ }
iDistTerm = i;
}
/* Terms of the form: distance < $dist or distance <= $dist */
- if( (iPlan & 64)==0
+ if( (iPlan & SPELLFIX_IDXNUM_ROWID)==0
&& pConstraint->iColumn<0
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
){
- iPlan |= 64;
+ iPlan |= SPELLFIX_IDXNUM_ROWID;
iRowidTerm = i;
}
}
- if( iPlan&1 ){
+ if( iPlan&SPELLFIX_IDXNUM_MATCH ){
int idx = 2;
pIdxInfo->idxNum = iPlan;
if( pIdxInfo->nOrderBy==1
@@ -2142,25 +2140,25 @@ static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
){
pIdxInfo->orderByConsumed = 1; /* Default order by iScore */
}
- if( iPlan&2 ){
+ if( iPlan&SPELLFIX_IDXNUM_LANGID ){
pIdxInfo->aConstraintUsage[iLangTerm].argvIndex = idx++;
pIdxInfo->aConstraintUsage[iLangTerm].omit = 1;
}
- if( iPlan&4 ){
+ if( iPlan&SPELLFIX_IDXNUM_TOP ){
pIdxInfo->aConstraintUsage[iTopTerm].argvIndex = idx++;
pIdxInfo->aConstraintUsage[iTopTerm].omit = 1;
}
- if( iPlan&8 ){
+ if( iPlan&SPELLFIX_IDXNUM_SCOPE ){
pIdxInfo->aConstraintUsage[iScopeTerm].argvIndex = idx++;
pIdxInfo->aConstraintUsage[iScopeTerm].omit = 1;
}
- if( iPlan&(16|32) ){
+ if( iPlan&SPELLFIX_IDXNUM_DIST ){
pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = idx++;
pIdxInfo->aConstraintUsage[iDistTerm].omit = 1;
}
pIdxInfo->estimatedCost = 1e5;
- }else if( (iPlan & 64) ){
- pIdxInfo->idxNum = 64;
+ }else if( (iPlan & SPELLFIX_IDXNUM_ROWID) ){
+ pIdxInfo->idxNum = SPELLFIX_IDXNUM_ROWID;
pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1;
pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1;
pIdxInfo->estimatedCost = 5;
@@ -2311,15 +2309,24 @@ static void spellfix1RunQuery(MatchQuery *p, const char *zQuery, int nQuery){
break;
}
pCur->nSearch++;
- iScore = spellfix1Score(iDist,iRank);
+
+ /* If there is a "distance < $dist" or "distance <= $dist" constraint,
+ ** check if this row meets it. If not, jump back up to the top of the
+ ** loop to process the next row. Otherwise, if the row does match the
+ ** distance constraint, check if the pCur->a[] array is already full.
+ ** If it is and no explicit "top = ?" constraint was present in the
+ ** query, grow the array to ensure there is room for the new entry. */
+ assert( (p->iMaxDist>=0)==((pCur->idxNum & SPELLFIX_IDXNUM_DIST) ? 1 : 0) );
if( p->iMaxDist>=0 ){
if( iDist>p->iMaxDist ) continue;
- if( pCur->nRow>=pCur->nAlloc-1 ){
+ if( pCur->nRow>=pCur->nAlloc && (pCur->idxNum & SPELLFIX_IDXNUM_TOP)==0 ){
spellfix1ResizeCursor(pCur, pCur->nAlloc*2 + 10);
if( pCur->a==0 ) break;
}
- idx = pCur->nRow;
- }else if( pCur->nRow<pCur->nAlloc ){
+ }
+
+ iScore = spellfix1Score(iDist,iRank);
+ if( pCur->nRow<pCur->nAlloc ){
idx = pCur->nRow;
}else if( iScore<iWorst ){
idx = idxWorst;
@@ -2327,6 +2334,7 @@ static void spellfix1RunQuery(MatchQuery *p, const char *zQuery, int nQuery){
}else{
continue;
}
+
pCur->a[idx].zWord = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
if( pCur->a[idx].zWord==0 ){
p->rc = SQLITE_NOMEM;
@@ -2361,10 +2369,10 @@ static void spellfix1RunQuery(MatchQuery *p, const char *zQuery, int nQuery){
*/
static int spellfix1FilterForMatch(
spellfix1_cursor *pCur,
- int idxNum,
int argc,
sqlite3_value **argv
){
+ int idxNum = pCur->idxNum;
const unsigned char *zMatchThis; /* RHS of the MATCH operator */
EditDist3FromString *pMatchStr3 = 0; /* zMatchThis as an editdist string */
char *zPattern; /* Transliteration of zMatchThis */
@@ -2476,11 +2484,11 @@ filter_exit:
*/
static int spellfix1FilterForFullScan(
spellfix1_cursor *pCur,
- int idxNum,
int argc,
sqlite3_value **argv
){
int rc = SQLITE_OK;
+ int idxNum = pCur->idxNum;
char *zSql;
spellfix1_vtab *pVTab = pCur->pVTab;
spellfix1ResetCursor(pCur);
@@ -2521,10 +2529,11 @@ static int spellfix1Filter(
){
spellfix1_cursor *pCur = (spellfix1_cursor *)cur;
int rc;
+ pCur->idxNum = idxNum;
if( idxNum & 1 ){
- rc = spellfix1FilterForMatch(pCur, idxNum, argc, argv);
+ rc = spellfix1FilterForMatch(pCur, argc, argv);
}else{
- rc = spellfix1FilterForFullScan(pCur, idxNum, argc, argv);
+ rc = spellfix1FilterForFullScan(pCur, argc, argv);
}
return rc;
}
diff --git a/lib/libsqlite3/ext/rtree/rtree1.test b/lib/libsqlite3/ext/rtree/rtree1.test
index 0beb16cc949..c9192de192e 100644
--- a/lib/libsqlite3/ext/rtree/rtree1.test
+++ b/lib/libsqlite3/ext/rtree/rtree1.test
@@ -34,6 +34,11 @@ set testprefix rtree1
#
# rtree-12.*: Test that on-conflict clauses are supported.
# rtree-13.*: Test that bug [d2889096e7bdeac6d] has been fixed.
+# rtree-14.*: Test if a non-integer is inserted into the PK column of an
+# r-tree table, it is converted to an integer before being
+# inserted. Also that if a non-numeric is inserted into one
+# of the min/max dimension columns, it is converted to the
+# required type before being inserted.
#
ifcapable !rtree {
@@ -535,4 +540,54 @@ do_execsql_test 13.2 {
SELECT * FROM r CROSS JOIN t9 WHERE id=x;
} {1 1 0.0 0.0 2 2 0.0 0.0}
+#-------------------------------------------------------------------------
+# Test if a non-integer is inserted into the PK column of an r-tree
+# table, it is converted to an integer before being inserted. Also
+# that if a non-numeric is inserted into one of the min/max dimension
+# columns, it is converted to the required type before being inserted.
+#
+do_execsql_test 14.1 {
+ CREATE VIRTUAL TABLE t10 USING rtree(ii, x1, x2);
+}
+
+do_execsql_test 14.2 {
+ INSERT INTO t10 VALUES(NULL, 1, 2);
+ INSERT INTO t10 VALUES(NULL, 2, 3);
+ INSERT INTO t10 VALUES('4xxx', 3, 4);
+ INSERT INTO t10 VALUES(5.0, 4, 5);
+ INSERT INTO t10 VALUES(6.4, 5, 6);
+}
+do_execsql_test 14.3 {
+ SELECT * FROM t10;
+} {
+ 1 1.0 2.0 2 2.0 3.0 4 3.0 4.0 5 4.0 5.0 6 5.0 6.0
+}
+
+do_execsql_test 14.4 {
+ DELETE FROM t10;
+ INSERT INTO t10 VALUES(1, 'one', 'two');
+ INSERT INTO t10 VALUES(2, '52xyz', '81...');
+}
+do_execsql_test 14.5 {
+ SELECT * FROM t10;
+} {
+ 1 0.0 0.0
+ 2 52.0 81.0
+}
+
+do_execsql_test 14.4 {
+ DROP TABLE t10;
+ CREATE VIRTUAL TABLE t10 USING rtree_i32(ii, x1, x2);
+ INSERT INTO t10 VALUES(1, 'one', 'two');
+ INSERT INTO t10 VALUES(2, '52xyz', '81...');
+ INSERT INTO t10 VALUES(3, 42.3, 49.9);
+}
+do_execsql_test 14.5 {
+ SELECT * FROM t10;
+} {
+ 1 0 0
+ 2 52 81
+ 3 42 49
+}
+
finish_test