at1.3w-tablecmds-enum.patch

text/plain

Filename: at1.3w-tablecmds-enum.patch
Type: text/plain
Part: 3
Message: Re: ALTER TYPE 2: skip already-provable no-work rewrites

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/commands/tablecmds.c 0 0
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 78262d8..63e2538 100644
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 129,134 **** static List *on_commits = NIL;
--- 129,137 ----
  #define AT_PASS_MISC			8		/* other stuff */
  #define AT_NUM_PASSES			9
  
+ /* Level of effort required in Phase 3 (ATRewriteTables). */
+ typedef enum { WORK_NONE = 0, WORK_SCAN = 1, WORK_REWRITE = 2 } WorkLevel;
+ 
  typedef struct AlteredTableInfo
  {
  	/* Information saved before any work commences: */
***************
*** 141,147 **** 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		new_changeoids; /* T if we added/dropped the OID column */
  	Oid			newTableSpace;	/* new tablespace; 0 means no change */
  	/* Objects to rebuild after completing ALTER TYPE operations */
  	List	   *changedConstraintOids;	/* OIDs of constraints to rebuild */
--- 144,150 ----
  	List	   *constraints;	/* List of NewConstraint */
  	List	   *newvals;		/* List of NewColumnValue */
  	bool		new_notnull;	/* T if we added new NOT NULL constraints */
! 	WorkLevel	worklevel;		/* How much work shall we do on the heap? */
  	Oid			newTableSpace;	/* new tablespace; 0 means no change */
  	/* Objects to rebuild after completing ALTER TYPE operations */
  	List	   *changedConstraintOids;	/* OIDs of constraints to rebuild */
***************
*** 3180,3190 **** ATRewriteTables(List **wqueue, LOCKMODE lockmode)
  		if (tab->relkind == RELKIND_FOREIGN_TABLE)
  			continue;
  
! 		/*
! 		 * We only need to rewrite the table if at least one column needs to
! 		 * be recomputed, or we are adding/removing the OID column.
! 		 */
! 		if (tab->newvals != NIL || tab->new_changeoids)
  		{
  			/* Build a temporary relation and copy data */
  			Relation	OldHeap;
--- 3183,3195 ----
  		if (tab->relkind == RELKIND_FOREIGN_TABLE)
  			continue;
  
! 		/* New NOT NULL constraints always require a scan. */
! 		if (tab->new_notnull)
! 			tab->worklevel = Max(tab->worklevel, WORK_SCAN);
! 
! 		switch (tab->worklevel)
! 		{
! 			case WORK_REWRITE:
  		{
  			/* Build a temporary relation and copy data */
  			Relation	OldHeap;
***************
*** 3194,3202 **** ATRewriteTables(List **wqueue, LOCKMODE lockmode)
  			OldHeap = heap_open(tab->relid, NoLock);
  
  			/*
! 			 * We don't support rewriting of system catalogs; there are too
! 			 * many corner cases and too little benefit.  In particular this
! 			 * is certainly not going to work for mapped catalogs.
  			 */
  			if (IsSystemRelation(OldHeap))
  				ereport(ERROR,
--- 3199,3207 ----
  			OldHeap = heap_open(tab->relid, NoLock);
  
  			/*
! 					 * We don't support rewriting of system catalogs; there are
! 					 * too many corner cases and too little benefit.  In
! 					 * particular, it would fail for mapped catalogs.
  			 */
  			if (IsSystemRelation(OldHeap))
  				ereport(ERROR,
***************
*** 3205,3212 **** ATRewriteTables(List **wqueue, LOCKMODE lockmode)
  								RelationGetRelationName(OldHeap))));
  
  			/*
! 			 * Don't allow rewrite on temp tables of other backends ... their
! 			 * local buffer manager is not going to cope.
  			 */
  			if (RELATION_IS_OTHER_TEMP(OldHeap))
  				ereport(ERROR,
--- 3210,3217 ----
  								RelationGetRelationName(OldHeap))));
  
  			/*
! 					 * Don't allow rewrite on temp tables of other backends
! 					 * ... their local buffer manager is not going to cope.
  			 */
  			if (RELATION_IS_OTHER_TEMP(OldHeap))
  				ereport(ERROR,
***************
*** 3214,3221 **** ATRewriteTables(List **wqueue, LOCKMODE lockmode)
  				errmsg("cannot rewrite temporary tables of other sessions")));
  
  			/*
! 			 * Select destination tablespace (same as original unless user
! 			 * requested a change)
  			 */
  			if (tab->newTableSpace)
  				NewTableSpace = tab->newTableSpace;
