mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Refactor the Table object to reduce its memory footprint.
FossilOrigin-Name: bbb6759bcf6e01d36dfc787a82a610d359f50aaeac8104b73883a84906d54e1f
This commit is contained in:
82
src/vtab.c
82
src/vtab.c
@@ -192,7 +192,7 @@ void sqlite3VtabLock(VTable *pVTab){
|
||||
VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){
|
||||
VTable *pVtab;
|
||||
assert( IsVirtual(pTab) );
|
||||
for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
|
||||
for(pVtab=pTab->u.vtab.p; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
|
||||
return pVtab;
|
||||
}
|
||||
|
||||
@@ -220,21 +220,21 @@ void sqlite3VtabUnlock(VTable *pVTab){
|
||||
|
||||
/*
|
||||
** Table p is a virtual table. This function moves all elements in the
|
||||
** p->pVTable list to the sqlite3.pDisconnect lists of their associated
|
||||
** p->u.vtab.p list to the sqlite3.pDisconnect lists of their associated
|
||||
** database connections to be disconnected at the next opportunity.
|
||||
** Except, if argument db is not NULL, then the entry associated with
|
||||
** connection db is left in the p->pVTable list.
|
||||
** connection db is left in the p->u.vtab.p list.
|
||||
*/
|
||||
static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
|
||||
VTable *pRet = 0;
|
||||
VTable *pVTable = p->pVTable;
|
||||
p->pVTable = 0;
|
||||
VTable *pVTable = p->u.vtab.p;
|
||||
p->u.vtab.p = 0;
|
||||
|
||||
/* Assert that the mutex (if any) associated with the BtShared database
|
||||
** that contains table p is held by the caller. See header comments
|
||||
** above function sqlite3VtabUnlockList() for an explanation of why
|
||||
** this makes it safe to access the sqlite3.pDisconnect list of any
|
||||
** database connection that may have an entry in the p->pVTable list.
|
||||
** database connection that may have an entry in the p->u.vtab.p list.
|
||||
*/
|
||||
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
|
||||
|
||||
@@ -244,7 +244,7 @@ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
|
||||
assert( db2 );
|
||||
if( db2==db ){
|
||||
pRet = pVTable;
|
||||
p->pVTable = pRet;
|
||||
p->u.vtab.p = pRet;
|
||||
pRet->pNext = 0;
|
||||
}else{
|
||||
pVTable->pNext = db2->pDisconnect;
|
||||
@@ -272,7 +272,7 @@ void sqlite3VtabDisconnect(sqlite3 *db, Table *p){
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
|
||||
for(ppVTab=&p->pVTable; *ppVTab; ppVTab=&(*ppVTab)->pNext){
|
||||
for(ppVTab=&p->u.vtab.p; *ppVTab; ppVTab=&(*ppVTab)->pNext){
|
||||
if( (*ppVTab)->db==db ){
|
||||
VTable *pVTab = *ppVTab;
|
||||
*ppVTab = pVTab->pNext;
|
||||
@@ -336,36 +336,36 @@ void sqlite3VtabUnlockList(sqlite3 *db){
|
||||
*/
|
||||
void sqlite3VtabClear(sqlite3 *db, Table *p){
|
||||
if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
|
||||
if( p->azModuleArg ){
|
||||
if( p->u.vtab.azArg ){
|
||||
int i;
|
||||
for(i=0; i<p->nModuleArg; i++){
|
||||
if( i!=1 ) sqlite3DbFree(db, p->azModuleArg[i]);
|
||||
for(i=0; i<p->u.vtab.nArg; i++){
|
||||
if( i!=1 ) sqlite3DbFree(db, p->u.vtab.azArg[i]);
|
||||
}
|
||||
sqlite3DbFree(db, p->azModuleArg);
|
||||
sqlite3DbFree(db, p->u.vtab.azArg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a new module argument to pTable->azModuleArg[].
|
||||
** Add a new module argument to pTable->u.vtab.azArg[].
|
||||
** The string is not copied - the pointer is stored. The
|
||||
** string will be freed automatically when the table is
|
||||
** deleted.
|
||||
*/
|
||||
static void addModuleArgument(Parse *pParse, Table *pTable, char *zArg){
|
||||
sqlite3_int64 nBytes = sizeof(char *)*(2+pTable->nModuleArg);
|
||||
sqlite3_int64 nBytes = sizeof(char *)*(2+pTable->u.vtab.nArg);
|
||||
char **azModuleArg;
|
||||
sqlite3 *db = pParse->db;
|
||||
if( pTable->nModuleArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
||||
if( pTable->u.vtab.nArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
||||
sqlite3ErrorMsg(pParse, "too many columns on %s", pTable->zName);
|
||||
}
|
||||
azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes);
|
||||
azModuleArg = sqlite3DbRealloc(db, pTable->u.vtab.azArg, nBytes);
|
||||
if( azModuleArg==0 ){
|
||||
sqlite3DbFree(db, zArg);
|
||||
}else{
|
||||
int i = pTable->nModuleArg++;
|
||||
int i = pTable->u.vtab.nArg++;
|
||||
azModuleArg[i] = zArg;
|
||||
azModuleArg[i+1] = 0;
|
||||
pTable->azModuleArg = azModuleArg;
|
||||
pTable->u.vtab.azArg = azModuleArg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,10 +388,11 @@ void sqlite3VtabBeginParse(
|
||||
pTable = pParse->pNewTable;
|
||||
if( pTable==0 ) return;
|
||||
assert( 0==pTable->pIndex );
|
||||
pTable->eTabType = TABTYP_VTAB;
|
||||
|
||||
db = pParse->db;
|
||||
|
||||
assert( pTable->nModuleArg==0 );
|
||||
assert( pTable->u.vtab.nArg==0 );
|
||||
addModuleArgument(pParse, pTable, sqlite3NameFromToken(db, pModuleName));
|
||||
addModuleArgument(pParse, pTable, 0);
|
||||
addModuleArgument(pParse, pTable, sqlite3DbStrDup(db, pTable->zName));
|
||||
@@ -408,11 +409,11 @@ void sqlite3VtabBeginParse(
|
||||
** sqlite_schema table, has already been made by sqlite3StartTable().
|
||||
** The second call, to obtain permission to create the table, is made now.
|
||||
*/
|
||||
if( pTable->azModuleArg ){
|
||||
if( pTable->u.vtab.azArg ){
|
||||
int iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
|
||||
assert( iDb>=0 ); /* The database the table is being created in */
|
||||
sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
|
||||
pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName);
|
||||
pTable->u.vtab.azArg[0], pParse->db->aDb[iDb].zDbSName);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -442,7 +443,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
if( pTab==0 ) return;
|
||||
addArgumentToVtab(pParse);
|
||||
pParse->sArg.z = 0;
|
||||
if( pTab->nModuleArg<1 ) return;
|
||||
if( pTab->u.vtab.nArg<1 ) return;
|
||||
|
||||
/* If the CREATE VIRTUAL TABLE statement is being entered for the
|
||||
** first time (in other words if the virtual table is actually being
|
||||
@@ -557,8 +558,8 @@ static int vtabCallConstructor(
|
||||
VtabCtx sCtx;
|
||||
VTable *pVTable;
|
||||
int rc;
|
||||
const char *const*azArg = (const char *const*)pTab->azModuleArg;
|
||||
int nArg = pTab->nModuleArg;
|
||||
const char *const*azArg = (const char *const*)pTab->u.vtab.azArg;
|
||||
int nArg = pTab->u.vtab.nArg;
|
||||
char *zErr = 0;
|
||||
char *zModuleName;
|
||||
int iDb;
|
||||
@@ -590,7 +591,7 @@ static int vtabCallConstructor(
|
||||
pVTable->eVtabRisk = SQLITE_VTABRISK_Normal;
|
||||
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
|
||||
pTab->u.vtab.azArg[1] = db->aDb[iDb].zDbSName;
|
||||
|
||||
/* Invoke the virtual table constructor */
|
||||
assert( &db->pVtabCtx );
|
||||
@@ -629,12 +630,12 @@ static int vtabCallConstructor(
|
||||
int iCol;
|
||||
u16 oooHidden = 0;
|
||||
/* If everything went according to plan, link the new VTable structure
|
||||
** into the linked list headed by pTab->pVTable. Then loop through the
|
||||
** into the linked list headed by pTab->u.vtab.p. Then loop through the
|
||||
** columns of the table to see if any of them contain the token "hidden".
|
||||
** If so, set the Column COLFLAG_HIDDEN flag and remove the token from
|
||||
** the type string. */
|
||||
pVTable->pNext = pTab->pVTable;
|
||||
pTab->pVTable = pVTable;
|
||||
pVTable->pNext = pTab->u.vtab.p;
|
||||
pTab->u.vtab.p = pVTable;
|
||||
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
|
||||
@@ -692,11 +693,11 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
||||
}
|
||||
|
||||
/* Locate the required virtual table module */
|
||||
zMod = pTab->azModuleArg[0];
|
||||
zMod = pTab->u.vtab.azArg[0];
|
||||
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);
|
||||
|
||||
if( !pMod ){
|
||||
const char *zModule = pTab->azModuleArg[0];
|
||||
const char *zModule = pTab->u.vtab.azArg[0];
|
||||
sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
@@ -759,10 +760,10 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
|
||||
const char *zMod;
|
||||
|
||||
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
|
||||
assert( pTab && IsVirtual(pTab) && !pTab->pVTable );
|
||||
assert( pTab && IsVirtual(pTab) && !pTab->u.vtab.p );
|
||||
|
||||
/* Locate the required virtual table module */
|
||||
zMod = pTab->azModuleArg[0];
|
||||
zMod = pTab->u.vtab.azArg[0];
|
||||
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);
|
||||
|
||||
/* If the module has been registered and includes a Create method,
|
||||
@@ -822,19 +823,17 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
|
||||
&& sParse.pNewTable
|
||||
&& !db->mallocFailed
|
||||
&& !sParse.pNewTable->pSelect
|
||||
&& !IsVirtual(sParse.pNewTable)
|
||||
&& IsOrdinaryTable(sParse.pNewTable)
|
||||
){
|
||||
if( !pTab->aCol ){
|
||||
Table *pNew = sParse.pNewTable;
|
||||
Index *pIdx;
|
||||
pTab->aCol = pNew->aCol;
|
||||
pTab->pDfltList = pNew->pDfltList;
|
||||
sqlite3ExprListDelete(db, pNew->u.tab.pDfltList);
|
||||
pTab->nNVCol = pTab->nCol = pNew->nCol;
|
||||
pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
|
||||
pNew->nCol = 0;
|
||||
pNew->aCol = 0;
|
||||
pNew->pDfltList = 0;
|
||||
assert( pTab->pIndex==0 );
|
||||
assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 );
|
||||
if( !HasRowid(pNew)
|
||||
@@ -885,10 +884,10 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
|
||||
Table *pTab;
|
||||
|
||||
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
|
||||
if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){
|
||||
if( pTab!=0 && ALWAYS(pTab->u.vtab.p!=0) ){
|
||||
VTable *p;
|
||||
int (*xDestroy)(sqlite3_vtab *);
|
||||
for(p=pTab->pVTable; p; p=p->pNext){
|
||||
for(p=pTab->u.vtab.p; p; p=p->pNext){
|
||||
assert( p->pVtab );
|
||||
if( p->pVtab->nRef>0 ){
|
||||
return SQLITE_LOCKED;
|
||||
@@ -902,9 +901,9 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
|
||||
rc = xDestroy(p->pVtab);
|
||||
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( pTab->pVTable==p && p->pNext==0 );
|
||||
assert( pTab->u.vtab.p==p && p->pNext==0 );
|
||||
p->pVtab = 0;
|
||||
pTab->pVTable = 0;
|
||||
pTab->u.vtab.p = 0;
|
||||
sqlite3VtabUnlock(p);
|
||||
}
|
||||
sqlite3DeleteTable(db, pTab);
|
||||
@@ -1221,8 +1220,9 @@ int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
|
||||
}
|
||||
pMod->pEpoTab = pTab;
|
||||
pTab->nTabRef = 1;
|
||||
pTab->eTabType = TABTYP_VTAB;
|
||||
pTab->pSchema = db->aDb[0].pSchema;
|
||||
assert( pTab->nModuleArg==0 );
|
||||
assert( pTab->u.vtab.nArg==0 );
|
||||
pTab->iPKey = -1;
|
||||
pTab->tabFlags |= TF_Eponymous;
|
||||
addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
|
||||
|
Reference in New Issue
Block a user