diff options
author | drh <drh@noemail.net> | 2015-05-22 23:26:18 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2015-05-22 23:26:18 +0000 |
commit | 893ca50d0f3d8283883d373fe4591e6da048676d (patch) | |
tree | 4c7cd09124739481517a7691f59030fff443eca1 /src | |
parent | dbbd8160590680efbef189ea1d2284d944659931 (diff) | |
parent | 18070e08c5ec5048335df96e36019a6c778091e6 (diff) | |
download | sqlite-893ca50d0f3d8283883d373fe4591e6da048676d.tar.gz sqlite-893ca50d0f3d8283883d373fe4591e6da048676d.zip |
Merge enhancements from trunk, including the new sqlite3_value_dup() API and
the addition of the apSqlParam field in the sqlite3_rtree_query_info object
of R-Tree.
FossilOrigin-Name: cdc0ca6fb36e787b981fb544a27c6df838f85704
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 6 | ||||
-rw-r--r-- | src/build.c | 47 | ||||
-rw-r--r-- | src/insert.c | 2 | ||||
-rw-r--r-- | src/parse.y | 6 | ||||
-rw-r--r-- | src/select.c | 24 | ||||
-rw-r--r-- | src/sqlite.h.in | 27 | ||||
-rw-r--r-- | src/sqlite3ext.h | 5 | ||||
-rw-r--r-- | src/test_rtree.c | 48 | ||||
-rw-r--r-- | src/update.c | 4 | ||||
-rw-r--r-- | src/vdbeInt.h | 6 | ||||
-rw-r--r-- | src/vdbeapi.c | 30 | ||||
-rw-r--r-- | src/vdbemem.c | 4 |
12 files changed, 152 insertions, 57 deletions
diff --git a/src/btree.c b/src/btree.c index 4831657fc..6b7da394a 100644 --- a/src/btree.c +++ b/src/btree.c @@ -7860,7 +7860,8 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){ pgnoRoot==PENDING_BYTE_PAGE(pBt) ){ pgnoRoot++; } - assert( pgnoRoot>=3 ); + assert( pgnoRoot>=3 || CORRUPT_DB ); + testcase( pgnoRoot<3 ); /* Allocate a page. The page that currently resides at pgnoRoot will ** be moved to the allocated page (unless the allocated page happens @@ -8010,7 +8011,8 @@ static int clearDatabasePage( rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); if( rc ) goto cleardatabasepage_out; }else if( pnChange ){ - assert( pPage->intKey ); + assert( pPage->intKey || CORRUPT_DB ); + testcase( !pPage->intKey ); *pnChange += pPage->nCell; } if( freePageFlag ){ diff --git a/src/build.c b/src/build.c index 799056139..44d75e955 100644 --- a/src/build.c +++ b/src/build.c @@ -1913,26 +1913,45 @@ void sqlite3EndTable( ** be redundant. */ if( pSelect ){ - SelectDest dest; - Table *pSelTab; - + SelectDest dest; /* Where the SELECT should store results */ + int regYield; /* Register holding co-routine entry-point */ + int addrTop; /* Top of the co-routine */ + int regRec; /* A record to be insert into the new table */ + int regRowid; /* Rowid of the next row to insert */ + int addrInsLoop; /* Top of the loop for inserting rows */ + Table *pSelTab; /* A table that describes the SELECT results */ + + regYield = ++pParse->nMem; + regRec = ++pParse->nMem; + regRowid = ++pParse->nMem; assert(pParse->nTab==1); sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb); sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); pParse->nTab = 2; - sqlite3SelectDestInit(&dest, SRT_Table, 1); + addrTop = sqlite3VdbeCurrentAddr(v) + 1; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); + sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); sqlite3Select(pParse, pSelect, &dest); + sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); + sqlite3VdbeJumpHere(v, addrTop - 1); + if( pParse->nErr ) return; + pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect); + if( pSelTab==0 ) return; + assert( p->aCol==0 ); + p->nCol = pSelTab->nCol; + p->aCol = pSelTab->aCol; + pSelTab->nCol = 0; + pSelTab->aCol = 0; + sqlite3DeleteTable(db, pSelTab); + addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec); + sqlite3TableAffinity(v, p, 0); + sqlite3VdbeAddOp2(v, OP_NewRowid, 1, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrInsLoop); + sqlite3VdbeJumpHere(v, addrInsLoop); sqlite3VdbeAddOp1(v, OP_Close, 1); - if( pParse->nErr==0 ){ - pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect); - if( pSelTab==0 ) return; - assert( p->aCol==0 ); - p->nCol = pSelTab->nCol; - p->aCol = pSelTab->aCol; - pSelTab->nCol = 0; - pSelTab->aCol = 0; - sqlite3DeleteTable(db, pSelTab); - } } /* Compute the complete text of the CREATE statement */ diff --git a/src/insert.c b/src/insert.c index ea0d9537b..f9a680e96 100644 --- a/src/insert.c +++ b/src/insert.c @@ -42,7 +42,7 @@ void sqlite3OpenTable( }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); - assert( pPk->tnum=pTab->tnum ); + assert( pPk->tnum==pTab->tnum ); sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pPk); VdbeComment((v, "%s", pTab->zName)); diff --git a/src/parse.y b/src/parse.y index 6a64206ac..72a0a6d22 100644 --- a/src/parse.y +++ b/src/parse.y @@ -448,6 +448,7 @@ selectnowith(A) ::= oneselect(X). {A = X;} %ifndef SQLITE_OMIT_COMPOUND_SELECT selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). { Select *pRhs = Z; + Select *pLhs = X; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; @@ -458,11 +459,12 @@ selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). { } if( pRhs ){ pRhs->op = (u8)Y; - pRhs->pPrior = X; + pRhs->pPrior = pLhs; + if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; pRhs->selFlags &= ~SF_MultiValue; if( Y!=TK_ALL ) pParse->hasCompound = 1; }else{ - sqlite3SelectDelete(pParse->db, X); + sqlite3SelectDelete(pParse->db, pLhs); } A = pRhs; } diff --git a/src/select.c b/src/select.c index e8d9fdd5c..8fc2dbde3 100644 --- a/src/select.c +++ b/src/select.c @@ -816,6 +816,8 @@ static void selectInnerLoop( int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1); testcase( eDest==SRT_Table ); testcase( eDest==SRT_EphemTab ); + testcase( eDest==SRT_Fifo ); + testcase( eDest==SRT_DistFifo ); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg); #ifndef SQLITE_OMIT_CTE if( eDest==SRT_DistFifo ){ @@ -1231,10 +1233,7 @@ static void generateSortTail( VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan)); } switch( eDest ){ - case SRT_Table: case SRT_EphemTab: { - testcase( eDest==SRT_Table ); - testcase( eDest==SRT_EphemTab ); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); @@ -2583,15 +2582,14 @@ static int generateOutputSubroutine( */ codeOffset(v, p->iOffset, iContinue); + assert( pDest->eDest!=SRT_Exists ); + assert( pDest->eDest!=SRT_Table ); switch( pDest->eDest ){ /* Store the result as data using a unique key. */ - case SRT_Table: case SRT_EphemTab: { int r1 = sqlite3GetTempReg(pParse); int r2 = sqlite3GetTempReg(pParse); - testcase( pDest->eDest==SRT_Table ); - testcase( pDest->eDest==SRT_EphemTab ); sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1); sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iSDParm, r2); sqlite3VdbeAddOp3(v, OP_Insert, pDest->iSDParm, r1, r2); @@ -2619,16 +2617,6 @@ static int generateOutputSubroutine( break; } -#if 0 /* Never occurs on an ORDER BY query */ - /* If any row exist in the result set, record that fact and abort. - */ - case SRT_Exists: { - sqlite3VdbeAddOp2(v, OP_Integer, 1, pDest->iSDParm); - /* The LIMIT clause will terminate the loop for us */ - break; - } -#endif - /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. @@ -5523,9 +5511,9 @@ select_end: void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ int n = 0; pView = sqlite3TreeViewPush(pView, moreToFollow); - sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p)", + sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), - ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p + ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags ); if( p->pSrc && p->pSrc->nSrc ) n++; if( p->pWhere ) n++; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 382d3bd6c..ffa9de138 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -4294,12 +4294,12 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), #endif /* -** CAPI3REF: Obtaining SQL Function Parameter Values +** CAPI3REF: Obtaining SQL Values ** METHOD: sqlite3_value ** ** The C-language implementation of SQL functions and aggregates uses ** this set of interface routines to access the parameter values on -** the function or aggregate. +** the function or aggregate. ** ** The xFunc (for scalar functions) or xStep (for aggregates) parameters ** to [sqlite3_create_function()] and [sqlite3_create_function16()] @@ -4353,6 +4353,23 @@ int sqlite3_value_type(sqlite3_value*); int sqlite3_value_numeric_type(sqlite3_value*); /* +** CAPI3REF: Copy And Free SQL Values +** METHOD: sqlite3_value +** +** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value] +** object D and returns a pointer to that copy. ^The [sqlite3_value] returned +** is a [protected sqlite3_value] object even if the input is not. +** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a +** memory allocation fails. +** +** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object +** previously obtained from [sqlite_value_dup()]. ^If V is a NULL pointer +** then sqlite3_value_free(V) is a harmless no-op. +*/ +SQLITE_EXPERIMENTAL sqlite3_value *sqlite3_value_dup(const sqlite3_value*); +SQLITE_EXPERIMENTAL void sqlite3_value_free(sqlite3_value*); + +/* ** CAPI3REF: Obtain Aggregate Function Context ** METHOD: sqlite3_context ** @@ -5875,7 +5892,7 @@ int sqlite3_blob_open( ** ** ^This function sets the database handle error code and message. */ -SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); +int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); /* ** CAPI3REF: Close A BLOB Handle @@ -7685,7 +7702,7 @@ int sqlite3_vtab_on_conflict(sqlite3 *); ** ** See also: [sqlite3_stmt_scanstatus_reset()] */ -SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( +int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ int idx, /* Index of loop to report on */ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ @@ -7701,7 +7718,7 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( ** This API is only available if the library is built with pre-processor ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. */ -SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); +void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index f9a066592..5c4488c3b 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -267,6 +267,8 @@ struct sqlite3_api_routines { void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, void(*)(void*), unsigned char); int (*strglob)(const char*,const char*); + sqlite3_value (*value_dup)(const sqlite3_value*); + void (*value_free)(sqlite3_value*); }; /* @@ -497,6 +499,9 @@ struct sqlite3_api_routines { #define sqlite3_result_blob64 sqlite3_api->result_blob64 #define sqlite3_result_text64 sqlite3_api->result_text64 #define sqlite3_strglob sqlite3_api->strglob +/* Version 3.8.11 and later */ +#define sqlite3_value_dup sqlite3_api->value_dup +#define sqlite3_value_free sqlite3_api->value_free #endif /* SQLITE_CORE */ #ifndef SQLITE_CORE diff --git a/src/test_rtree.c b/src/test_rtree.c index 7beec6645..797ec0026 100644 --- a/src/test_rtree.c +++ b/src/test_rtree.c @@ -155,6 +155,11 @@ static int circle_geom( /* ** Implementation of "circle" r-tree geometry callback using the ** 2nd-generation interface that allows scoring. +** +** Two calling forms: +** +** Qcircle(X,Y,Radius,eType) -- All values are doubles +** Qcircle('x:X y:Y r:R e:ETYPE') -- Single string parameter */ static int circle_query_func(sqlite3_rtree_query_info *p){ int i; /* Iterator variable */ @@ -176,10 +181,9 @@ static int circle_query_func(sqlite3_rtree_query_info *p){ ** Return an error if the table does not have exactly 2 dimensions. */ if( p->nCoord!=4 ) return SQLITE_ERROR; - /* Test that the correct number of parameters (4) have been supplied, - ** and that the parameters are in range (that the radius of the circle - ** radius is greater than zero). */ - if( p->nParam!=4 || p->aParam[2]<0.0 ) return SQLITE_ERROR; + /* Test that the correct number of parameters (1 or 4) have been supplied. + */ + if( p->nParam!=4 && p->nParam!=1 ) return SQLITE_ERROR; /* Allocate a structure to cache parameter data in. Return SQLITE_NOMEM ** if the allocation fails. */ @@ -191,10 +195,38 @@ static int circle_query_func(sqlite3_rtree_query_info *p){ ** tested bounding boxes that intersect the circular region are detected ** is by testing if each corner of the bounding box lies within radius ** units of the center of the circle. */ - pCircle->centerx = p->aParam[0]; - pCircle->centery = p->aParam[1]; - pCircle->radius = p->aParam[2]; - pCircle->eScoreType = (int)p->aParam[3]; + if( p->nParam==4 ){ + pCircle->centerx = p->aParam[0]; + pCircle->centery = p->aParam[1]; + pCircle->radius = p->aParam[2]; + pCircle->eScoreType = (int)p->aParam[3]; + }else{ + const char *z = (const char*)sqlite3_value_text(p->apSqlParam[0]); + pCircle->centerx = 0.0; + pCircle->centery = 0.0; + pCircle->radius = 0.0; + pCircle->eScoreType = 0; + while( z && z[0] ){ + if( z[0]=='r' && z[1]==':' ){ + pCircle->radius = atof(&z[2]); + }else if( z[0]=='x' && z[1]==':' ){ + pCircle->centerx = atof(&z[2]); + }else if( z[0]=='y' && z[1]==':' ){ + pCircle->centery = atof(&z[2]); + }else if( z[0]=='e' && z[1]==':' ){ + pCircle->eScoreType = (int)atof(&z[2]); + }else if( z[0]==' ' ){ + z++; + continue; + } + while( z[0]!=0 && z[0]!=' ' ) z++; + while( z[0]==' ' ) z++; + } + } + if( pCircle->radius<0.0 ){ + sqlite3_free(pCircle); + return SQLITE_NOMEM; + } /* Define two bounding box regions. The first, aBox[0], extends to ** infinity in the X dimension. It covers the same range of the Y dimension diff --git a/src/update.c b/src/update.c index 7e7ceeb16..bb32eb74c 100644 --- a/src/update.c +++ b/src/update.c @@ -756,12 +756,10 @@ static void updateVirtualTable( */ assert( v ); ephemTab = pParse->nTab++; - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0)); - sqlite3VdbeChangeP5(v, BTREE_UNORDERED); /* fill the ephemeral table */ - sqlite3SelectDestInit(&dest, SRT_Table, ephemTab); + sqlite3SelectDestInit(&dest, SRT_EphemTab, ephemTab); sqlite3Select(pParse, pSelect, &dest); /* Generate code to scan the ephemeral table and call VUpdate. */ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 72e4a6b73..06ffd95b5 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -186,6 +186,12 @@ struct Mem { #endif }; +/* +** Size of struct Mem not including the Mem.zMalloc member or anything that +** follows. +*/ +#define MEMCELLSIZE offsetof(Mem,zMalloc) + /* One or more of the following flags are set to indicate the validOK ** representations of the value stored in the Mem struct. ** diff --git a/src/vdbeapi.c b/src/vdbeapi.c index e557d610e..fa5444cf2 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -212,6 +212,36 @@ int sqlite3_value_type(sqlite3_value* pVal){ return aType[pVal->flags&MEM_AffMask]; } +/* Make a copy of an sqlite3_value object +*/ +sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){ + sqlite3_value *pNew; + if( pOrig==0 ) return 0; + pNew = sqlite3_malloc( sizeof(*pNew) ); + if( pNew==0 ) return 0; + memset(pNew, 0, sizeof(*pNew)); + memcpy(pNew, pOrig, MEMCELLSIZE); + pNew->flags &= ~MEM_Dyn; + pNew->db = 0; + if( pNew->flags&(MEM_Str|MEM_Blob) ){ + pNew->flags &= ~(MEM_Static|MEM_Dyn); + pNew->flags |= MEM_Ephem; + if( sqlite3VdbeMemMakeWriteable(pNew)!=SQLITE_OK ){ + sqlite3ValueFree(pNew); + pNew = 0; + } + } + return pNew; +} + +/* Destroy an sqlite3_value object previously obtained from +** sqlite3_value_dup(). +*/ +void sqlite3_value_free(sqlite3_value *pOld){ + sqlite3ValueFree(pOld); +} + + /**************************** sqlite3_result_ ******************************* ** The following routines are used by user-defined functions to specify ** the function result. diff --git a/src/vdbemem.c b/src/vdbemem.c index 29a0445ae..1c1311d0c 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -770,10 +770,6 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ } #endif /* SQLITE_DEBUG */ -/* -** Size of struct Mem not including the Mem.zMalloc member. -*/ -#define MEMCELLSIZE offsetof(Mem,zMalloc) /* ** Make an shallow copy of pFrom into pTo. Prior contents of |