--- 3219,3226 ----
  				errmsg("cannot rewrite temporary tables of other sessions")));
  
  			/*
! 					 * Select destination tablespace (same as original unless
! 					 * user requested a change)
  			 */
  			if (tab->newTableSpace)
  				NewTableSpace = tab->newTableSpace;
***************
*** 3224,3265 **** ATRewriteTables(List **wqueue, LOCKMODE lockmode)
  
  			heap_close(OldHeap, NoLock);
  
! 			/* Create transient table that will receive the modified data */
  			OIDNewHeap = make_new_heap(tab->relid, NewTableSpace);
  
  			/*
  			 * Copy the heap data into the new table with the desired
  			 * modifications, and test the current data within the table
! 			 * against new constraints generated by ALTER TABLE commands.
  			 */
  			ATRewriteTable(tab, OIDNewHeap, lockmode);
  
  			/*
! 			 * Swap the physical files of the old and new heaps, then rebuild
! 			 * indexes and discard the old heap.  We can use RecentXmin for
! 			 * the table's new relfrozenxid because we rewrote all the tuples
! 			 * in ATRewriteTable, so no older Xid remains in the table.  Also,
! 			 * we never try to swap toast tables by content, since we have no
! 			 * interest in letting this code work on system catalogs.
  			 */
  			finish_heap_swap(tab->relid, OIDNewHeap,
  							 false, false, true, RecentXmin);
  		}
! 		else
! 		{
! 			/*
! 			 * Test the current data within the table against new constraints
! 			 * generated by ALTER TABLE commands, but don't rebuild data.
! 			 */
! 			if (tab->constraints != NIL || tab->new_notnull)
  				ATRewriteTable(tab, InvalidOid, lockmode);
  
  			/*
  			 * If we had SET TABLESPACE but no reason to reconstruct tuples,
  			 * just do a block-by-block copy.
  			 */
  			if (tab->newTableSpace)
  				ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
  		}
  	}
  
--- 3229,3271 ----
  
  			heap_close(OldHeap, NoLock);
  
! 					/* Create transient table for the modified data */
  			OIDNewHeap = make_new_heap(tab->relid, NewTableSpace);
  
  			/*
  			 * Copy the heap data into the new table with the desired
  			 * modifications, and test the current data within the table
! 					 * against new constraints.
  			 */
  			ATRewriteTable(tab, OIDNewHeap, lockmode);
  
  			/*
! 					 * Swap the physical files of the old and new heaps, then
! 					 * rebuild indexes and discard the old heap.  We can use
! 					 * RecentXmin for the table's new relfrozenxid because we
! 					 * rewrote all the tuples in ATRewriteTable, so no older Xid
! 					 * remains in the table.  Also, we never try to swap toast
! 					 * tables by content, since we have no interest in letting
! 					 * this code work on system catalogs.
  			 */
  			finish_heap_swap(tab->relid, OIDNewHeap,
  							 false, false, true, RecentXmin);
  		}
! 				break;
! 
! 			case WORK_SCAN:
! 				/* Test the current table data. */
  				ATRewriteTable(tab, InvalidOid, lockmode);
+ 				break;
  
+ 			case WORK_NONE:
  			/*
  			 * If we had SET TABLESPACE but no reason to reconstruct tuples,
  			 * just do a block-by-block copy.
  			 */
  			if (tab->newTableSpace)
  				ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
+ 				break;
  		}
  	}
  
***************
*** 3320,3326 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
  	Relation	newrel;
  	TupleDesc	oldTupDesc;
  	TupleDesc	newTupDesc;
- 	bool		needscan = false;
  	List	   *notnull_attrs;
  	int			i;
  	ListCell   *l;
--- 3326,3331 ----
***************
*** 3328,3333 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
--- 3333,3348 ----
  	CommandId	mycid;
  	BulkInsertState bistate;
  	int			hi_options;
