📄 vtab.c
字号:
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;}/*** This function is invoked by the parser to call the xConnect() method** of the virtual table pTab. If an error occurs, an error code is returned ** and an error left in pParse.**** This call is a no-op if table pTab is not a virtual table.*/int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ Module *pMod; int rc = SQLITE_OK; if( !pTab || (pTab->tabFlags & TF_Virtual)==0 || pTab->pVtab ){ return SQLITE_OK; } pMod = pTab->pMod; 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); } sqlite3DbFree(db, 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 = sqlite3DbRealloc(db, (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 sqlite3DbFree(db, ) 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->tabFlags & TF_Virtual)!=0 && !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(db, "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; 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->tabFlags & TF_Virtual)!=0 && 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->tabFlags & TF_Virtual)==0 ){ pTab->aCol = sParse.pNewTable->aCol; pTab->nCol = sParse.pNewTable->nCol; sParse.pNewTable->nCol = 0; sParse.pNewTable->aCol = 0; db->pVTab = 0; } else { sqlite3Error(db, SQLITE_ERROR, zErr); sqlite3DbFree(db, zErr); rc = SQLITE_ERROR; } sParse.declareVtab = 0; sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); sqlite3DeleteTable(sParse.pNewTable); sParse.pNewTable = 0; assert( (rc&0xff)==rc ); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); 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); } (void)sqlite3SafetyOn(db); if( rc==SQLITE_OK ){ int i; for(i=0; i<db->nVTrans; i++){ if( db->aVTrans[i]==pTab->pVtab ){ db->aVTrans[i] = db->aVTrans[--db->nVTrans]; break; } } 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; 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); } sqlite3DbFree(db, db->aVTrans); db->nVTrans = 0; db->aVTrans = 0; }}/*** 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.**** Set *pzErrmsg to point to a buffer that should be released using ** sqlite3DbFree() containing an error message, if one is available.*/int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){ int i; int rc = SQLITE_OK; int rcsafety; sqlite3_vtab **aVTrans = db->aVTrans; 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); sqlite3DbFree(db, *pzErrmsg); *pzErrmsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; } } 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, offsetof(sqlite3_module,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, offsetof(sqlite3_module,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( sqlite3VtabInSync(db) ){ 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 ){ 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( 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 */){ Table *pTab; sqlite3_vtab *pVtab; sqlite3_module *pMod; 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; if( pExpr->op!=TK_COLUMN ) return pDef; pTab = pExpr->pTab; if( pTab==0 ) return pDef; if( (pTab->tabFlags & TF_Virtual)==0 ) 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 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); sqlite3DbFree(db, zLowerName); if( pVtab->zErrMsg ){ sqlite3Error(db, rc, "%s", pVtab->zErrMsg); sqlite3DbFree(db, pVtab->zErrMsg); pVtab->zErrMsg = 0; } } if( rc==0 ){ return pDef; } /* Create a new ephemeral function definition for the overloaded ** function */ pNew = sqlite3DbMallocZero(db, sizeof(*pNew) + strlen(pDef->zName) ); if( pNew==0 ){ return pDef; } *pNew = *pDef; pNew->zName = (char *)&pNew[1]; memcpy(pNew->zName, pDef->zName, strlen(pDef->zName)+1); pNew->xFunc = xFunc; pNew->pUserData = pArg; pNew->flags |= SQLITE_FUNC_EPHEM; return pNew;}/*** Make sure virtual table pTab is contained in the pParse->apVirtualLock[]** array so that an OP_VBegin will get generated for it. Add pTab to the** array if it is missing. If pTab is already in the array, this routine** is a no-op.*/void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ int i, n; assert( IsVirtual(pTab) ); for(i=0; i<pParse->nVtabLock; i++){ if( pTab==pParse->apVtabLock[i] ) return; } n = (pParse->nVtabLock+1)*sizeof(pParse->apVtabLock[0]); pParse->apVtabLock = sqlite3_realloc(pParse->apVtabLock, n); if( pParse->apVtabLock ){ pParse->apVtabLock[pParse->nVtabLock++] = pTab; }else{ pParse->db->mallocFailed = 1; }}#endif /* SQLITE_OMIT_VIRTUALTABLE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -