summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src/vtab.c
diff options
context:
space:
mode:
authorScott MacVicar <scottmac@php.net>2008-03-07 10:55:14 +0000
committerScott MacVicar <scottmac@php.net>2008-03-07 10:55:14 +0000
commit31dade5280849135b00fd1c5e53d057732a72776 (patch)
tree564b9f0f9d8cf89d7df9a9c12147ba8a5da6506f /ext/pdo_sqlite/sqlite/src/vtab.c
parent7abf0787ad9fd613ddde880c9bc163161d7bf4ff (diff)
downloadphp-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.c303
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;