+ 	ExprContext *econtext;
+ 	Datum	   *values;
+ 	bool	   *isnull;
+ 	TupleTableSlot *oldslot;
+ 	TupleTableSlot *newslot;
+ 	HeapScanDesc scan;
+ 	HeapTuple	tuple;
+ 	MemoryContext oldCxt;
+ 	List	   *dropped_attrs = NIL;
+ 	ListCell   *lc;
  
  	/*
  	 * Open the relation(s).  We have surely already locked the existing
***************
*** 3379,3385 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
  		switch (con->contype)
  		{
  			case CONSTR_CHECK:
- 				needscan = true;
  				con->qualstate = (List *)
  					ExecPrepareExpr((Expr *) con->qual, estate);
  				break;
--- 3394,3399 ----
***************
*** 3414,3436 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
  				!newTupDesc->attrs[i]->attisdropped)
  				notnull_attrs = lappend_int(notnull_attrs, i);
  		}
- 		if (notnull_attrs)
- 			needscan = true;
  	}
  
- 	if (newrel || needscan)
- 	{
- 		ExprContext *econtext;
- 		Datum	   *values;
- 		bool	   *isnull;
- 		TupleTableSlot *oldslot;
- 		TupleTableSlot *newslot;
- 		HeapScanDesc scan;
- 		HeapTuple	tuple;
- 		MemoryContext oldCxt;
- 		List	   *dropped_attrs = NIL;
- 		ListCell   *lc;
- 
  		if (newrel)
  			ereport(DEBUG1,
  					(errmsg("Rewriting table \"%s\"",
--- 3428,3435 ----
***************
*** 3574,3580 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
  
  		ExecDropSingleTupleTableSlot(oldslot);
  		ExecDropSingleTupleTableSlot(newslot);
- 	}
  
  	FreeExecutorState(estate);
  
--- 3573,3578 ----
***************
*** 4271,4276 **** ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
--- 4269,4275 ----
  			newval->expr = defval;
  
  			tab->newvals = lappend(tab->newvals, newval);
+ 			tab->worklevel = WORK_REWRITE;
  		}
  
  		/*
***************
*** 4288,4294 **** ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
  	 */
  	if (isOid)
  	{
! 		tab->new_changeoids = true;
  
  		/* See comments in ATExecDropColumn. */
  		find_composite_type_dependencies(rel->rd_rel->reltype,
--- 4287,4293 ----
  	 */
  	if (isOid)
  	{
! 		tab->worklevel = WORK_REWRITE;
  
  		/* See comments in ATExecDropColumn. */
  		find_composite_type_dependencies(rel->rd_rel->reltype,
***************
*** 4967,4973 **** ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
  		tab = ATGetQueueEntry(wqueue, rel);
  
  		/* Tell Phase 3 to physically remove the OID column */
! 		tab->new_changeoids = true;
  
  		/*
  		 * We would also need to rewrite all tables using this table's rowtype
--- 4966,4972 ----
  		tab = ATGetQueueEntry(wqueue, rel);
  
  		/* Tell Phase 3 to physically remove the OID column */
! 		tab->worklevel = WORK_REWRITE;
  
  		/*
  		 * We would also need to rewrite all tables using this table's rowtype
***************
*** 5000,5006 **** ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
  	/* suppress schema rights check when rebuilding existing index */
  	check_rights = !is_rebuild;
  	/* skip index build if phase 3 will have to rewrite table anyway */
! 	skip_build = (tab->newvals != NIL);
  	/* suppress notices when rebuilding existing index */
  	quiet = is_rebuild;
  
--- 4999,5005 ----
  	/* suppress schema rights check when rebuilding existing index */
  	check_rights = !is_rebuild;
  	/* skip index build if phase 3 will have to rewrite table anyway */
! 	skip_build = (tab->worklevel == WORK_REWRITE);
  	/* suppress notices when rebuilding existing index */
  	quiet = is_rebuild;
  
***************
*** 5139,5144 **** ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
--- 5138,5144 ----
  		newcon->qual = (Node *) make_ands_implicit((Expr *) ccon->expr);
  
  		tab->constraints = lappend(tab->constraints, newcon);
+ 		tab->worklevel = Max(tab->worklevel, WORK_SCAN);
  
  		/* Save the actually assigned name if it was defaulted */
  		if (constr->conname == NULL)
***************
*** 5485,5490 **** ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
--- 5485,5494 ----
  		newcon->qual = (Node *) fkconstraint;
  
  		tab->constraints = lappend(tab->constraints, newcon);
+ 		/*
+ 		 * No need to set tab->worklevel; foreign key validation is a distinct
+ 		 * aspect of Phase 3.
+ 		 */
  	}
  
  	/*
***************
*** 6369,6374 **** ATPrepAlterColumnType(List **wqueue,
--- 6373,6379 ----
  		newval->expr = (Expr *) transform;
  
  		tab->newvals = lappend(tab->newvals, newval);
+ 		tab->worklevel = WORK_REWRITE;
  
  		/*
  		 * If we need to rewrite or scan this table, tables using its rowtype as