aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/tablecmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r--src/backend/commands/tablecmds.c64
1 files changed, 45 insertions, 19 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2333e1bed92..1e737a01c9f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -46,6 +46,7 @@
#include "commands/cluster.h"
#include "commands/comment.h"
#include "commands/defrem.h"
+#include "commands/event_trigger.h"
#include "commands/policy.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
@@ -153,7 +154,7 @@ typedef struct AlteredTableInfo
List *constraints; /* List of NewConstraint */
List *newvals; /* List of NewColumnValue */
bool new_notnull; /* T if we added new NOT NULL constraints */
- bool rewrite; /* T if a rewrite is forced */
+ int rewrite; /* Reason for forced rewrite, if any */
Oid newTableSpace; /* new tablespace; 0 means no change */
bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
char newrelpersistence; /* if above is true */
@@ -303,13 +304,15 @@ static void validateForeignKeyConstraint(char *conname,
static void createForeignKeyTriggers(Relation rel, Oid refRelOid,
Constraint *fkconstraint,
Oid constraintOid, Oid indexOid);
-static void ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode);
+static void ATController(AlterTableStmt *parsetree,
+ Relation rel, List *cmds, bool recurse, LOCKMODE lockmode);
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
bool recurse, bool recursing, LOCKMODE lockmode);
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode);
static void ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
AlterTableCmd *cmd, LOCKMODE lockmode);
-static void ATRewriteTables(List **wqueue, LOCKMODE lockmode);
+static void ATRewriteTables(AlterTableStmt *parsetree,
+ List **wqueue, LOCKMODE lockmode);
static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
static void ATSimplePermissions(Relation rel, int allowed_targets);
@@ -2724,7 +2727,8 @@ AlterTable(Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
CheckTableNotInUse(rel, "ALTER TABLE");
- ATController(rel, stmt->cmds, interpretInhOption(stmt->relation->inhOpt),
+ ATController(stmt,
+ rel, stmt->cmds, interpretInhOption(stmt->relation->inhOpt),
lockmode);
}
@@ -2747,7 +2751,7 @@ AlterTableInternal(Oid relid, List *cmds, bool recurse)
rel = relation_open(relid, lockmode);
- ATController(rel, cmds, recurse, lockmode);
+ ATController(NULL, rel, cmds, recurse, lockmode);
}
/*
@@ -3015,8 +3019,15 @@ AlterTableGetLockLevel(List *cmds)
return lockmode;
}
+/*
+ * ATController provides top level control over the phases.
+ *
+ * parsetree is passed in to allow it to be passed to event triggers
+ * when requested.
+ */
static void
-ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
+ATController(AlterTableStmt *parsetree,
+ Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
{
List *wqueue = NIL;
ListCell *lcmd;
@@ -3036,7 +3047,7 @@ ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
ATRewriteCatalogs(&wqueue, lockmode);
/* Phase 3: scan/rewrite tables as needed */
- ATRewriteTables(&wqueue, lockmode);
+ ATRewriteTables(parsetree, &wqueue, lockmode);
}
/*
@@ -3195,7 +3206,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
/* force rewrite if necessary; see comment in ATRewriteTables */
if (tab->chgPersistence)
{
- tab->rewrite = true;
+ tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
tab->newrelpersistence = RELPERSISTENCE_PERMANENT;
}
pass = AT_PASS_MISC;
@@ -3206,7 +3217,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
/* force rewrite if necessary; see comment in ATRewriteTables */
if (tab->chgPersistence)
{
- tab->rewrite = true;
+ tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE;
tab->newrelpersistence = RELPERSISTENCE_UNLOGGED;
}
pass = AT_PASS_MISC;
@@ -3607,7 +3618,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
* ATRewriteTables: ALTER TABLE phase 3
*/
static void
-ATRewriteTables(List **wqueue, LOCKMODE lockmode)
+ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
{
ListCell *ltab;
@@ -3634,7 +3645,7 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
* constraints, so it's not necessary/appropriate to enforce them just
* during ALTER.)
*/
- if (tab->newvals != NIL || tab->rewrite)
+ if (tab->newvals != NIL || tab->rewrite > 0)
{
Relation rel;
@@ -3655,7 +3666,7 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
* and assigns a new relfilenode, we automatically create or drop an
* init fork for the relation as appropriate.
*/
- if (tab->rewrite)
+ if (tab->rewrite > 0)
{
/* Build a temporary relation and copy data */
Relation OldHeap;
@@ -3710,6 +3721,21 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
heap_close(OldHeap, NoLock);
/*
+ * Fire off an Event Trigger now, before actually rewriting the
+ * table.
+ *
+ * We don't support Event Trigger for nested commands anywhere,
+ * here included, and parsetree is given NULL when coming from
+ * AlterTableInternal.
+ *
+ * And fire it only once.
+ */
+ if (parsetree)
+ EventTriggerTableRewrite((Node *)parsetree,
+ tab->relid,
+ tab->rewrite);
+
+ /*
* Create transient table that will receive the modified data.
*
* Ensure it is marked correctly as logged or unlogged. We have
@@ -4002,7 +4028,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
- if (tab->rewrite)
+ if (tab->rewrite > 0)
{
Oid tupOid = InvalidOid;
@@ -4828,7 +4854,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
newval->expr = expression_planner(defval);
tab->newvals = lappend(tab->newvals, newval);
- tab->rewrite = true;
+ tab->rewrite |= AT_REWRITE_DEFAULT_VAL;
}
/*
@@ -4845,7 +4871,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
* table to fix that.
*/
if (isOid)
- tab->rewrite = true;
+ tab->rewrite |= AT_REWRITE_ALTER_OID;
/*
* Add needed dependency entries for the new column.
@@ -5657,7 +5683,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
tab = ATGetQueueEntry(wqueue, rel);
/* Tell Phase 3 to physically remove the OID column */
- tab->rewrite = true;
+ tab->rewrite |= AT_REWRITE_ALTER_OID;
}
}
@@ -5683,7 +5709,7 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
/* suppress schema rights check when rebuilding existing index */
check_rights = !is_rebuild;
/* skip index build if phase 3 will do it or we're reusing an old one */
- skip_build = tab->rewrite || OidIsValid(stmt->oldNode);
+ skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
/* suppress notices when rebuilding existing index */
quiet = is_rebuild;
@@ -7686,7 +7712,7 @@ ATPrepAlterColumnType(List **wqueue,
tab->newvals = lappend(tab->newvals, newval);
if (ATColumnChangeRequiresRewrite(transform, attnum))
- tab->rewrite = true;
+ tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
}
else if (transform)
ereport(ERROR,
@@ -8431,7 +8457,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
con->old_pktable_oid = refRelId;
/* rewriting neither side of a FK */
if (con->contype == CONSTR_FOREIGN &&
- !rewrite && !tab->rewrite)
+ !rewrite && tab->rewrite == 0)
TryReuseForeignKey(oldId, con);
cmd->subtype = AT_ReAddConstraint;
tab->subcmds[AT_PASS_OLD_CONSTR] =