On Fri, Feb 11, 2011 at 02:49:27PM -0500, Robert Haas wrote:
> You might want to consider a second boolean in lieu of a three way
> enum.  I'm not sure if that's cleaner but if it lets you write:
> 
> if (blah)
>     at->verify = true;
> 
> instead of:
> 
> if (blah)
>      at->worklevel = Min(at->worklevel, WORK_VERIFY);
> 
> ...then I think that might be cleaner.

Good point; the Max() calls did not make much sense all by themselves.  The
point was to make sure nothing decreased the worklevel.  Wrapping them in a
macro, say, ATRequireWork, probably would have helped.

That said, I've tried both constructions, and I marginally prefer the end result
with AlteredTableInfo.verify.  I've inlined ATColumnChangeRequiresRewrite into
ATPrepAlterColumnType; it would need to either pass back two bools or take an
AlteredTableInfo arg to mutate, so this seemed cleaner.  I've omitted the
assertion that my previous version added to ATRewriteTable; it was helpful for
other scan-only type changes, but it's excessive for domains alone.  Otherwise,
the differences are cosmetic.

The large block in ATRewriteTable is now superfluous.  For easier review, I
haven't removed it.

I missed a typo in the last patch: "T if we a rewrite is forced".  Not changed
in this patch as I assume you'll want to commit it separately.

nm
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 452ced6..466be25 100644
diff --git a/src/backend/commands/index 1db42d0..2e10661 100644
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 142,147 **** typedef struct AlteredTableInfo
--- 142,148 ----
        List       *newvals;            /* List of NewColumnValue */
        bool            new_notnull;    /* T if we added new NOT NULL 
constraints */
        bool            rewrite;                /* T if we a rewrite is forced 
*/
+       bool            verify;                 /* T if we shall verify 
constraints */
        Oid                     newTableSpace;  /* new tablespace; 0 means no 
change */
        /* Objects to rebuild after completing ALTER TYPE operations */
        List       *changedConstraintOids;      /* OIDs of constraints to 
rebuild */
***************
*** 336,342 **** static void ATPrepAlterColumnType(List **wqueue,
                                          AlteredTableInfo *tab, Relation rel,
                                          bool recurse, bool recursing,
                                          AlterTableCmd *cmd, LOCKMODE 
lockmode);
- static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
  static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
                                          const char *colName, TypeName 
*typeName, LOCKMODE lockmode);
  static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, 
LOCKMODE lockmode);
--- 337,342 ----
***************
*** 3242,3247 **** ATRewriteTables(List **wqueue, LOCKMODE lockmode)
--- 3242,3251 ----
                        heap_close(rel, NoLock);
                }
  
+               /* New NOT NULL constraints always require a scan. */
+               if (tab->new_notnull)
+                       tab->verify = true;
+ 
                /*
                 * We only need to rewrite the table if at least one column 
needs to
                 * be recomputed, or we are adding/removing the OID column.
***************
*** 3313,3319 **** ATRewriteTables(List **wqueue, LOCKMODE lockmode)
                         * 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);
  
                        /*
--- 3317,3323 ----
                         * Test the current data within the table against new 
constraints
                         * generated by ALTER TABLE commands, but don't rebuild 
data.
                         */
!                       if (tab->verify)
                                ATRewriteTable(tab, InvalidOid, lockmode);
  
                        /*
***************
*** 3387,3393 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, 
LOCKMODE lockmode)
        Relation        newrel;
        TupleDesc       oldTupDesc;
        TupleDesc       newTupDesc;
-       bool            needscan = false;
        List       *notnull_attrs;
        int                     i;
        ListCell   *l;
--- 3391,3396 ----
***************
*** 3446,3452 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, 
LOCKMODE lockmode)
                switch (con->contype)
                {
                        case CONSTR_CHECK:
-                               needscan = true;
                                con->qualstate = (List *)
                                        ExecPrepareExpr((Expr *) con->qual, 
estate);
                                break;
--- 3449,3454 ----
***************
*** 3481,3491 **** 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;
--- 3483,3490 ----
***************
*** 3549,3558 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, 
LOCKMODE lockmode)
  
                while ((tuple = heap_getnext(scan, ForwardScanDirection)) != 
NULL)
                {
!                       if (tab->rewrite)
!                       {
!                               Oid                     tupOid = InvalidOid;
  
                                /* Extract data from old tuple */
                                heap_deform_tuple(tuple, oldTupDesc, values, 
isnull);
                                if (oldTupDesc->tdhasoid)
--- 3548,3557 ----
  
                while ((tuple = heap_getnext(scan, ForwardScanDirection)) != 
NULL)
                {
!                       Oid                     tupOid = InvalidOid;
  
+                       if (newrel)
+                       {
                                /* Extract data from old tuple */
                                heap_deform_tuple(tuple, oldTupDesc, values, 
isnull);
                                if (oldTupDesc->tdhasoid)
***************
*** 3561,3570 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, 
LOCKMODE lockmode)
                                /* Set dropped attributes to null in new tuple 
*/
                                foreach(lc, dropped_attrs)
                                        isnull[lfirst_int(lc)] = true;
  
                                /*
                                 * Process supplied expressions to replace 
selected columns.
!                                * Expression inputs come from the old tuple.
                                 */
                                ExecStoreTuple(tuple, oldslot, InvalidBuffer, 
false);
                                econtext->ecxt_scantuple = oldslot;
--- 3560,3574 ----
                                /* Set dropped attributes to null in new tuple 
*/
                                foreach(lc, dropped_attrs)
                                        isnull[lfirst_int(lc)] = true;
+                       }
  
