📄 vtab.c
字号:
pMod = pTab->pMod; zModule = pTab->azModuleArg[0]; if( !pMod ){ const char *zModule = pTab->azModuleArg[0]; sqlite3ErrorMsg(pParse, "no such module: %s", zModule); rc = SQLITE_ERROR; } else { char *zErr = 0; sqlite3 *db = pParse->db; rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "%s", zErr); } sqliteFree(zErr); } return rc;}/*** Add the virtual table pVtab to the array sqlite3.aVTrans[].*/static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){ const int ARRAY_INCR = 5; /* Grow the sqlite3.aVTrans array if required */ if( (db->nVTrans%ARRAY_INCR)==0 ){ sqlite3_vtab **aVTrans; int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR); aVTrans = sqliteRealloc((void *)db->aVTrans, nBytes); if( !aVTrans ){ return SQLITE_NOMEM; } memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR); db->aVTrans = aVTrans; } /* Add pVtab to the end of sqlite3.aVTrans */ db->aVTrans[db->nVTrans++] = pVtab; sqlite3VtabLock(pVtab); return SQLITE_OK;}/*** This function is invoked by the vdbe to call the xCreate method** of the virtual table named zTab in database iDb. **** 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.*/int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ int rc = SQLITE_OK; Table *pTab; Module *pMod; const char *zModule; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); assert(pTab && pTab->isVirtual && !pTab->pVtab); pMod = pTab->pMod; zModule = pTab->azModuleArg[0]; /* If the module has been registered and includes a Create method, ** invoke it now. If the module has not been registered, return an ** error. Otherwise, do nothing. */ if( !pMod ){ *pzErr = sqlite3MPrintf("no such module: %s", zModule); rc = SQLITE_ERROR; }else{ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); } if( rc==SQLITE_OK && pTab->pVtab ){ rc = addToVTrans(db, pTab->pVtab); } return rc;}/*** This function is used to set the schema of a virtual table. It is only** valid to call this function from within the xCreate() or xConnect() of a** virtual table module.*/int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ Parse sParse; int rc = SQLITE_OK; Table *pTab = db->pVTab; char *zErr = 0; if( !pTab ){ sqlite3Error(db, SQLITE_MISUSE, 0); return SQLITE_MISUSE; } assert(pTab->isVirtual && pTab->nCol==0 && pTab->aCol==0); memset(&sParse, 0, sizeof(Parse)); sParse.declareVtab = 1; sParse.db = db; if( SQLITE_OK == sqlite3RunParser(&sParse, zCreateTable, &zErr) && sParse.pNewTable && !sParse.pNewTable->pSelect && !sParse.pNewTable->isVirtual ){ pTab->aCol = sParse.pNewTable->aCol; pTab->nCol = sParse.pNewTable->nCol; sParse.pNewTable->nCol = 0; sParse.pNewTable->aCol = 0; } else { sqlite3Error(db, SQLITE_ERROR, zErr); sqliteFree(zErr); rc = SQLITE_ERROR; } sParse.declareVtab = 0; sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); sqlite3DeleteTable(0, sParse.pNewTable); sParse.pNewTable = 0; db->pVTab = 0; assert( (rc&0xff)==rc ); return rc;}/*** This function is invoked by the vdbe to call the xDestroy method** of the virtual table named zTab in database iDb. This occurs** when a DROP TABLE is mentioned.**** This call is a no-op if zTab is not a virtual table.*/int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); assert(pTab); if( pTab->pVtab ){ int (*xDestroy)(sqlite3_vtab *pVTab) = pTab->pMod->pModule->xDestroy; rc = sqlite3SafetyOff(db); assert( rc==SQLITE_OK ); if( xDestroy ){ rc = xDestroy(pTab->pVtab); } sqlite3SafetyOn(db); if( rc==SQLITE_OK ){ pTab->pVtab = 0; } } return rc;}/*** This function invokes either the xRollback or xCommit method** of each of the virtual tables in the sqlite3.aVTrans array. The method** called is identified by the second argument, "offset", which is** the offset of the method to call in the sqlite3_module structure.**** The array is cleared after invoking the callbacks. */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); sqlite3VtabUnlock(pVtab); } sqliteFree(db->aVTrans); db->nVTrans = 0; db->aVTrans = 0;}/*** If argument rc2 is not SQLITE_OK, then return it and do nothing. ** Otherwise, invoke the xSync method of all virtual tables in the ** sqlite3.aVTrans array. Return the error code for the first error ** that occurs, or SQLITE_OK if all xSync operations are successful.*/int sqlite3VtabSync(sqlite3 *db, int rc2){ int i; int rc = SQLITE_OK; int rcsafety; sqlite3_vtab **aVTrans = db->aVTrans; if( rc2!=SQLITE_OK ) return rc2; rc = sqlite3SafetyOff(db); db->aVTrans = 0; for(i=0; rc==SQLITE_OK && i<db->nVTrans && aVTrans[i]; i++){ sqlite3_vtab *pVtab = aVTrans[i]; int (*x)(sqlite3_vtab *); x = pVtab->pModule->xSync; if( x ){ rc = x(pVtab); } } db->aVTrans = aVTrans; rcsafety = sqlite3SafetyOn(db); if( rc==SQLITE_OK ){ rc = rcsafety; } return rc;}/*** Invoke the xRollback method of all virtual tables in the ** sqlite3.aVTrans array. Then clear the array itself.*/int sqlite3VtabRollback(sqlite3 *db){ callFinaliser(db, (int)(&((sqlite3_module *)0)->xRollback)); return SQLITE_OK;}/*** Invoke the xCommit method of all virtual tables in the ** sqlite3.aVTrans array. Then clear the array itself.*/int sqlite3VtabCommit(sqlite3 *db){ callFinaliser(db, (int)(&((sqlite3_module *)0)->xCommit)); return SQLITE_OK;}/*** If the virtual table pVtab supports the transaction interface** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is** not currently open, invoke the xBegin method now.**** If the xBegin call is successful, place the sqlite3_vtab pointer** in the sqlite3.aVTrans array.*/int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){ int rc = SQLITE_OK; const sqlite3_module *pModule; /* Special case: If db->aVTrans is NULL and db->nVTrans is greater ** than zero, then this function is being called from within a ** virtual module xSync() callback. It is illegal to write to ** virtual module tables in this case, so return SQLITE_LOCKED. */ if( 0==db->aVTrans && db->nVTrans>0 ){ return SQLITE_LOCKED; } if( !pVtab ){ return SQLITE_OK; } pModule = pVtab->pModule; if( pModule->xBegin ){ int i; /* If pVtab is already in the aVTrans array, return early */ for(i=0; (i<db->nVTrans) && 0!=db->aVTrans[i]; i++){ if( db->aVTrans[i]==pVtab ){ return SQLITE_OK; } } /* Invoke the xBegin method */ rc = pModule->xBegin(pVtab); if( rc!=SQLITE_OK ){ return rc; } rc = addToVTrans(db, pVtab); } return rc;}/*** The first parameter (pDef) is a function implementation. The** second parameter (pExpr) is the first argument to this function.** If pExpr is a column in a virtual table, then let the virtual** table implementation have an opportunity to overload the function.**** This routine is used to allow virtual table implementations to** overload MATCH, LIKE, GLOB, and REGEXP operators.**** Return either the pDef argument (indicating no change) or a ** new FuncDef structure that is marked as ephemeral using the** SQLITE_FUNC_EPHEM flag.*/FuncDef *sqlite3VtabOverloadFunction( FuncDef *pDef, /* Function to possibly overload */ int nArg, /* Number of arguments to the function */ Expr *pExpr /* First argument to the function */){ Table *pTab; sqlite3_vtab *pVtab; sqlite3_module *pMod; void (*xFunc)(sqlite3_context*,int,sqlite3_value**); void *pArg; FuncDef *pNew; int rc; char *zLowerName; unsigned char *z; /* Check to see the left operand is a column in a virtual table */ if( pExpr==0 ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; pTab = pExpr->pTab; if( pTab==0 ) return pDef; if( !pTab->isVirtual ) return pDef; pVtab = pTab->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); 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 */ zLowerName = sqlite3StrDup(pDef->zName); for(z=(unsigned char*)zLowerName; *z; z++){ *z = sqlite3UpperToLower[*z]; } rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg); sqliteFree(zLowerName); if( rc==0 ){ return pDef; } /* Create a new ephemeral function definition for the overloaded ** function */ pNew = sqliteMalloc( sizeof(*pNew) + strlen(pDef->zName) ); if( pNew==0 ){ return pDef; } *pNew = *pDef; strcpy(pNew->zName, pDef->zName); pNew->xFunc = xFunc; pNew->pUserData = pArg; pNew->flags |= SQLITE_FUNC_EPHEM; return pNew;}#endif /* SQLITE_OMIT_VIRTUALTABLE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -