aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2019-08-27 10:05:45 +0000
committerdrh <drh@noemail.net>2019-08-27 10:05:45 +0000
commit6397a78b2ba93729678ef0ea68d0765e046a360e (patch)
tree442024ebdfb05d45c2ee5f8c1bbeab882c726334 /src
parentd790c9a1613334e2fc6b92211911e032ecbf36cf (diff)
downloadsqlite-6397a78b2ba93729678ef0ea68d0765e046a360e.tar.gz
sqlite-6397a78b2ba93729678ef0ea68d0765e046a360e.zip
If a TEMP TRIGGER references an auxiliary schema, and that auxiliary schema
is detached, move the trigger to reference the TEMP schema before completing the detach, so that the trigger does not hold a dangling schema pointer. FossilOrigin-Name: 069c2f4c61f06211a8981abc412afcc1536ece13380b13a70aa99123f8f527cd
Diffstat (limited to 'src')
-rw-r--r--src/attach.c13
-rw-r--r--src/trigger.c14
2 files changed, 20 insertions, 7 deletions
diff --git a/src/attach.c b/src/attach.c
index 61f169ed7..1dcb407ed 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -299,6 +299,7 @@ static void detachFunc(
sqlite3 *db = sqlite3_context_db_handle(context);
int i;
Db *pDb = 0;
+ HashElem *pEntry;
char zErr[128];
UNUSED_PARAMETER(NotUsed);
@@ -323,6 +324,18 @@ static void detachFunc(
goto detach_error;
}
+ /* If any TEMP triggers reference the schema being detached, move those
+ ** triggers to reference the TEMP schema itself. */
+ assert( db->aDb[1].pSchema );
+ pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash);
+ while( pEntry ){
+ Trigger *pTrig = (Trigger*)sqliteHashData(pEntry);
+ if( pTrig->pTabSchema==pDb->pSchema ){
+ pTrig->pTabSchema = pTrig->pSchema;
+ }
+ pEntry = sqliteHashNext(pEntry);
+ }
+
sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0;
pDb->pSchema = 0;
diff --git a/src/trigger.c b/src/trigger.c
index 989df9678..16cc57b40 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -618,10 +618,9 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
assert( iDb>=0 && iDb<db->nDb );
pTable = tableOfTrigger(pTrigger);
- assert( pTable );
- assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
+ assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 );
#ifndef SQLITE_OMIT_AUTHORIZATION
- {
+ if( pTable ){
int code = SQLITE_DROP_TRIGGER;
const char *zDb = db->aDb[iDb].zDbSName;
const char *zTab = SCHEMA_TABLE(iDb);
@@ -635,7 +634,6 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
/* Generate code to destroy the database record of the trigger.
*/
- assert( pTable!=0 );
if( (v = sqlite3GetVdbe(pParse))!=0 ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
@@ -659,9 +657,11 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
if( ALWAYS(pTrigger) ){
if( pTrigger->pSchema==pTrigger->pTabSchema ){
Table *pTab = tableOfTrigger(pTrigger);
- Trigger **pp;
- for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
- *pp = (*pp)->pNext;
+ if( pTab ){
+ Trigger **pp;
+ for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
+ *pp = (*pp)->pNext;
+ }
}
sqlite3DeleteTrigger(db, pTrigger);
db->mDbFlags |= DBFLAG_SchemaChange;