+                       if (tab->newvals != NIL)
+                       {
                                /*
                                 * Process supplied expressions to replace 
selected columns.
!                                * Expression inputs come from the old tuple.  
If !newrel, we've
!                                * proven that no expression will change a 
tuple value, but they
!                                * may throw errors.
                                 */
                                ExecStoreTuple(tuple, oldslot, InvalidBuffer, 
false);
                                econtext->ecxt_scantuple = oldslot;
***************
*** 3578,3584 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, 
LOCKMODE lockmode)
--- 3582,3591 ----
                                                                                
                         &isnull[ex->attnum - 1],
                                                                                
                                  NULL);
                                }
+                       }
  
+                       if (newrel)
+                       {
                                /*
                                 * Form the new tuple. Note that we don't 
explicitly pfree it,
                                 * since the per-tuple memory context will be 
reset shortly.
***************
*** 5270,5275 **** ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, 
Relation rel,
--- 5277,5283 ----
                newcon->qual = (Node *) make_ands_implicit((Expr *) ccon->expr);
  
                tab->constraints = lappend(tab->constraints, newcon);
+               tab->verify = true;
  
                /* Save the actually assigned name if it was defaulted */
                if (constr->conname == NULL)
***************
*** 5618,5623 **** ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation 
rel,
--- 5626,5635 ----
                newcon->qual = (Node *) fkconstraint;
  
                tab->constraints = lappend(tab->constraints, newcon);
+               /*
+                * No need to set tab->verify; foreign key validation is a 
distinct
+                * aspect of Phase 3.
+                */
        }
  
        /*
***************
*** 6581,6588 **** ATPrepAlterColumnType(List **wqueue,
                newval->expr = (Expr *) transform;
  
                tab->newvals = lappend(tab->newvals, newval);
!               if (ATColumnChangeRequiresRewrite(transform, attnum))
!                       tab->rewrite = true;
        }
        else if (tab->relkind == RELKIND_FOREIGN_TABLE)
        {
--- 6593,6625 ----
                newval->expr = (Expr *) transform;
  
                tab->newvals = lappend(tab->newvals, newval);
! 
!               /*
!                * Decide how much phase-3 per-tuple work this change entails.  
None
!                * needed when the present type changes to itself, to a 
constraint-free
!                * domain thereon, or to a type to which it is binary 
coercible.  Any
!                * constrained domain requires a verification scan.  Anything 
else
!                * requires a rewrite.  Beware of a USING clause trying to 
substitute
!                * some other value.
!                */
!               while (!tab->rewrite)
!               {
!                       /* only one varno, so no need to check that */
!                       if (IsA(transform, Var) && ((Var *) 
transform)->varattno == attnum)
!                               break;
!                       else if (IsA(transform, RelabelType))
!                               transform = (Node *) ((RelabelType *) 
transform)->arg;
!                       else if (IsA(transform, CoerceToDomain))
!                       {
!                               CoerceToDomain *d = (CoerceToDomain *) 
transform;
! 
!                               if (GetDomainConstraints(d->resulttype) != NIL)
!                                       tab->verify = true;
!                               transform = (Node *) d->arg;
!                       }
!                       else
!                               tab->rewrite = true;
!               }
        }
        else if (tab->relkind == RELKIND_FOREIGN_TABLE)
        {
***************
*** 6622,6650 **** ATPrepAlterColumnType(List **wqueue,
                ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
  }
  
- /*
-  * When the data type of a column is changed, a rewrite might not be require
-  * if the data type is being changed to its current type, or more 
interestingly
-  * to a type to which it is binary coercible.  But we must check carefully 
that
-  * the USING clause isn't trying to insert some other value.
-  */
- static bool
- ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
- {
-       Assert(expr != NULL);
- 
-       for (;;)
-       {
-               /* only one varno, so no need to check that */
-               if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
-                       return false;
-               else if (IsA(expr, RelabelType))
-                       expr = (Node *) ((RelabelType *) expr)->arg;
-               else
-                       return true;
-       }
- }
- 
  static void
  ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
                                          const char *colName, TypeName 
*typeName, LOCKMODE lockmode)
--- 6659,6664 ----
diff --git a/src/test/regress/GNUmakefiindex 4c8af0f..eeb9487 100644
diff --git a/src/test/regress/expecnew file mode 100644
index 0000000..248fb39
diff --git a/src/test/regress/parallel_schedule b/srindex 3b99e86..0420922 
100644
diff --git a/src/test/regress/serial_scheindex b348f0e..9954cf7 100644
diff --git a/src/test/regress/sql/big_anew file mode 100644
index 0000000..8302d87
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to