mirror of
https://github.com/postgres/postgres.git
synced 2025-08-12 15:23:02 +03:00
Add ALTER TABLE ENABLE/DISABLE TRIGGER commands. Change pg_dump to
use these instead of its previous hack of changing pg_class.reltriggers. Documentation is lacking, will add that later. Patch by Satoshi Nagayasu, review and some extra work by Tom Lane.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.168 2005/08/22 19:40:09 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.169 2005/08/23 22:40:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -246,6 +246,8 @@ static void ATExecDropCluster(Relation rel);
|
||||
static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
|
||||
char *tablespacename);
|
||||
static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace);
|
||||
static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
|
||||
bool enable, bool skip_system);
|
||||
static void copy_relation_data(Relation rel, SMgrRelation dst);
|
||||
static void update_ri_trigger_args(Oid relid,
|
||||
const char *oldname,
|
||||
@@ -2005,6 +2007,17 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
||||
ATPrepSetTableSpace(tab, rel, cmd->name);
|
||||
pass = AT_PASS_MISC; /* doesn't actually matter */
|
||||
break;
|
||||
case AT_EnableTrig: /* ENABLE TRIGGER variants */
|
||||
case AT_EnableTrigAll:
|
||||
case AT_EnableTrigUser:
|
||||
case AT_DisableTrig: /* DISABLE TRIGGER variants */
|
||||
case AT_DisableTrigAll:
|
||||
case AT_DisableTrigUser:
|
||||
ATSimplePermissions(rel, false);
|
||||
/* These commands never recurse */
|
||||
/* No command-specific prep needed */
|
||||
pass = AT_PASS_MISC;
|
||||
break;
|
||||
default: /* oops */
|
||||
elog(ERROR, "unrecognized alter table type: %d",
|
||||
(int) cmd->subtype);
|
||||
@@ -2163,6 +2176,24 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd)
|
||||
* Nothing to do here; Phase 3 does the work
|
||||
*/
|
||||
break;
|
||||
case AT_EnableTrig: /* ENABLE TRIGGER name */
|
||||
ATExecEnableDisableTrigger(rel, cmd->name, true, false);
|
||||
break;
|
||||
case AT_DisableTrig: /* DISABLE TRIGGER name */
|
||||
ATExecEnableDisableTrigger(rel, cmd->name, false, false);
|
||||
break;
|
||||
case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */
|
||||
ATExecEnableDisableTrigger(rel, NULL, true, false);
|
||||
break;
|
||||
case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */
|
||||
ATExecEnableDisableTrigger(rel, NULL, false, false);
|
||||
break;
|
||||
case AT_EnableTrigUser: /* ENABLE TRIGGER USER */
|
||||
ATExecEnableDisableTrigger(rel, NULL, true, true);
|
||||
break;
|
||||
case AT_DisableTrigUser: /* DISABLE TRIGGER USER */
|
||||
ATExecEnableDisableTrigger(rel, NULL, false, true);
|
||||
break;
|
||||
default: /* oops */
|
||||
elog(ERROR, "unrecognized alter table type: %d",
|
||||
(int) cmd->subtype);
|
||||
@@ -5778,6 +5809,18 @@ copy_relation_data(Relation rel, SMgrRelation dst)
|
||||
smgrimmedsync(dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* ALTER TABLE ENABLE/DISABLE TRIGGER
|
||||
*
|
||||
* We just pass this off to trigger.c.
|
||||
*/
|
||||
static void
|
||||
ATExecEnableDisableTrigger(Relation rel, char *trigname,
|
||||
bool enable, bool skip_system)
|
||||
{
|
||||
EnableDisableTrigger(rel, trigname, enable, skip_system);
|
||||
}
|
||||
|
||||
/*
|
||||
* ALTER TABLE CREATE TOAST TABLE
|
||||
*
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.192 2005/08/20 00:39:54 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.193 2005/08/23 22:40:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -712,6 +712,114 @@ renametrig(Oid relid,
|
||||
heap_close(targetrel, NoLock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* EnableDisableTrigger()
|
||||
*
|
||||
* Called by ALTER TABLE ENABLE/DISABLE TRIGGER
|
||||
* to change 'tgenabled' flag for the specified trigger(s)
|
||||
*
|
||||
* rel: relation to process (caller must hold suitable lock on it)
|
||||
* tgname: trigger to process, or NULL to scan all triggers
|
||||
* enable: new value for tgenabled flag
|
||||
* skip_system: if true, skip "system" triggers (constraint triggers)
|
||||
*
|
||||
* Caller should have checked permissions for the table; here we also
|
||||
* enforce that superuser privilege is required to alter the state of
|
||||
* system triggers
|
||||
*/
|
||||
void
|
||||
EnableDisableTrigger(Relation rel, const char *tgname,
|
||||
bool enable, bool skip_system)
|
||||
{
|
||||
Relation tgrel;
|
||||
int nkeys;
|
||||
ScanKeyData keys[2];
|
||||
SysScanDesc tgscan;
|
||||
HeapTuple tuple;
|
||||
bool found;
|
||||
bool changed;
|
||||
|
||||
/* Scan the relevant entries in pg_triggers */
|
||||
tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
|
||||
|
||||
ScanKeyInit(&keys[0],
|
||||
Anum_pg_trigger_tgrelid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(RelationGetRelid(rel)));
|
||||
if (tgname)
|
||||
{
|
||||
ScanKeyInit(&keys[1],
|
||||
Anum_pg_trigger_tgname,
|
||||
BTEqualStrategyNumber, F_NAMEEQ,
|
||||
CStringGetDatum(tgname));
|
||||
nkeys = 2;
|
||||
}
|
||||
else
|
||||
nkeys = 1;
|
||||
|
||||
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
|
||||
SnapshotNow, nkeys, keys);
|
||||
|
||||
found = changed = false;
|
||||
|
||||
while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
|
||||
{
|
||||
Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
|
||||
|
||||
if (oldtrig->tgisconstraint)
|
||||
{
|
||||
/* system trigger ... ok to process? */
|
||||
if (skip_system)
|
||||
continue;
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied: \"%s\" is a system trigger",
|
||||
NameStr(oldtrig->tgname))));
|
||||
}
|
||||
|
||||
found = true;
|
||||
|
||||
if (oldtrig->tgenabled != enable)
|
||||
{
|
||||
/* need to change this one ... make a copy to scribble on */
|
||||
HeapTuple newtup = heap_copytuple(tuple);
|
||||
Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
|
||||
|
||||
newtrig->tgenabled = enable;
|
||||
|
||||
simple_heap_update(tgrel, &newtup->t_self, newtup);
|
||||
|
||||
/* Keep catalog indexes current */
|
||||
CatalogUpdateIndexes(tgrel, newtup);
|
||||
|
||||
heap_freetuple(newtup);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
systable_endscan(tgscan);
|
||||
|
||||
heap_close(tgrel, RowExclusiveLock);
|
||||
|
||||
if (tgname && !found)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("trigger \"%s\" for table \"%s\" does not exist",
|
||||
tgname, RelationGetRelationName(rel))));
|
||||
|
||||
/*
|
||||
* If we changed anything, broadcast a SI inval message to force each
|
||||
* backend (including our own!) to rebuild relation's relcache entry.
|
||||
* Otherwise they will fail to apply the change promptly.
|
||||
*/
|
||||
if (changed)
|
||||
CacheInvalidateRelcache(rel);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Build trigger data to attach to the given relcache entry.
|
||||
*
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.507 2005/08/01 20:31:09 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.508 2005/08/23 22:40:20 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -350,9 +350,9 @@ static void doNegateFloat(Value *v);
|
||||
|
||||
DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
|
||||
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
|
||||
DESC DISTINCT DO DOMAIN_P DOUBLE_P DROP
|
||||
DESC DISABLE_P DISTINCT DO DOMAIN_P DOUBLE_P DROP
|
||||
|
||||
EACH ELSE ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
|
||||
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
|
||||
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
|
||||
|
||||
FALSE_P FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
|
||||
@@ -1415,6 +1415,50 @@ alter_table_cmd:
|
||||
n->name = NULL;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
/* ALTER TABLE <name> ENABLE TRIGGER <trig> */
|
||||
| ENABLE_P TRIGGER name
|
||||
{
|
||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||
n->subtype = AT_EnableTrig;
|
||||
n->name = $3;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
/* ALTER TABLE <name> ENABLE TRIGGER ALL */
|
||||
| ENABLE_P TRIGGER ALL
|
||||
{
|
||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||
n->subtype = AT_EnableTrigAll;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
/* ALTER TABLE <name> ENABLE TRIGGER USER */
|
||||
| ENABLE_P TRIGGER USER
|
||||
{
|
||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||
n->subtype = AT_EnableTrigUser;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
/* ALTER TABLE <name> DISABLE TRIGGER <trig> */
|
||||
| DISABLE_P TRIGGER name
|
||||
{
|
||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||
n->subtype = AT_DisableTrig;
|
||||
n->name = $3;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
/* ALTER TABLE <name> DISABLE TRIGGER ALL */
|
||||
| DISABLE_P TRIGGER ALL
|
||||
{
|
||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||
n->subtype = AT_DisableTrigAll;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
/* ALTER TABLE <name> DISABLE TRIGGER USER */
|
||||
| DISABLE_P TRIGGER USER
|
||||
{
|
||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||
n->subtype = AT_DisableTrigUser;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| alter_rel_cmd
|
||||
{
|
||||
$$ = $1;
|
||||
@@ -8067,10 +8111,12 @@ unreserved_keyword:
|
||||
| DELETE_P
|
||||
| DELIMITER
|
||||
| DELIMITERS
|
||||
| DISABLE_P
|
||||
| DOMAIN_P
|
||||
| DOUBLE_P
|
||||
| DROP
|
||||
| EACH
|
||||
| ENABLE_P
|
||||
| ENCODING
|
||||
| ENCRYPTED
|
||||
| ESCAPE
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.164 2005/07/31 17:19:18 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.165 2005/08/23 22:40:27 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -117,6 +117,7 @@ static const ScanKeyword ScanKeywords[] = {
|
||||
{"delimiter", DELIMITER},
|
||||
{"delimiters", DELIMITERS},
|
||||
{"desc", DESC},
|
||||
{"disable", DISABLE_P},
|
||||
{"distinct", DISTINCT},
|
||||
{"do", DO},
|
||||
{"domain", DOMAIN_P},
|
||||
@@ -124,6 +125,7 @@ static const ScanKeyword ScanKeywords[] = {
|
||||
{"drop", DROP},
|
||||
{"each", EACH},
|
||||
{"else", ELSE},
|
||||
{"enable", ENABLE_P},
|
||||
{"encoding", ENCODING},
|
||||
{"encrypted", ENCRYPTED},
|
||||
{"end", END_P},
|
||||
|
Reference in New Issue
Block a user