| Index: third_party/sqlite/src/src/vtab.c | 
| diff --git a/third_party/sqlite/src/src/vtab.c b/third_party/sqlite/src/src/vtab.c | 
| index b052de23a5ff5c7b32511ab5faed98dbb4efcc07..faee4ae4788dd59b5fe99fe695712876a5483872 100644 | 
| --- a/third_party/sqlite/src/src/vtab.c | 
| +++ b/third_party/sqlite/src/src/vtab.c | 
| @@ -15,6 +15,18 @@ | 
| #include "sqliteInt.h" | 
|  | 
| /* | 
| +** Before a virtual table xCreate() or xConnect() method is invoked, the | 
| +** sqlite3.pVtabCtx member variable is set to point to an instance of | 
| +** this struct allocated on the stack. It is used by the implementation of | 
| +** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which | 
| +** are invoked only from within xCreate and xConnect methods. | 
| +*/ | 
| +struct VtabCtx { | 
| +  VTable *pVTable;    /* The virtual table being constructed */ | 
| +  Table *pTab;        /* The Table object to which the virtual table belongs */ | 
| +}; | 
| + | 
| +/* | 
| ** The actual function that does the work of creating a new module. | 
| ** This function implements the sqlite3_create_module() and | 
| ** sqlite3_create_module_v2() interfaces. | 
| @@ -26,33 +38,35 @@ static int createModule( | 
| void *pAux,                     /* Context pointer for xCreate/xConnect */ | 
| void (*xDestroy)(void *)        /* Module destructor function */ | 
| ){ | 
| -  int rc, nName; | 
| -  Module *pMod; | 
| +  int rc = SQLITE_OK; | 
| +  int nName; | 
|  | 
| sqlite3_mutex_enter(db->mutex); | 
| nName = sqlite3Strlen30(zName); | 
| -  pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1); | 
| -  if( pMod ){ | 
| -    Module *pDel; | 
| -    char *zCopy = (char *)(&pMod[1]); | 
| -    memcpy(zCopy, zName, nName+1); | 
| -    pMod->zName = zCopy; | 
| -    pMod->pModule = pModule; | 
| -    pMod->pAux = pAux; | 
| -    pMod->xDestroy = xDestroy; | 
| -    pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod); | 
| -    if( pDel && pDel->xDestroy ){ | 
| -      pDel->xDestroy(pDel->pAux); | 
| -    } | 
| -    sqlite3DbFree(db, pDel); | 
| -    if( pDel==pMod ){ | 
| -      db->mallocFailed = 1; | 
| +  if( sqlite3HashFind(&db->aModule, zName) ){ | 
| +    rc = SQLITE_MISUSE_BKPT; | 
| +  }else{ | 
| +    Module *pMod; | 
| +    pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1); | 
| +    if( pMod ){ | 
| +      Module *pDel; | 
| +      char *zCopy = (char *)(&pMod[1]); | 
| +      memcpy(zCopy, zName, nName+1); | 
| +      pMod->zName = zCopy; | 
| +      pMod->pModule = pModule; | 
| +      pMod->pAux = pAux; | 
| +      pMod->xDestroy = xDestroy; | 
| +      pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); | 
| +      assert( pDel==0 || pDel==pMod ); | 
| +      if( pDel ){ | 
| +        db->mallocFailed = 1; | 
| +        sqlite3DbFree(db, pDel); | 
| +      } | 
| } | 
| -    sqlite3ResetInternalSchema(db, -1); | 
| -  }else if( xDestroy ){ | 
| -    xDestroy(pAux); | 
| } | 
| -  rc = sqlite3ApiExit(db, SQLITE_OK); | 
| +  rc = sqlite3ApiExit(db, rc); | 
| +  if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux); | 
| + | 
| sqlite3_mutex_leave(db->mutex); | 
| return rc; | 
| } | 
| @@ -117,7 +131,7 @@ void sqlite3VtabUnlock(VTable *pVTab){ | 
|  | 
| assert( db ); | 
| assert( pVTab->nRef>0 ); | 
| -  assert( sqlite3SafetyCheckOk(db) ); | 
| +  assert( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ZOMBIE ); | 
|  | 
| pVTab->nRef--; | 
| if( pVTab->nRef==0 ){ | 
| @@ -168,6 +182,31 @@ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){ | 
| return pRet; | 
| } | 
|  | 
| +/* | 
| +** Table *p is a virtual table. This function removes the VTable object | 
| +** for table *p associated with database connection db from the linked | 
| +** list in p->pVTab. It also decrements the VTable ref count. This is | 
| +** used when closing database connection db to free all of its VTable | 
| +** objects without disturbing the rest of the Schema object (which may | 
| +** be being used by other shared-cache connections). | 
| +*/ | 
| +void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ | 
| +  VTable **ppVTab; | 
| + | 
| +  assert( IsVirtual(p) ); | 
| +  assert( sqlite3BtreeHoldsAllMutexes(db) ); | 
| +  assert( sqlite3_mutex_held(db->mutex) ); | 
| + | 
| +  for(ppVTab=&p->pVTable; *ppVTab; ppVTab=&(*ppVTab)->pNext){ | 
| +    if( (*ppVTab)->db==db  ){ | 
| +      VTable *pVTab = *ppVTab; | 
| +      *ppVTab = pVTab->pNext; | 
| +      sqlite3VtabUnlock(pVTab); | 
| +      break; | 
| +    } | 
| +  } | 
| +} | 
| + | 
|  | 
| /* | 
| ** Disconnect all the virtual table objects in the sqlite3.pDisconnect list. | 
| @@ -225,7 +264,7 @@ void sqlite3VtabClear(sqlite3 *db, Table *p){ | 
| if( p->azModuleArg ){ | 
| int i; | 
| for(i=0; i<p->nModuleArg; i++){ | 
| -      sqlite3DbFree(db, p->azModuleArg[i]); | 
| +      if( i!=1 ) sqlite3DbFree(db, p->azModuleArg[i]); | 
| } | 
| sqlite3DbFree(db, p->azModuleArg); | 
| } | 
| @@ -266,13 +305,14 @@ void sqlite3VtabBeginParse( | 
| Parse *pParse,        /* Parsing context */ | 
| Token *pName1,        /* Name of new table, or database name */ | 
| Token *pName2,        /* Name of new table or NULL */ | 
| -  Token *pModuleName    /* Name of the module for the virtual table */ | 
| +  Token *pModuleName,   /* Name of the module for the virtual table */ | 
| +  int ifNotExists       /* No error if the table already exists */ | 
| ){ | 
| int iDb;              /* The database the table is being created in */ | 
| Table *pTable;        /* The new virtual table */ | 
| sqlite3 *db;          /* Database connection */ | 
|  | 
| -  sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0); | 
| +  sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, ifNotExists); | 
| pTable = pParse->pNewTable; | 
| if( pTable==0 ) return; | 
| assert( 0==pTable->pIndex ); | 
| @@ -284,7 +324,7 @@ void sqlite3VtabBeginParse( | 
| pTable->tabFlags |= TF_Virtual; | 
| pTable->nModuleArg = 0; | 
| addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); | 
| -  addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName)); | 
| +  addModuleArgument(db, pTable, 0); | 
| addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); | 
| pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z); | 
|  | 
| @@ -307,7 +347,7 @@ void sqlite3VtabBeginParse( | 
| ** virtual table currently under construction in pParse->pTable. | 
| */ | 
| static void addArgumentToVtab(Parse *pParse){ | 
| -  if( pParse->sArg.z && ALWAYS(pParse->pNewTable) ){ | 
| +  if( pParse->sArg.z && pParse->pNewTable ){ | 
| const char *z = (const char*)pParse->sArg.z; | 
| int n = pParse->sArg.n; | 
| sqlite3 *db = pParse->db; | 
| @@ -371,7 +411,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ | 
|  | 
| sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); | 
| zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName); | 
| -    sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); | 
| +    sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); | 
| sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0, | 
| pTab->zName, sqlite3Strlen30(pTab->zName) + 1); | 
| } | 
| @@ -385,9 +425,8 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ | 
| Table *pOld; | 
| Schema *pSchema = pTab->pSchema; | 
| const char *zName = pTab->zName; | 
| -    int nName = sqlite3Strlen30(zName); | 
| assert( sqlite3SchemaMutexHeld(db, 0, pSchema) ); | 
| -    pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); | 
| +    pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); | 
| if( pOld ){ | 
| db->mallocFailed = 1; | 
| assert( pTab==pOld );  /* Malloc must have failed inside HashInsert() */ | 
| @@ -434,12 +473,14 @@ static int vtabCallConstructor( | 
| int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), | 
| char **pzErr | 
| ){ | 
| +  VtabCtx sCtx, *pPriorCtx; | 
| 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); | 
| +  int iDb; | 
|  | 
| if( !zModuleName ){ | 
| return SQLITE_NOMEM; | 
| @@ -453,12 +494,18 @@ static int vtabCallConstructor( | 
| pVTable->db = db; | 
| pVTable->pMod = pMod; | 
|  | 
| -  assert( !db->pVTab ); | 
| -  assert( xConstruct ); | 
| -  db->pVTab = pTab; | 
| +  iDb = sqlite3SchemaToIndex(db, pTab->pSchema); | 
| +  pTab->azModuleArg[1] = db->aDb[iDb].zName; | 
|  | 
| /* Invoke the virtual table constructor */ | 
| +  assert( &db->pVtabCtx ); | 
| +  assert( xConstruct ); | 
| +  sCtx.pTab = pTab; | 
| +  sCtx.pVTable = pVTable; | 
| +  pPriorCtx = db->pVtabCtx; | 
| +  db->pVtabCtx = &sCtx; | 
| rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); | 
| +  db->pVtabCtx = pPriorCtx; | 
| if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; | 
|  | 
| if( SQLITE_OK!=rc ){ | 
| @@ -472,9 +519,10 @@ static int vtabCallConstructor( | 
| }else if( ALWAYS(pVTable->pVtab) ){ | 
| /* Justification of ALWAYS():  A correct vtab constructor must allocate | 
| ** the sqlite3_vtab object if successful.  */ | 
| +    memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); | 
| pVTable->pVtab->pModule = pMod->pModule; | 
| pVTable->nRef = 1; | 
| -    if( db->pVTab ){ | 
| +    if( sCtx.pTab ){ | 
| const char *zFormat = "vtable constructor did not declare schema: %s"; | 
| *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); | 
| sqlite3VtabUnlock(pVTable); | 
| @@ -484,7 +532,7 @@ static int vtabCallConstructor( | 
| /* 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". | 
| -      ** If so, set the Column.isHidden flag and remove the token from | 
| +      ** If so, set the Column COLFLAG_HIDDEN flag and remove the token from | 
| ** the type string.  */ | 
| pVTable->pNext = pTab->pVTable; | 
| pTab->pVTable = pVTable; | 
| @@ -515,14 +563,13 @@ static int vtabCallConstructor( | 
| assert(zType[i-1]==' '); | 
| zType[i-1] = '\0'; | 
| } | 
| -          pTab->aCol[iCol].isHidden = 1; | 
| +          pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN; | 
| } | 
| } | 
| } | 
| } | 
|  | 
| sqlite3DbFree(db, zModuleName); | 
| -  db->pVTab = 0; | 
| return rc; | 
| } | 
|  | 
| @@ -546,7 +593,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ | 
|  | 
| /* Locate the required virtual table module */ | 
| zMod = pTab->azModuleArg[0]; | 
| -  pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod)); | 
| +  pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); | 
|  | 
| if( !pMod ){ | 
| const char *zModule = pTab->azModuleArg[0]; | 
| @@ -563,11 +610,11 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ | 
|  | 
| return rc; | 
| } | 
| - | 
| /* | 
| -** Add the virtual table pVTab to the array sqlite3.aVTrans[]. | 
| +** Grow the db->aVTrans[] array so that there is room for at least one | 
| +** more v-table. Return SQLITE_NOMEM if a malloc fails, or SQLITE_OK otherwise. | 
| */ | 
| -static int addToVTrans(sqlite3 *db, VTable *pVTab){ | 
| +static int growVTrans(sqlite3 *db){ | 
| const int ARRAY_INCR = 5; | 
|  | 
| /* Grow the sqlite3.aVTrans array if required */ | 
| @@ -582,10 +629,17 @@ static int addToVTrans(sqlite3 *db, VTable *pVTab){ | 
| db->aVTrans = aVTrans; | 
| } | 
|  | 
| +  return SQLITE_OK; | 
| +} | 
| + | 
| +/* | 
| +** Add the virtual table pVTab to the array sqlite3.aVTrans[]. Space should | 
| +** have already been reserved using growVTrans(). | 
| +*/ | 
| +static void addToVTrans(sqlite3 *db, VTable *pVTab){ | 
| /* Add pVtab to the end of sqlite3.aVTrans */ | 
| db->aVTrans[db->nVTrans++] = pVTab; | 
| sqlite3VtabLock(pVTab); | 
| -  return SQLITE_OK; | 
| } | 
|  | 
| /* | 
| @@ -607,7 +661,7 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ | 
|  | 
| /* Locate the required virtual table module */ | 
| zMod = pTab->azModuleArg[0]; | 
| -  pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod)); | 
| +  pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); | 
|  | 
| /* If the module has been registered and includes a Create method, | 
| ** invoke it now. If the module has not been registered, return an | 
| @@ -623,7 +677,10 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ | 
| /* Justification of ALWAYS():  The xConstructor method is required to | 
| ** create a valid sqlite3_vtab if it returns SQLITE_OK. */ | 
| if( rc==SQLITE_OK && ALWAYS(sqlite3GetVTable(db, pTab)) ){ | 
| -      rc = addToVTrans(db, sqlite3GetVTable(db, pTab)); | 
| +    rc = growVTrans(db); | 
| +    if( rc==SQLITE_OK ){ | 
| +      addToVTrans(db, sqlite3GetVTable(db, pTab)); | 
| +    } | 
| } | 
|  | 
| return rc; | 
| @@ -642,9 +699,8 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ | 
| char *zErr = 0; | 
|  | 
| sqlite3_mutex_enter(db->mutex); | 
| -  pTab = db->pVTab; | 
| -  if( !pTab ){ | 
| -    sqlite3Error(db, SQLITE_MISUSE, 0); | 
| +  if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){ | 
| +    sqlite3Error(db, SQLITE_MISUSE); | 
| sqlite3_mutex_leave(db->mutex); | 
| return SQLITE_MISUSE_BKPT; | 
| } | 
| @@ -670,9 +726,9 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ | 
| pParse->pNewTable->nCol = 0; | 
| pParse->pNewTable->aCol = 0; | 
| } | 
| -      db->pVTab = 0; | 
| +      db->pVtabCtx->pTab = 0; | 
| }else{ | 
| -      sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); | 
| +      sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); | 
| sqlite3DbFree(db, zErr); | 
| rc = SQLITE_ERROR; | 
| } | 
| @@ -682,6 +738,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ | 
| sqlite3VdbeFinalize(pParse->pVdbe); | 
| } | 
| sqlite3DeleteTable(db, pParse->pNewTable); | 
| +    sqlite3ParserReset(pParse); | 
| sqlite3StackFree(db, pParse); | 
| } | 
|  | 
| @@ -740,6 +797,7 @@ static void callFinaliser(sqlite3 *db, int offset){ | 
| x = *(int (**)(sqlite3_vtab *))((char *)p->pModule + offset); | 
| if( x ) x(p); | 
| } | 
| +      pVTab->iSavepoint = 0; | 
| sqlite3VtabUnlock(pVTab); | 
| } | 
| sqlite3DbFree(db, db->aVTrans); | 
| @@ -753,10 +811,9 @@ static void callFinaliser(sqlite3 *db, int offset){ | 
| ** array. Return the error code for the first error that occurs, or | 
| ** SQLITE_OK if all xSync operations are successful. | 
| ** | 
| -** Set *pzErrmsg to point to a buffer that should be released using | 
| -** sqlite3DbFree() containing an error message, if one is available. | 
| +** If an error message is available, leave it in p->zErrMsg. | 
| */ | 
| -int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){ | 
| +int sqlite3VtabSync(sqlite3 *db, Vdbe *p){ | 
| int i; | 
| int rc = SQLITE_OK; | 
| VTable **aVTrans = db->aVTrans; | 
| @@ -767,9 +824,7 @@ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){ | 
| sqlite3_vtab *pVtab = aVTrans[i]->pVtab; | 
| if( pVtab && (x = pVtab->pModule->xSync)!=0 ){ | 
| rc = x(pVtab); | 
| -      sqlite3DbFree(db, *pzErrmsg); | 
| -      *pzErrmsg = sqlite3DbStrDup(db, pVtab->zErrMsg); | 
| -      sqlite3_free(pVtab->zErrMsg); | 
| +      sqlite3VtabImportErrmsg(p, pVtab); | 
| } | 
| } | 
| db->aVTrans = aVTrans; | 
| @@ -822,7 +877,6 @@ int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ | 
| if( pModule->xBegin ){ | 
| int i; | 
|  | 
| - | 
| /* If pVtab is already in the aVTrans array, return early */ | 
| for(i=0; i<db->nVTrans; i++){ | 
| if( db->aVTrans[i]==pVTab ){ | 
| @@ -830,10 +884,62 @@ int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ | 
| } | 
| } | 
|  | 
| -    /* Invoke the xBegin method */ | 
| -    rc = pModule->xBegin(pVTab->pVtab); | 
| +    /* Invoke the xBegin method. If successful, add the vtab to the | 
| +    ** sqlite3.aVTrans[] array. */ | 
| +    rc = growVTrans(db); | 
| if( rc==SQLITE_OK ){ | 
| -      rc = addToVTrans(db, pVTab); | 
| +      rc = pModule->xBegin(pVTab->pVtab); | 
| +      if( rc==SQLITE_OK ){ | 
| +        addToVTrans(db, pVTab); | 
| +      } | 
| +    } | 
| +  } | 
| +  return rc; | 
| +} | 
| + | 
| +/* | 
| +** Invoke either the xSavepoint, xRollbackTo or xRelease method of all | 
| +** virtual tables that currently have an open transaction. Pass iSavepoint | 
| +** as the second argument to the virtual table method invoked. | 
| +** | 
| +** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is | 
| +** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is | 
| +** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with | 
| +** an open transaction is invoked. | 
| +** | 
| +** If any virtual table method returns an error code other than SQLITE_OK, | 
| +** processing is abandoned and the error returned to the caller of this | 
| +** function immediately. If all calls to virtual table methods are successful, | 
| +** SQLITE_OK is returned. | 
| +*/ | 
| +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 ); | 
| +  if( db->aVTrans ){ | 
| +    int i; | 
| +    for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){ | 
| +      VTable *pVTab = db->aVTrans[i]; | 
| +      const sqlite3_module *pMod = pVTab->pMod->pModule; | 
| +      if( pVTab->pVtab && pMod->iVersion>=2 ){ | 
| +        int (*xMethod)(sqlite3_vtab *, int); | 
| +        switch( op ){ | 
| +          case SAVEPOINT_BEGIN: | 
| +            xMethod = pMod->xSavepoint; | 
| +            pVTab->iSavepoint = iSavepoint+1; | 
| +            break; | 
| +          case SAVEPOINT_ROLLBACK: | 
| +            xMethod = pMod->xRollbackTo; | 
| +            break; | 
| +          default: | 
| +            xMethod = pMod->xRelease; | 
| +            break; | 
| +        } | 
| +        if( xMethod && pVTab->iSavepoint>iSavepoint ){ | 
| +          rc = xMethod(pVTab->pVtab, iSavepoint); | 
| +        } | 
| +      } | 
| } | 
| } | 
| return rc; | 
| @@ -908,7 +1014,7 @@ FuncDef *sqlite3VtabOverloadFunction( | 
| memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1); | 
| pNew->xFunc = xFunc; | 
| pNew->pUserData = pArg; | 
| -  pNew->flags |= SQLITE_FUNC_EPHEM; | 
| +  pNew->funcFlags |= SQLITE_FUNC_EPHEM; | 
| return pNew; | 
| } | 
|  | 
| @@ -937,4 +1043,55 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ | 
| } | 
| } | 
|  | 
| +/* | 
| +** Return the ON CONFLICT resolution mode in effect for the virtual | 
| +** table update operation currently in progress. | 
| +** | 
| +** The results of this routine are undefined unless it is called from | 
| +** within an xUpdate method. | 
| +*/ | 
| +int sqlite3_vtab_on_conflict(sqlite3 *db){ | 
| +  static const unsigned char aMap[] = { | 
| +    SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE | 
| +  }; | 
| +  assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 ); | 
| +  assert( OE_Ignore==4 && OE_Replace==5 ); | 
| +  assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 ); | 
| +  return (int)aMap[db->vtabOnConflict-1]; | 
| +} | 
| + | 
| +/* | 
| +** Call from within the xCreate() or xConnect() methods to provide | 
| +** the SQLite core with additional information about the behavior | 
| +** of the virtual table being implemented. | 
| +*/ | 
| +int sqlite3_vtab_config(sqlite3 *db, int op, ...){ | 
| +  va_list ap; | 
| +  int rc = SQLITE_OK; | 
| + | 
| +  sqlite3_mutex_enter(db->mutex); | 
| + | 
| +  va_start(ap, op); | 
| +  switch( op ){ | 
| +    case SQLITE_VTAB_CONSTRAINT_SUPPORT: { | 
| +      VtabCtx *p = db->pVtabCtx; | 
| +      if( !p ){ | 
| +        rc = SQLITE_MISUSE_BKPT; | 
| +      }else{ | 
| +        assert( p->pTab==0 || (p->pTab->tabFlags & TF_Virtual)!=0 ); | 
| +        p->pVTable->bConstraint = (u8)va_arg(ap, int); | 
| +      } | 
| +      break; | 
| +    } | 
| +    default: | 
| +      rc = SQLITE_MISUSE_BKPT; | 
| +      break; | 
| +  } | 
| +  va_end(ap); | 
| + | 
| +  if( rc!=SQLITE_OK ) sqlite3Error(db, rc); | 
| +  sqlite3_mutex_leave(db->mutex); | 
| +  return rc; | 
| +} | 
| + | 
| #endif /* SQLITE_OMIT_VIRTUALTABLE */ | 
|  |