| Index: third_party/sqlite/sqlite-src-3100200/src/vtab.c
|
| diff --git a/third_party/sqlite/src/src/vtab.c b/third_party/sqlite/sqlite-src-3100200/src/vtab.c
|
| similarity index 87%
|
| copy from third_party/sqlite/src/src/vtab.c
|
| copy to third_party/sqlite/sqlite-src-3100200/src/vtab.c
|
| index faee4ae4788dd59b5fe99fe695712876a5483872..6054df3d710d06067da60002bc5410237e46791d 100644
|
| --- a/third_party/sqlite/src/src/vtab.c
|
| +++ b/third_party/sqlite/sqlite-src-3100200/src/vtab.c
|
| @@ -24,6 +24,8 @@
|
| struct VtabCtx {
|
| VTable *pVTable; /* The virtual table being constructed */
|
| Table *pTab; /* The Table object to which the virtual table belongs */
|
| + VtabCtx *pPrior; /* Parent context (if any) */
|
| + int bDeclared; /* True after sqlite3_declare_vtab() is called */
|
| };
|
|
|
| /*
|
| @@ -56,6 +58,7 @@ static int createModule(
|
| pMod->pModule = pModule;
|
| pMod->pAux = pAux;
|
| pMod->xDestroy = xDestroy;
|
| + pMod->pEpoTab = 0;
|
| pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
|
| assert( pDel==0 || pDel==pMod );
|
| if( pDel ){
|
| @@ -81,6 +84,9 @@ int sqlite3_create_module(
|
| const sqlite3_module *pModule, /* The definition of the module */
|
| void *pAux /* Context pointer for xCreate/xConnect */
|
| ){
|
| +#ifdef SQLITE_ENABLE_API_ARMOR
|
| + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
|
| +#endif
|
| return createModule(db, zName, pModule, pAux, 0);
|
| }
|
|
|
| @@ -94,6 +100,9 @@ int sqlite3_create_module_v2(
|
| void *pAux, /* Context pointer for xCreate/xConnect */
|
| void (*xDestroy)(void *) /* Module destructor function */
|
| ){
|
| +#ifdef SQLITE_ENABLE_API_ARMOR
|
| + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
|
| +#endif
|
| return createModule(db, zName, pModule, pAux, xDestroy);
|
| }
|
|
|
| @@ -277,23 +286,17 @@ void sqlite3VtabClear(sqlite3 *db, Table *p){
|
| ** deleted.
|
| */
|
| static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){
|
| - int i = pTable->nModuleArg++;
|
| - int nBytes = sizeof(char *)*(1+pTable->nModuleArg);
|
| + int nBytes = sizeof(char *)*(2+pTable->nModuleArg);
|
| char **azModuleArg;
|
| azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes);
|
| if( azModuleArg==0 ){
|
| - int j;
|
| - for(j=0; j<i; j++){
|
| - sqlite3DbFree(db, pTable->azModuleArg[j]);
|
| - }
|
| sqlite3DbFree(db, zArg);
|
| - sqlite3DbFree(db, pTable->azModuleArg);
|
| - pTable->nModuleArg = 0;
|
| }else{
|
| + int i = pTable->nModuleArg++;
|
| azModuleArg[i] = zArg;
|
| azModuleArg[i+1] = 0;
|
| + pTable->azModuleArg = azModuleArg;
|
| }
|
| - pTable->azModuleArg = azModuleArg;
|
| }
|
|
|
| /*
|
| @@ -326,7 +329,12 @@ void sqlite3VtabBeginParse(
|
| addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
|
| addModuleArgument(db, pTable, 0);
|
| addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
|
| - pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
|
| + assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0)
|
| + || (pParse->sNameToken.z==pName1->z && pName2->z==0)
|
| + );
|
| + pParse->sNameToken.n = (int)(
|
| + &pModuleName->z[pModuleName->n] - pParse->sNameToken.z
|
| + );
|
|
|
| #ifndef SQLITE_OMIT_AUTHORIZATION
|
| /* Creating a virtual table invokes the authorization callback twice.
|
| @@ -378,6 +386,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
| char *zStmt;
|
| char *zWhere;
|
| int iDb;
|
| + int iReg;
|
| Vdbe *v;
|
|
|
| /* Compute the complete text of the CREATE VIRTUAL TABLE statement */
|
| @@ -412,8 +421,10 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
| sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
|
| zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
|
| sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
|
| - sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
|
| - pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
|
| +
|
| + iReg = ++pParse->nMem;
|
| + sqlite3VdbeLoadString(v, iReg, pTab->zName);
|
| + sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
|
| }
|
|
|
| /* If we are rereading the sqlite_master table create the in-memory
|
| @@ -456,7 +467,7 @@ void sqlite3VtabArgExtend(Parse *pParse, Token *p){
|
| pArg->z = p->z;
|
| pArg->n = p->n;
|
| }else{
|
| - assert(pArg->z < p->z);
|
| + assert(pArg->z <= p->z);
|
| pArg->n = (int)(&p->z[p->n] - pArg->z);
|
| }
|
| }
|
| @@ -473,15 +484,27 @@ static int vtabCallConstructor(
|
| int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
|
| char **pzErr
|
| ){
|
| - VtabCtx sCtx, *pPriorCtx;
|
| + VtabCtx sCtx;
|
| VTable *pVTable;
|
| int rc;
|
| const char *const*azArg = (const char *const*)pTab->azModuleArg;
|
| int nArg = pTab->nModuleArg;
|
| char *zErr = 0;
|
| - char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
|
| + char *zModuleName;
|
| int iDb;
|
| + VtabCtx *pCtx;
|
| +
|
| + /* Check that the virtual-table is not already being initialized */
|
| + for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
|
| + if( pCtx->pTab==pTab ){
|
| + *pzErr = sqlite3MPrintf(db,
|
| + "vtable constructor called recursively: %s", pTab->zName
|
| + );
|
| + return SQLITE_LOCKED;
|
| + }
|
| + }
|
|
|
| + zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
|
| if( !zModuleName ){
|
| return SQLITE_NOMEM;
|
| }
|
| @@ -502,11 +525,13 @@ static int vtabCallConstructor(
|
| assert( xConstruct );
|
| sCtx.pTab = pTab;
|
| sCtx.pVTable = pVTable;
|
| - pPriorCtx = db->pVtabCtx;
|
| + sCtx.pPrior = db->pVtabCtx;
|
| + sCtx.bDeclared = 0;
|
| db->pVtabCtx = &sCtx;
|
| rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
|
| - db->pVtabCtx = pPriorCtx;
|
| + db->pVtabCtx = sCtx.pPrior;
|
| if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
| + assert( sCtx.pTab==pTab );
|
|
|
| if( SQLITE_OK!=rc ){
|
| if( zErr==0 ){
|
| @@ -522,13 +547,14 @@ static int vtabCallConstructor(
|
| memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0]));
|
| pVTable->pVtab->pModule = pMod->pModule;
|
| pVTable->nRef = 1;
|
| - if( sCtx.pTab ){
|
| + if( sCtx.bDeclared==0 ){
|
| const char *zFormat = "vtable constructor did not declare schema: %s";
|
| *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
|
| sqlite3VtabUnlock(pVTable);
|
| rc = SQLITE_ERROR;
|
| }else{
|
| int iCol;
|
| + u8 oooHidden = 0;
|
| /* If everything went according to plan, link the new VTable structure
|
| ** into the linked list headed by pTab->pVTable. Then loop through the
|
| ** columns of the table to see if any of them contain the token "hidden".
|
| @@ -541,7 +567,10 @@ static int vtabCallConstructor(
|
| char *zType = pTab->aCol[iCol].zType;
|
| int nType;
|
| int i = 0;
|
| - if( !zType ) continue;
|
| + if( !zType ){
|
| + pTab->tabFlags |= oooHidden;
|
| + continue;
|
| + }
|
| nType = sqlite3Strlen30(zType);
|
| if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){
|
| for(i=0; i<nType; i++){
|
| @@ -564,6 +593,9 @@ static int vtabCallConstructor(
|
| zType[i-1] = '\0';
|
| }
|
| pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN;
|
| + oooHidden = TF_OOOHidden;
|
| + }else{
|
| + pTab->tabFlags |= oooHidden;
|
| }
|
| }
|
| }
|
| @@ -667,7 +699,7 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
|
| ** invoke it now. If the module has not been registered, return an
|
| ** error. Otherwise, do nothing.
|
| */
|
| - if( !pMod ){
|
| + if( pMod==0 || pMod->pModule->xCreate==0 || pMod->pModule->xDestroy==0 ){
|
| *pzErr = sqlite3MPrintf(db, "no such module: %s", zMod);
|
| rc = SQLITE_ERROR;
|
| }else{
|
| @@ -692,18 +724,25 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
|
| ** virtual table module.
|
| */
|
| int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
| + VtabCtx *pCtx;
|
| Parse *pParse;
|
| -
|
| int rc = SQLITE_OK;
|
| Table *pTab;
|
| char *zErr = 0;
|
|
|
| +#ifdef SQLITE_ENABLE_API_ARMOR
|
| + if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
|
| + return SQLITE_MISUSE_BKPT;
|
| + }
|
| +#endif
|
| sqlite3_mutex_enter(db->mutex);
|
| - if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
|
| + pCtx = db->pVtabCtx;
|
| + if( !pCtx || pCtx->bDeclared ){
|
| sqlite3Error(db, SQLITE_MISUSE);
|
| sqlite3_mutex_leave(db->mutex);
|
| return SQLITE_MISUSE_BKPT;
|
| }
|
| + pTab = pCtx->pTab;
|
| assert( (pTab->tabFlags & TF_Virtual)!=0 );
|
|
|
| pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
|
| @@ -726,7 +765,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
| pParse->pNewTable->nCol = 0;
|
| pParse->pNewTable->aCol = 0;
|
| }
|
| - db->pVtabCtx->pTab = 0;
|
| + pCtx->bDeclared = 1;
|
| }else{
|
| sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
|
| sqlite3DbFree(db, zErr);
|
| @@ -761,11 +800,18 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
|
|
|
| pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
|
| if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
|
| - VTable *p = vtabDisconnectAll(db, pTab);
|
| -
|
| - assert( rc==SQLITE_OK );
|
| - rc = p->pMod->pModule->xDestroy(p->pVtab);
|
| -
|
| + VTable *p;
|
| + int (*xDestroy)(sqlite3_vtab *);
|
| + for(p=pTab->pVTable; p; p=p->pNext){
|
| + assert( p->pVtab );
|
| + if( p->pVtab->nRef>0 ){
|
| + return SQLITE_LOCKED;
|
| + }
|
| + }
|
| + p = vtabDisconnectAll(db, pTab);
|
| + xDestroy = p->pMod->pModule->xDestroy;
|
| + assert( xDestroy!=0 ); /* Checked before the virtual table is created */
|
| + rc = xDestroy(p->pVtab);
|
| /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
|
| if( rc==SQLITE_OK ){
|
| assert( pTab->pVTable==p && p->pNext==0 );
|
| @@ -789,8 +835,10 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
|
| static void callFinaliser(sqlite3 *db, int offset){
|
| int i;
|
| if( db->aVTrans ){
|
| + VTable **aVTrans = db->aVTrans;
|
| + db->aVTrans = 0;
|
| for(i=0; i<db->nVTrans; i++){
|
| - VTable *pVTab = db->aVTrans[i];
|
| + VTable *pVTab = aVTrans[i];
|
| sqlite3_vtab *p = pVTab->pVtab;
|
| if( p ){
|
| int (*x)(sqlite3_vtab *);
|
| @@ -800,9 +848,8 @@ static void callFinaliser(sqlite3 *db, int offset){
|
| pVTab->iSavepoint = 0;
|
| sqlite3VtabUnlock(pVTab);
|
| }
|
| - sqlite3DbFree(db, db->aVTrans);
|
| + sqlite3DbFree(db, aVTrans);
|
| db->nVTrans = 0;
|
| - db->aVTrans = 0;
|
| }
|
| }
|
|
|
| @@ -890,7 +937,9 @@ int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
|
| if( rc==SQLITE_OK ){
|
| rc = pModule->xBegin(pVTab->pVtab);
|
| if( rc==SQLITE_OK ){
|
| + int iSvpt = db->nStatement + db->nSavepoint;
|
| addToVTrans(db, pVTab);
|
| + if( iSvpt ) rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, iSvpt-1);
|
| }
|
| }
|
| }
|
| @@ -916,7 +965,7 @@ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
|
| int rc = SQLITE_OK;
|
|
|
| assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN );
|
| - assert( iSavepoint>=0 );
|
| + assert( iSavepoint>=-1 );
|
| if( db->aVTrans ){
|
| int i;
|
| for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
|
| @@ -1034,7 +1083,7 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
|
| if( pTab==pToplevel->apVtabLock[i] ) return;
|
| }
|
| n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
|
| - apVtabLock = sqlite3_realloc(pToplevel->apVtabLock, n);
|
| + apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n);
|
| if( apVtabLock ){
|
| pToplevel->apVtabLock = apVtabLock;
|
| pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
|
| @@ -1044,6 +1093,67 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
|
| }
|
|
|
| /*
|
| +** Check to see if virtual tale module pMod can be have an eponymous
|
| +** virtual table instance. If it can, create one if one does not already
|
| +** exist. Return non-zero if the eponymous virtual table instance exists
|
| +** when this routine returns, and return zero if it does not exist.
|
| +**
|
| +** An eponymous virtual table instance is one that is named after its
|
| +** module, and more importantly, does not require a CREATE VIRTUAL TABLE
|
| +** statement in order to come into existance. Eponymous virtual table
|
| +** instances always exist. They cannot be DROP-ed.
|
| +**
|
| +** Any virtual table module for which xConnect and xCreate are the same
|
| +** method can have an eponymous virtual table instance.
|
| +*/
|
| +int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
|
| + const sqlite3_module *pModule = pMod->pModule;
|
| + Table *pTab;
|
| + char *zErr = 0;
|
| + int nName;
|
| + int rc;
|
| + sqlite3 *db = pParse->db;
|
| + if( pMod->pEpoTab ) return 1;
|
| + if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0;
|
| + nName = sqlite3Strlen30(pMod->zName) + 1;
|
| + pTab = sqlite3DbMallocZero(db, sizeof(Table) + nName);
|
| + if( pTab==0 ) return 0;
|
| + pMod->pEpoTab = pTab;
|
| + pTab->zName = (char*)&pTab[1];
|
| + memcpy(pTab->zName, pMod->zName, nName);
|
| + pTab->nRef = 1;
|
| + pTab->pSchema = db->aDb[0].pSchema;
|
| + pTab->tabFlags |= TF_Virtual;
|
| + pTab->nModuleArg = 0;
|
| + pTab->iPKey = -1;
|
| + addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
|
| + addModuleArgument(db, pTab, 0);
|
| + addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
|
| + rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr);
|
| + if( rc ){
|
| + sqlite3ErrorMsg(pParse, "%s", zErr);
|
| + sqlite3DbFree(db, zErr);
|
| + sqlite3VtabEponymousTableClear(db, pMod);
|
| + return 0;
|
| + }
|
| + return 1;
|
| +}
|
| +
|
| +/*
|
| +** Erase the eponymous virtual table instance associated with
|
| +** virtual table module pMod, if it exists.
|
| +*/
|
| +void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
|
| + Table *pTab = pMod->pEpoTab;
|
| + if( pTab!=0 ){
|
| + sqlite3DeleteColumnNames(db, pTab);
|
| + sqlite3VtabClear(db, pTab);
|
| + sqlite3DbFree(db, pTab);
|
| + pMod->pEpoTab = 0;
|
| + }
|
| +}
|
| +
|
| +/*
|
| ** Return the ON CONFLICT resolution mode in effect for the virtual
|
| ** table update operation currently in progress.
|
| **
|
| @@ -1054,6 +1164,9 @@ int sqlite3_vtab_on_conflict(sqlite3 *db){
|
| static const unsigned char aMap[] = {
|
| SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
|
| };
|
| +#ifdef SQLITE_ENABLE_API_ARMOR
|
| + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
| +#endif
|
| assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 );
|
| assert( OE_Ignore==4 && OE_Replace==5 );
|
| assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 );
|
| @@ -1069,8 +1182,10 @@ int sqlite3_vtab_config(sqlite3 *db, int op, ...){
|
| va_list ap;
|
| int rc = SQLITE_OK;
|
|
|
| +#ifdef SQLITE_ENABLE_API_ARMOR
|
| + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
| +#endif
|
| sqlite3_mutex_enter(db->mutex);
|
| -
|
| va_start(ap, op);
|
| switch( op ){
|
| case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
|
|
|