8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.192 2006/07/03 22:45:38 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.193 2006/07/10 22:10:39 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -123,6 +123,7 @@ typedef struct AlteredTableInfo
123
123
/* Information saved by Phases 1/2 for Phase 3: */
124
124
List * constraints ; /* List of NewConstraint */
125
125
List * newvals ; /* List of NewColumnValue */
126
+ bool new_notnull ; /* T if we added new NOT NULL constraints */
126
127
Oid newTableSpace ; /* new tablespace; 0 means no change */
127
128
/* Objects to rebuild after completing ALTER TYPE operations */
128
129
List * changedConstraintOids ; /* OIDs of constraints to rebuild */
@@ -132,11 +133,11 @@ typedef struct AlteredTableInfo
132
133
} AlteredTableInfo ;
133
134
134
135
/* Struct describing one new constraint to check in Phase 3 scan */
136
+ /* Note: new NOT NULL constraints are handled elsewhere */
135
137
typedef struct NewConstraint
136
138
{
137
139
char * name ; /* Constraint name, or NULL if none */
138
- ConstrType contype ; /* CHECK, NOT_NULL, or FOREIGN */
139
- AttrNumber attnum ; /* only relevant for NOT_NULL */
140
+ ConstrType contype ; /* CHECK or FOREIGN */
140
141
Oid refrelid ; /* PK rel, if FOREIGN */
141
142
Node * qual ; /* Check expr or FkConstraint struct */
142
143
List * qualstate ; /* Execution state for CHECK */
@@ -2438,7 +2439,7 @@ ATRewriteTables(List **wqueue)
2438
2439
* Test the current data within the table against new constraints
2439
2440
* generated by ALTER TABLE commands, but don't rebuild data.
2440
2441
*/
2441
- if (tab -> constraints != NIL )
2442
+ if (tab -> constraints != NIL || tab -> new_notnull )
2442
2443
ATRewriteTable (tab , InvalidOid );
2443
2444
2444
2445
/*
@@ -2504,6 +2505,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
2504
2505
TupleDesc oldTupDesc ;
2505
2506
TupleDesc newTupDesc ;
2506
2507
bool needscan = false;
2508
+ List * notnull_attrs ;
2507
2509
int i ;
2508
2510
ListCell * l ;
2509
2511
EState * estate ;
@@ -2554,9 +2556,6 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
2554
2556
case CONSTR_FOREIGN :
2555
2557
/* Nothing to do here */
2556
2558
break ;
2557
- case CONSTR_NOTNULL :
2558
- needscan = true;
2559
- break ;
2560
2559
default :
2561
2560
elog (ERROR , "unrecognized constraint type: %d" ,
2562
2561
(int ) con -> contype );
@@ -2572,6 +2571,25 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
2572
2571
ex -> exprstate = ExecPrepareExpr ((Expr * ) ex -> expr , estate );
2573
2572
}
2574
2573
2574
+ notnull_attrs = NIL ;
2575
+ if (newrel || tab -> new_notnull )
2576
+ {
2577
+ /*
2578
+ * If we are rebuilding the tuples OR if we added any new NOT NULL
2579
+ * constraints, check all not-null constraints. This is a bit of
2580
+ * overkill but it minimizes risk of bugs, and heap_attisnull is
2581
+ * a pretty cheap test anyway.
2582
+ */
2583
+ for (i = 0 ; i < newTupDesc -> natts ; i ++ )
2584
+ {
2585
+ if (newTupDesc -> attrs [i ]-> attnotnull &&
2586
+ !newTupDesc -> attrs [i ]-> attisdropped )
2587
+ notnull_attrs = lappend_int (notnull_attrs , i );
2588
+ }
2589
+ if (notnull_attrs )
2590
+ needscan = true;
2591
+ }
2592
+
2575
2593
if (needscan )
2576
2594
{
2577
2595
ExprContext * econtext ;
@@ -2672,6 +2690,17 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
2672
2690
ExecStoreTuple (tuple , newslot , InvalidBuffer , false);
2673
2691
econtext -> ecxt_scantuple = newslot ;
2674
2692
2693
+ foreach (l , notnull_attrs )
2694
+ {
2695
+ int attn = lfirst_int (l );
2696
+
2697
+ if (heap_attisnull (tuple , attn + 1 ))
2698
+ ereport (ERROR ,
2699
+ (errcode (ERRCODE_NOT_NULL_VIOLATION ),
2700
+ errmsg ("column \"%s\" contains null values" ,
2701
+ NameStr (newTupDesc -> attrs [attn ]-> attname ))));
2702
+ }
2703
+
2675
2704
foreach (l , tab -> constraints )
2676
2705
{
2677
2706
NewConstraint * con = lfirst (l );
@@ -2685,21 +2714,6 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
2685
2714
errmsg ("check constraint \"%s\" is violated by some row" ,
2686
2715
con -> name )));
2687
2716
break ;
2688
- case CONSTR_NOTNULL :
2689
- {
2690
- Datum d ;
2691
- bool isnull ;
2692
-
2693
- d = heap_getattr (tuple , con -> attnum , newTupDesc ,
2694
- & isnull );
2695
- if (isnull )
2696
- ereport (ERROR ,
2697
- (errcode (ERRCODE_NOT_NULL_VIOLATION ),
2698
- errmsg ("column \"%s\" contains null values" ,
2699
- get_attname (tab -> relid ,
2700
- con -> attnum ))));
2701
- }
2702
- break ;
2703
2717
case CONSTR_FOREIGN :
2704
2718
/* Nothing to do here */
2705
2719
break ;
@@ -3398,7 +3412,6 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
3398
3412
HeapTuple tuple ;
3399
3413
AttrNumber attnum ;
3400
3414
Relation attr_rel ;
3401
- NewConstraint * newcon ;
3402
3415
3403
3416
/*
3404
3417
* lookup the attribute
@@ -3434,13 +3447,8 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
3434
3447
/* keep the system catalog indexes current */
3435
3448
CatalogUpdateIndexes (attr_rel , tuple );
3436
3449
3437
- /* Tell Phase 3 to test the constraint */
3438
- newcon = (NewConstraint * ) palloc0 (sizeof (NewConstraint ));
3439
- newcon -> contype = CONSTR_NOTNULL ;
3440
- newcon -> attnum = attnum ;
3441
- newcon -> name = "NOT NULL" ;
3442
-
3443
- tab -> constraints = lappend (tab -> constraints , newcon );
3450
+ /* Tell Phase 3 it needs to test the constraint */
3451
+ tab -> new_notnull = true;
3444
3452
}
3445
3453
3446
3454
heap_close (attr_rel , RowExclusiveLock );
@@ -3909,7 +3917,6 @@ ATExecAddConstraint(AlteredTableInfo *tab, Relation rel, Node *newConstraint)
3909
3917
newcon = (NewConstraint * ) palloc0 (sizeof (NewConstraint ));
3910
3918
newcon -> name = ccon -> name ;
3911
3919
newcon -> contype = ccon -> contype ;
3912
- newcon -> attnum = ccon -> attnum ;
3913
3920
/* ExecQual wants implicit-AND format */
3914
3921
newcon -> qual = (Node * )
3915
3922
make_ands_implicit ((Expr * ) ccon -> expr );
0 commit comments