First the shadow table mechanism so that it works even if the shadow table

comes before the virtual table in the sqlite_schema table, as can happen
after a VACUUM.

FossilOrigin-Name: 005a8642773556825fe4c5d0b2c12517d35289308a30df0151ef7f080acb0172
This commit is contained in:
drh
2021-11-04 00:51:53 +00:00
parent 0b97189c49
commit ddfec00de3
6 changed files with 57 additions and 25 deletions
+39 -6
View File
@@ -2492,6 +2492,40 @@ int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){
}
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Table pTab is a virtual table. If it the virtual table implementation
** exists and has an xShadowName method, then loop over all other ordinary
** tables within the same schema looking for shadow tables of pTab, and mark
** any shadow tables seen using the TF_Shadow flag.
*/
void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){
int nName; /* Length of pTab->zName */
Module *pMod; /* Module for the virtual table */
HashElem *k; /* For looping through the symbol table */
assert( IsVirtual(pTab) );
pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]);
if( pMod==0 ) return;
if( NEVER(pMod->pModule==0) ) return;
if( pMod->pModule->xShadowName==0 ) return;
assert( pTab->zName!=0 );
nName = sqlite3Strlen30(pTab->zName);
for(k=sqliteHashFirst(&pTab->pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pOther = sqliteHashData(k);
assert( pOther->zName!=0 );
if( !IsOrdinaryTable(pOther) ) continue;
if( pOther->tabFlags & TF_Shadow ) continue;
if( sqlite3StrNICmp(pOther->zName, pTab->zName, nName)==0
&& pOther->zName[nName]=='_'
&& pMod->pModule->xShadowName(pOther->zName+nName+1)
){
pOther->tabFlags |= TF_Shadow;
}
}
}
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Return true if zName is a shadow table name in the current database
@@ -3006,13 +3040,12 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable );
#ifndef SQLITE_OMIT_VIRTUALTABLE
db->nSchemaLock++;
rc = sqlite3VtabCallConnect(pParse, pTable);
db->nSchemaLock--;
if( rc ){
return 1;
if( IsVirtual(pTable) ){
db->nSchemaLock++;
rc = sqlite3VtabCallConnect(pParse, pTable);
db->nSchemaLock--;
return rc;
}
if( IsVirtual(pTable) ) return 0;
#endif
#ifndef SQLITE_OMIT_VIEW
+2
View File
@@ -5050,9 +5050,11 @@ int sqlite3ReadOnlyShadowTables(sqlite3 *db);
#ifndef SQLITE_OMIT_VIRTUALTABLE
int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*);
void sqlite3MarkAllShadowTablesOf(sqlite3*, Table*);
#else
# define sqlite3ShadowTableName(A,B) 0
# define sqlite3IsShadowTableOf(A,B,C) 0
# define sqlite3MarkAllShadowTablesOf(A,B)
#endif
int sqlite3VtabEponymousTableInit(Parse*,Module*);
void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
+5 -9
View File
@@ -505,18 +505,14 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
iReg = ++pParse->nMem;
sqlite3VdbeLoadString(v, iReg, pTab->zName);
sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
}
/* If we are rereading the sqlite_schema table create the in-memory
** record of the table. The xConnect() method is not called until
** the first time the virtual table is used in an SQL statement. This
** allows a schema that contains virtual tables to be loaded before
** the required virtual table implementations are registered. */
else {
}else{
/* If we are rereading the sqlite_schema table create the in-memory
** record of the table. */
Table *pOld;
Schema *pSchema = pTab->pSchema;
const char *zName = pTab->zName;
assert( sqlite3SchemaMutexHeld(db, 0, pSchema) );
assert( zName!=0 );
sqlite3MarkAllShadowTablesOf(db, pTab);
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab);
if( pOld ){
sqlite3OomFault(db);