1
0
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:
drh
2021-08-02 16:41:57 +00:00
parent 79cf2b7120
commit f38524d20d
17 changed files with 246 additions and 205 deletions

View File

@@ -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));