diff options
| author | Scott MacVicar <scottmac@php.net> | 2008-03-07 10:55:14 +0000 |
|---|---|---|
| committer | Scott MacVicar <scottmac@php.net> | 2008-03-07 10:55:14 +0000 |
| commit | 31dade5280849135b00fd1c5e53d057732a72776 (patch) | |
| tree | 564b9f0f9d8cf89d7df9a9c12147ba8a5da6506f /ext/pdo_sqlite/sqlite/src/vtab.c | |
| parent | 7abf0787ad9fd613ddde880c9bc163161d7bf4ff (diff) | |
| download | php-git-31dade5280849135b00fd1c5e53d057732a72776.tar.gz | |
MFB: Update bundled SQLite to 3.5.6
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/vtab.c')
| -rw-r--r-- | ext/pdo_sqlite/sqlite/src/vtab.c | 303 |
1 files changed, 221 insertions, 82 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/vtab.c b/ext/pdo_sqlite/sqlite/src/vtab.c index 1f236246a7..1ffe2c8b8e 100644 --- a/ext/pdo_sqlite/sqlite/src/vtab.c +++ b/ext/pdo_sqlite/sqlite/src/vtab.c @@ -1,5 +1,5 @@ /* -** 2007 June 10 +** 2006 June 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -16,28 +16,93 @@ #ifndef SQLITE_OMIT_VIRTUALTABLE #include "sqliteInt.h" -/* -** External API function used to create a new virtual-table module. -*/ -int sqlite3_create_module( +static int createModule( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ - void *pAux /* Context pointer for xCreate/xConnect */ -){ - int nName = strlen(zName); - Module *pMod = (Module *)sqliteMallocRaw(sizeof(Module) + nName + 1); + void *pAux, /* Context pointer for xCreate/xConnect */ + void (*xDestroy)(void *) /* Module destructor function */ +) { + int rc, nName; + Module *pMod; + + sqlite3_mutex_enter(db->mutex); + nName = strlen(zName); + pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1); if( pMod ){ char *zCopy = (char *)(&pMod[1]); - strcpy(zCopy, zName); + memcpy(zCopy, zName, nName+1); pMod->zName = zCopy; pMod->pModule = pModule; pMod->pAux = pAux; + pMod->xDestroy = xDestroy; pMod = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod); - sqliteFree(pMod); + if( pMod && pMod->xDestroy ){ + pMod->xDestroy(pMod->pAux); + } + sqlite3_free(pMod); sqlite3ResetInternalSchema(db, 0); } - return sqlite3ApiExit(db, SQLITE_OK); + rc = sqlite3ApiExit(db, SQLITE_OK); + sqlite3_mutex_leave(db->mutex); + return rc; +} + + +/* +** External API function used to create a new virtual-table module. +*/ +int sqlite3_create_module( + sqlite3 *db, /* Database in which module is registered */ + const char *zName, /* Name assigned to this module */ + const sqlite3_module *pModule, /* The definition of the module */ + void *pAux /* Context pointer for xCreate/xConnect */ +){ + return createModule(db, zName, pModule, pAux, 0); +} + +/* +** External API function used to create a new virtual-table module. +*/ +int sqlite3_create_module_v2( + sqlite3 *db, /* Database in which module is registered */ + const char *zName, /* Name assigned to this module */ + const sqlite3_module *pModule, /* The definition of the module */ + void *pAux, /* Context pointer for xCreate/xConnect */ + void (*xDestroy)(void *) /* Module destructor function */ +){ + return createModule(db, zName, pModule, pAux, xDestroy); +} + +/* +** Lock the virtual table so that it cannot be disconnected. +** Locks nest. Every lock should have a corresponding unlock. +** If an unlock is omitted, resources leaks will occur. +** +** If a disconnect is attempted while a virtual table is locked, +** the disconnect is deferred until all locks have been removed. +*/ +void sqlite3VtabLock(sqlite3_vtab *pVtab){ + pVtab->nRef++; +} + +/* +** Unlock a virtual table. When the last lock is removed, +** disconnect the virtual table. +*/ +void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){ + pVtab->nRef--; + assert(db); + assert( sqlite3SafetyCheckOk(db) ); + if( pVtab->nRef==0 ){ + if( db->magic==SQLITE_MAGIC_BUSY ){ + (void)sqlite3SafetyOff(db); + pVtab->pModule->xDisconnect(pVtab); + (void)sqlite3SafetyOn(db); + } else { + pVtab->pModule->xDisconnect(pVtab); + } + } } /* @@ -49,18 +114,15 @@ void sqlite3VtabClear(Table *p){ sqlite3_vtab *pVtab = p->pVtab; if( pVtab ){ assert( p->pMod && p->pMod->pModule ); - pVtab->nRef--; - if( pVtab->nRef==0 ){ - pVtab->pModule->xDisconnect(pVtab); - } + sqlite3VtabUnlock(p->pSchema->db, pVtab); p->pVtab = 0; } if( p->azModuleArg ){ int i; for(i=0; i<p->nModuleArg; i++){ - sqliteFree(p->azModuleArg[i]); + sqlite3_free(p->azModuleArg[i]); } - sqliteFree(p->azModuleArg); + sqlite3_free(p->azModuleArg); } } @@ -70,18 +132,18 @@ void sqlite3VtabClear(Table *p){ ** string will be freed automatically when the table is ** deleted. */ -static void addModuleArgument(Table *pTable, char *zArg){ +static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){ int i = pTable->nModuleArg++; int nBytes = sizeof(char *)*(1+pTable->nModuleArg); char **azModuleArg; - azModuleArg = sqliteRealloc(pTable->azModuleArg, nBytes); + azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes); if( azModuleArg==0 ){ int j; for(j=0; j<i; j++){ - sqliteFree(pTable->azModuleArg[j]); + sqlite3_free(pTable->azModuleArg[j]); } - sqliteFree(zArg); - sqliteFree(pTable->azModuleArg); + sqlite3_free(zArg); + sqlite3_free(pTable->azModuleArg); pTable->nModuleArg = 0; }else{ azModuleArg[i] = zArg; @@ -103,20 +165,27 @@ void sqlite3VtabBeginParse( ){ int iDb; /* The database the table is being created in */ Table *pTable; /* The new virtual table */ + sqlite3 *db; /* Database connection */ + + if( pParse->db->flags & SQLITE_SharedCache ){ + sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode"); + return; + } sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0); pTable = pParse->pNewTable; if( pTable==0 || pParse->nErr ) return; assert( 0==pTable->pIndex ); - iDb = sqlite3SchemaToIndex(pParse->db, pTable->pSchema); + db = pParse->db; + iDb = sqlite3SchemaToIndex(db, pTable->pSchema); assert( iDb>=0 ); pTable->isVirtual = 1; pTable->nModuleArg = 0; - addModuleArgument(pTable, sqlite3NameFromToken(pModuleName)); - addModuleArgument(pTable, sqlite3StrDup(pParse->db->aDb[iDb].zName)); - addModuleArgument(pTable, sqlite3StrDup(pTable->zName)); + addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); + addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName)); + addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); pParse->sNameToken.n = pModuleName->z + pModuleName->n - pName1->z; #ifndef SQLITE_OMIT_AUTHORIZATION @@ -139,9 +208,10 @@ void sqlite3VtabBeginParse( */ static void addArgumentToVtab(Parse *pParse){ if( pParse->sArg.z && pParse->pNewTable ){ - const char *z = pParse->sArg.z; + const char *z = (const char*)pParse->sArg.z; int n = pParse->sArg.n; - addModuleArgument(pParse->pNewTable, sqliteStrNDup(z, n)); + sqlite3 *db = pParse->db; + addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); } } @@ -183,35 +253,36 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ if( pEnd ){ pParse->sNameToken.n = pEnd->z - pParse->sNameToken.z + pEnd->n; } - zStmt = sqlite3MPrintf("CREATE VIRTUAL TABLE %T", &pParse->sNameToken); + zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken); /* A slot for the record has already been allocated in the ** SQLITE_MASTER table. We just need to update that slot with all ** the information we've collected. ** - ** The top of the stack is the rootpage allocated by sqlite3StartTable(). - ** This value is always 0 and is ignored, a virtual table does not have a - ** rootpage. The next entry on the stack is the rowid of the record - ** in the sqlite_master table. + ** The VM register number pParse->regRowid holds the rowid of an + ** entry in the sqlite_master table tht was created for this vtab + ** by sqlite3StartTable(). */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " - "WHERE rowid=#1", + "WHERE rowid=#%d", db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTab->zName, pTab->zName, - zStmt + zStmt, + pParse->regRowid ); - sqliteFree(zStmt); + sqlite3_free(zStmt); v = sqlite3GetVdbe(pParse); - sqlite3ChangeCookie(db, v, iDb); + sqlite3ChangeCookie(pParse, iDb); - sqlite3VdbeAddOp(v, OP_Expire, 0, 0); - zWhere = sqlite3MPrintf("name='%q'", pTab->zName); - sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC); - sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1); + sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); + zWhere = sqlite3MPrintf(db, "name='%q'", pTab->zName); + sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 1, 0, zWhere, P4_DYNAMIC); + sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0, + pTab->zName, strlen(pTab->zName) + 1); } /* If we are rereading the sqlite_master table create the in-memory @@ -225,9 +296,11 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ int nName = strlen(zName) + 1; pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); if( pOld ){ + db->mallocFailed = 1; assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ return; } + pSchema->db = pParse->db; pParse->pNewTable = 0; } } @@ -266,14 +339,20 @@ static int vtabCallConstructor( sqlite3 *db, Table *pTab, Module *pMod, - int (*xConstruct)(sqlite3*, void *, int, char **, sqlite3_vtab **), + int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), char **pzErr ){ int rc; int rc2; - char **azArg = pTab->azModuleArg; + sqlite3_vtab *pVtab = 0; + const char *const*azArg = (const char *const*)pTab->azModuleArg; int nArg = pTab->nModuleArg; - char *zErr = sqlite3MPrintf("vtable constructor failed: %s", pTab->zName); + char *zErr = 0; + char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); + + if( !zModuleName ){ + return SQLITE_NOMEM; + } assert( !db->pVTab ); assert( xConstruct ); @@ -281,26 +360,69 @@ static int vtabCallConstructor( db->pVTab = pTab; rc = sqlite3SafetyOff(db); assert( rc==SQLITE_OK ); - rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab); + rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr); rc2 = sqlite3SafetyOn(db); - if( rc==SQLITE_OK && pTab->pVtab ){ - pTab->pVtab->pModule = pMod->pModule; - pTab->pVtab->nRef = 1; + if( rc==SQLITE_OK && pVtab ){ + pVtab->pModule = pMod->pModule; + pVtab->nRef = 1; + pTab->pVtab = pVtab; } if( SQLITE_OK!=rc ){ - *pzErr = zErr; - zErr = 0; - } else if( db->pVTab ){ + if( zErr==0 ){ + *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); + }else { + *pzErr = sqlite3MPrintf(db, "%s", zErr); + sqlite3_free(zErr); + } + }else if( db->pVTab ){ const char *zFormat = "vtable constructor did not declare schema: %s"; - *pzErr = sqlite3MPrintf(zFormat, pTab->zName); + *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); rc = SQLITE_ERROR; } if( rc==SQLITE_OK ){ rc = rc2; } db->pVTab = 0; - sqliteFree(zErr); + sqlite3_free(zModuleName); + + /* If everything went according to plan, 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 + ** the type string. + */ + if( rc==SQLITE_OK ){ + int iCol; + for(iCol=0; iCol<pTab->nCol; iCol++){ + char *zType = pTab->aCol[iCol].zType; + int nType; + int i = 0; + if( !zType ) continue; + nType = strlen(zType); + if( sqlite3StrNICmp("hidden", zType, 6) || (zType[6] && zType[6]!=' ') ){ + for(i=0; i<nType; i++){ + if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7)) + && (zType[i+7]=='\0' || zType[i+7]==' ') + ){ + i++; + break; + } + } + } + if( i<nType ){ + int j; + int nDel = 6 + (zType[i+6] ? 1 : 0); + for(j=i; (j+nDel)<=nType; j++){ + zType[j] = zType[j+nDel]; + } + if( zType[i]=='\0' && i>0 ){ + assert(zType[i-1]==' '); + zType[i-1] = '\0'; + } + pTab->aCol[iCol].isHidden = 1; + } + } + } return rc; } @@ -313,7 +435,6 @@ static int vtabCallConstructor( */ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ Module *pMod; - const char *zModule; int rc = SQLITE_OK; if( !pTab || !pTab->isVirtual || pTab->pVtab ){ @@ -321,7 +442,6 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ } pMod = pTab->pMod; - zModule = pTab->azModuleArg[0]; if( !pMod ){ const char *zModule = pTab->azModuleArg[0]; sqlite3ErrorMsg(pParse, "no such module: %s", zModule); @@ -333,7 +453,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "%s", zErr); } - sqliteFree(zErr); + sqlite3_free(zErr); } return rc; @@ -349,7 +469,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){ if( (db->nVTrans%ARRAY_INCR)==0 ){ sqlite3_vtab **aVTrans; int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR); - aVTrans = sqliteRealloc((void *)db->aVTrans, nBytes); + aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes); if( !aVTrans ){ return SQLITE_NOMEM; } @@ -359,7 +479,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){ /* Add pVtab to the end of sqlite3.aVTrans */ db->aVTrans[db->nVTrans++] = pVtab; - pVtab->nRef++; + sqlite3VtabLock(pVtab); return SQLITE_OK; } @@ -369,7 +489,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){ ** ** If an error occurs, *pzErr is set to point an an English language ** description of the error and an SQLITE_XXX error code is returned. -** In this case the caller must call sqliteFree() on *pzErr. +** In this case the caller must call sqlite3_free() on *pzErr. */ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ int rc = SQLITE_OK; @@ -387,7 +507,7 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ ** error. Otherwise, do nothing. */ if( !pMod ){ - *pzErr = sqlite3MPrintf("no such module: %s", zModule); + *pzErr = sqlite3MPrintf(db, "no such module: %s", zModule); rc = SQLITE_ERROR; }else{ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); @@ -409,11 +529,14 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ Parse sParse; int rc = SQLITE_OK; - Table *pTab = db->pVTab; + Table *pTab; char *zErr = 0; + sqlite3_mutex_enter(db->mutex); + pTab = db->pVTab; if( !pTab ){ sqlite3Error(db, SQLITE_MISUSE, 0); + sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE; } assert(pTab->isVirtual && pTab->nCol==0 && pTab->aCol==0); @@ -432,18 +555,21 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ pTab->nCol = sParse.pNewTable->nCol; sParse.pNewTable->nCol = 0; sParse.pNewTable->aCol = 0; + db->pVTab = 0; } else { sqlite3Error(db, SQLITE_ERROR, zErr); - sqliteFree(zErr); + sqlite3_free(zErr); rc = SQLITE_ERROR; } sParse.declareVtab = 0; sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); - sqlite3DeleteTable(0, sParse.pNewTable); + sqlite3DeleteTable(sParse.pNewTable); sParse.pNewTable = 0; - db->pVTab = 0; + assert( (rc&0xff)==rc ); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); return rc; } @@ -468,7 +594,7 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab) if( xDestroy ){ rc = xDestroy(pTab->pVtab); } - sqlite3SafetyOn(db); + (void)sqlite3SafetyOn(db); if( rc==SQLITE_OK ){ pTab->pVtab = 0; } @@ -487,19 +613,18 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab) */ static void callFinaliser(sqlite3 *db, int offset){ int i; - for(i=0; i<db->nVTrans && db->aVTrans[i]; i++){ - sqlite3_vtab *pVtab = db->aVTrans[i]; - int (*x)(sqlite3_vtab *); - x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset); - if( x ) x(pVtab); - pVtab->nRef--; - if( pVtab->nRef==0 ){ - pVtab->pModule->xDisconnect(pVtab); + if( db->aVTrans ){ + for(i=0; i<db->nVTrans && db->aVTrans[i]; i++){ + sqlite3_vtab *pVtab = db->aVTrans[i]; + int (*x)(sqlite3_vtab *); + x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset); + if( x ) x(pVtab); + sqlite3VtabUnlock(db, pVtab); } + sqlite3_free(db->aVTrans); + db->nVTrans = 0; + db->aVTrans = 0; } - sqliteFree(db->aVTrans); - db->nVTrans = 0; - db->aVTrans = 0; } /* @@ -613,6 +738,7 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){ ** SQLITE_FUNC_EPHEM flag. */ FuncDef *sqlite3VtabOverloadFunction( + sqlite3 *db, /* Database connection for reporting malloc problems */ FuncDef *pDef, /* Function to possibly overload */ int nArg, /* Number of arguments to the function */ Expr *pExpr /* First argument to the function */ @@ -623,6 +749,10 @@ FuncDef *sqlite3VtabOverloadFunction( void (*xFunc)(sqlite3_context*,int,sqlite3_value**); void *pArg; FuncDef *pNew; + int rc = 0; + char *zLowerName; + unsigned char *z; + /* Check to see the left operand is a column in a virtual table */ if( pExpr==0 ) return pDef; @@ -636,20 +766,29 @@ FuncDef *sqlite3VtabOverloadFunction( pMod = (sqlite3_module *)pVtab->pModule; if( pMod->xFindFunction==0 ) return pDef; - /* Call the xFuncFunction method on the virtual table implementation - ** to see if the implementation wants to overload this function */ - if( pMod->xFindFunction(pVtab, nArg, pDef->zName, &xFunc, &pArg)==0 ){ + /* Call the xFindFunction method on the virtual table implementation + ** to see if the implementation wants to overload this function + */ + zLowerName = sqlite3DbStrDup(db, pDef->zName); + if( zLowerName ){ + for(z=(unsigned char*)zLowerName; *z; z++){ + *z = sqlite3UpperToLower[*z]; + } + rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg); + sqlite3_free(zLowerName); + } + if( rc==0 ){ return pDef; } /* Create a new ephemeral function definition for the overloaded ** function */ - pNew = sqliteMalloc( sizeof(*pNew) + strlen(pDef->zName) ); + pNew = sqlite3DbMallocZero(db, sizeof(*pNew) + strlen(pDef->zName) ); if( pNew==0 ){ return pDef; } *pNew = *pDef; - strcpy(pNew->zName, pDef->zName); + memcpy(pNew->zName, pDef->zName, strlen(pDef->zName)+1); pNew->xFunc = xFunc; pNew->pUserData = pArg; pNew->flags |= SQLITE_FUNC_EPHEM; |
