6
6
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7
7
* Portions Copyright (c) 1994, Regents of the University of California
8
8
*
9
- *$Id: analyze.c,v 1.138 2000/02/29 12:28:25 wieck Exp $
9
+ *$Id: analyze.c,v 1.139 2000/03/01 05:18:20 tgl Exp $
10
10
*
11
11
*-------------------------------------------------------------------------
12
12
*/
@@ -44,6 +44,7 @@ static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt);
44
44
45
45
static void transformForUpdate (Query * qry ,List * forUpdate );
46
46
static void transformFkeyGetPrimaryKey (FkConstraint * fkconstraint );
47
+ static void transformConstraintAttrs (List * constraintList );
47
48
static void transformColumnType (ParseState * pstate ,ColumnDef * column );
48
49
49
50
/* kluge to return extra info from transformCreateStmt() */
@@ -589,6 +590,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
589
590
IndexStmt * index ,
590
591
* pkey = NULL ;
591
592
IndexElem * iparam ;
593
+ bool saw_nullable ;
592
594
593
595
q = makeNode (Query );
594
596
q -> commandType = CMD_UTILITY ;
@@ -621,6 +623,12 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
621
623
FuncCall * funccallnode ;
622
624
CreateSeqStmt * sequence ;
623
625
626
+ /*
627
+ * Create appropriate constraints for SERIAL. We do this
628
+ * in full, rather than shortcutting, so that we will
629
+ * detect any conflicting constraints the user wrote
630
+ * (like a different DEFAULT).
631
+ */
624
632
sname = makeObjectName (stmt -> relname ,column -> colname ,
625
633
"seq" );
626
634
/*
@@ -644,27 +652,37 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
644
652
constraint -> raw_expr = (Node * )funccallnode ;
645
653
constraint -> cooked_expr = NULL ;
646
654
constraint -> keys = NULL ;
647
-
648
- column -> constraints = lappend ( column -> constraints , constraint );
655
+ column -> constraints = lappend ( column -> constraints ,
656
+ constraint );
649
657
650
658
constraint = makeNode (Constraint );
651
659
constraint -> contype = CONSTR_UNIQUE ;
652
660
constraint -> name = makeObjectName (stmt -> relname ,
653
661
column -> colname ,
654
662
"key" );
655
- column -> constraints = lappend (column -> constraints ,constraint );
663
+ column -> constraints = lappend (column -> constraints ,
664
+ constraint );
665
+
666
+ constraint = makeNode (Constraint );
667
+ constraint -> contype = CONSTR_NOTNULL ;
668
+ column -> constraints = lappend (column -> constraints ,
669
+ constraint );
656
670
657
671
sequence = makeNode (CreateSeqStmt );
658
672
sequence -> seqname = pstrdup (sname );
659
673
sequence -> options = NIL ;
660
674
661
675
elog (NOTICE ,"CREATE TABLE will create implicit sequence '%s' for SERIAL column '%s.%s'" ,
662
- sequence -> seqname ,stmt -> relname ,column -> colname );
676
+ sequence -> seqname ,stmt -> relname ,column -> colname );
663
677
664
678
blist = lcons (sequence ,NIL );
665
679
}
666
680
667
681
/* Process column constraints, if any... */
682
+ transformConstraintAttrs (column -> constraints );
683
+
684
+ saw_nullable = false;
685
+
668
686
foreach (clist ,column -> constraints )
669
687
{
670
688
constraint = lfirst (clist );
@@ -676,7 +694,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
676
694
* to be processed later.
677
695
* ----------
678
696
*/
679
- if (nodeTag (constraint ) == T_FkConstraint )
697
+ if (IsA (constraint , FkConstraint ) )
680
698
{
681
699
Ident * id = makeNode (Ident );
682
700
id -> name = column -> colname ;
@@ -693,23 +711,19 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
693
711
switch (constraint -> contype )
694
712
{
695
713
case CONSTR_NULL :
696
-
697
- /*
698
- * We should mark this explicitly, so we
699
- * can tell if NULL and NOT NULL are both
700
- * specified
701
- */
702
- if (column -> is_not_null )
714
+ if (saw_nullable && column -> is_not_null )
703
715
elog (ERROR ,"CREATE TABLE/(NOT) NULL conflicting declaration"
704
716
" for '%s.%s'" ,stmt -> relname ,column -> colname );
705
717
column -> is_not_null = FALSE;
718
+ saw_nullable = true;
706
719
break ;
707
720
708
721
case CONSTR_NOTNULL :
709
- if (column -> is_not_null )
710
- elog (ERROR ,"CREATE TABLE/NOT NULLalready specified "
722
+ if (saw_nullable && ! column -> is_not_null )
723
+ elog (ERROR ,"CREATE TABLE/( NOT) NULLconflicting declaration "
711
724
" for '%s.%s'" ,stmt -> relname ,column -> colname );
712
725
column -> is_not_null = TRUE;
726
+ saw_nullable = true;
713
727
break ;
714
728
715
729
case CONSTR_DEFAULT :
@@ -742,6 +756,13 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
742
756
constraints = lappend (constraints ,constraint );
743
757
break ;
744
758
759
+ case CONSTR_ATTR_DEFERRABLE :
760
+ case CONSTR_ATTR_NOT_DEFERRABLE :
761
+ case CONSTR_ATTR_DEFERRED :
762
+ case CONSTR_ATTR_IMMEDIATE :
763
+ /* transformConstraintAttrs took care of these */
764
+ break ;
765
+
745
766
default :
746
767
elog (ERROR ,"parser: unrecognized constraint (internal error)" );
747
768
break ;
@@ -767,10 +788,16 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
767
788
constraints = lappend (constraints ,constraint );
768
789
break ;
769
790
791
+ case CONSTR_NULL :
770
792
case CONSTR_NOTNULL :
771
793
case CONSTR_DEFAULT :
794
+ case CONSTR_ATTR_DEFERRABLE :
795
+ case CONSTR_ATTR_NOT_DEFERRABLE :
796
+ case CONSTR_ATTR_DEFERRED :
797
+ case CONSTR_ATTR_IMMEDIATE :
772
798
elog (ERROR ,"parser: illegal context for constraint (internal error)" );
773
799
break ;
800
+
774
801
default :
775
802
elog (ERROR ,"parser: unrecognized constraint (internal error)" );
776
803
break ;
@@ -1999,6 +2026,95 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
1999
2026
heap_close (pkrel ,AccessShareLock );
2000
2027
}
2001
2028
2029
+ /*
2030
+ * Preprocess a list of column constraint clauses
2031
+ * to attach constraint attributes to their primary constraint nodes
2032
+ * and detect inconsistent/misplaced constraint attributes.
2033
+ *
2034
+ * NOTE: currently, attributes are only supported for FOREIGN KEY primary
2035
+ * constraints, but someday they ought to be supported for other constraints.
2036
+ */
2037
+ static void
2038
+ transformConstraintAttrs (List * constraintList )
2039
+ {
2040
+ Node * lastprimarynode = NULL ;
2041
+ bool saw_deferrability = false;
2042
+ bool saw_initially = false;
2043
+ List * clist ;
2044
+
2045
+ foreach (clist ,constraintList )
2046
+ {
2047
+ Node * node = lfirst (clist );
2048
+
2049
+ if (!IsA (node ,Constraint ))
2050
+ {
2051
+ lastprimarynode = node ;
2052
+ /* reset flags for new primary node */
2053
+ saw_deferrability = false;
2054
+ saw_initially = false;
2055
+ }
2056
+ else
2057
+ {
2058
+ Constraint * con = (Constraint * )node ;
2059
+
2060
+ switch (con -> contype )
2061
+ {
2062
+ case CONSTR_ATTR_DEFERRABLE :
2063
+ if (lastprimarynode == NULL ||
2064
+ !IsA (lastprimarynode ,FkConstraint ))
2065
+ elog (ERROR ,"Misplaced DEFERRABLE clause" );
2066
+ if (saw_deferrability )
2067
+ elog (ERROR ,"Multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed" );
2068
+ saw_deferrability = true;
2069
+ ((FkConstraint * )lastprimarynode )-> deferrable = true;
2070
+ break ;
2071
+ case CONSTR_ATTR_NOT_DEFERRABLE :
2072
+ if (lastprimarynode == NULL ||
2073
+ !IsA (lastprimarynode ,FkConstraint ))
2074
+ elog (ERROR ,"Misplaced NOT DEFERRABLE clause" );
2075
+ if (saw_deferrability )
2076
+ elog (ERROR ,"Multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed" );
2077
+ saw_deferrability = true;
2078
+ ((FkConstraint * )lastprimarynode )-> deferrable = false;
2079
+ if (saw_initially &&
2080
+ ((FkConstraint * )lastprimarynode )-> initdeferred )
2081
+ elog (ERROR ,"INITIALLY DEFERRED constraint must be DEFERRABLE" );
2082
+ break ;
2083
+ case CONSTR_ATTR_DEFERRED :
2084
+ if (lastprimarynode == NULL ||
2085
+ !IsA (lastprimarynode ,FkConstraint ))
2086
+ elog (ERROR ,"Misplaced INITIALLY DEFERRED clause" );
2087
+ if (saw_initially )
2088
+ elog (ERROR ,"Multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed" );
2089
+ saw_initially = true;
2090
+ ((FkConstraint * )lastprimarynode )-> initdeferred = true;
2091
+ /* If only INITIALLY DEFERRED appears, assume DEFERRABLE */
2092
+ if (!saw_deferrability )
2093
+ ((FkConstraint * )lastprimarynode )-> deferrable = true;
2094
+ else if (! ((FkConstraint * )lastprimarynode )-> deferrable )
2095
+ elog (ERROR ,"INITIALLY DEFERRED constraint must be DEFERRABLE" );
2096
+ break ;
2097
+ case CONSTR_ATTR_IMMEDIATE :
2098
+ if (lastprimarynode == NULL ||
2099
+ !IsA (lastprimarynode ,FkConstraint ))
2100
+ elog (ERROR ,"Misplaced INITIALLY IMMEDIATE clause" );
2101
+ if (saw_initially )
2102
+ elog (ERROR ,"Multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed" );
2103
+ saw_initially = true;
2104
+ ((FkConstraint * )lastprimarynode )-> initdeferred = false;
2105
+ break ;
2106
+ default :
2107
+ /* Otherwise it's not an attribute */
2108
+ lastprimarynode = node ;
2109
+ /* reset flags for new primary node */
2110
+ saw_deferrability = false;
2111
+ saw_initially = false;
2112
+ break ;
2113
+ }
2114
+ }
2115
+ }
2116
+ }
2117
+
2002
2118
/*
2003
2119
* Special handling of type definition for a column
2004
2120
*/
@@ -2027,4 +2143,3 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
2027
2143
}
2028
2144
}
2029
2145
}
2030
-