8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.89 2000/07/14 22:17:42 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.90 2000/07/15 12:37:14 momjian Exp $
12
12
*
13
13
* NOTES
14
14
* The PerformAddAttribute() code, like most of the relation
33
33
#include "utils/acl.h"
34
34
#include "utils/fmgroids.h"
35
35
#include "commands/trigger.h"
36
+
37
+ #include "parser/parse_expr.h"
38
+ #include "parser/parse_clause.h"
39
+ #include "parser/parse_relation.h"
40
+ #include "nodes/makefuncs.h"
41
+ #include "optimizer/planmain.h"
42
+ #include "optimizer/clauses.h"
43
+ #include "rewrite/rewriteSupport.h"
44
+ #include "commands/view.h"
45
+ #include "utils/temprel.h"
46
+ #include "executor/spi_priv.h"
47
+
36
48
#ifdef _DROP_COLUMN_HACK__
37
49
#include "catalog/pg_index.h"
38
50
#include "parser/parse.h"
@@ -1067,13 +1079,158 @@ void
1067
1079
AlterTableAddConstraint (const char * relationName ,
1068
1080
bool inh , Node * newConstraint )
1069
1081
{
1082
+ char rulequery [41 + NAMEDATALEN ];
1083
+ void * qplan ;
1084
+ char nulls [1 ]= "" ;
1085
+
1070
1086
if (newConstraint == NULL )
1071
1087
elog (ERROR , "ALTER TABLE / ADD CONSTRAINT passed invalid constraint." );
1072
1088
1089
+ #ifndef NO_SECURITY
1090
+ if (!pg_ownercheck (UserName , relationName , RELNAME ))
1091
+ elog (ERROR , "ALTER TABLE: permission denied" );
1092
+ #endif
1093
+
1094
+ /* check to see if the table to be constrained is a view. */
1095
+ sprintf (rulequery , "select * from pg_views where viewname='%s'" , relationName );
1096
+ if (SPI_connect ()!= SPI_OK_CONNECT )
1097
+ elog (ERROR , "ALTER TABLE: Unable to determine if %s is a view - SPI_connect failure.." , relationName );
1098
+ qplan = SPI_prepare (rulequery , 0 , NULL );
1099
+ if (!qplan )
1100
+ elog (ERROR , "ALTER TABLE: Unable to determine if %s is a view - SPI_prepare failure." , relationName );
1101
+ qplan = SPI_saveplan (qplan );
1102
+ if (SPI_execp (qplan , NULL , nulls , 1 )!= SPI_OK_SELECT )
1103
+ elog (ERROR , "ALTER TABLE: Unable to determine if %s is a view - SPI_execp failure." , relationName );
1104
+ if (SPI_processed != 0 )
1105
+ elog (ERROR , "ALTER TABLE: Cannot add constraints to views." );
1106
+ if (SPI_finish () != SPI_OK_FINISH )
1107
+ elog (NOTICE , "SPI_finish() failed in ALTER TABLE" );
1108
+
1073
1109
switch (nodeTag (newConstraint ))
1074
1110
{
1075
1111
case T_Constraint :
1076
- elog (ERROR , "ALTER TABLE / ADD CONSTRAINT is not implemented" );
1112
+ {
1113
+ Constraint * constr = (Constraint * )newConstraint ;
1114
+ switch (constr -> contype ) {
1115
+ case CONSTR_CHECK :
1116
+ {
1117
+ ParseState * pstate ;
1118
+ bool successful = TRUE;
1119
+ HeapScanDesc scan ;
1120
+ ExprContext * econtext ;
1121
+ TupleTableSlot * slot = makeNode (TupleTableSlot );
1122
+ HeapTuple tuple ;
1123
+ RangeTblEntry * rte = makeNode (RangeTblEntry );
1124
+ List * rtlist ;
1125
+ List * qual ;
1126
+ List * constlist ;
1127
+ Relation rel ;
1128
+ Node * expr ;
1129
+ char * name ;
1130
+ if (constr -> name )
1131
+ name = constr -> name ;
1132
+ else
1133
+ name = "<unnamed>" ;
1134
+
1135
+ rel = heap_openr (relationName , AccessExclusiveLock );
1136
+
1137
+ /*
1138
+ * Scan all of the rows, looking for a false match
1139
+ */
1140
+ scan = heap_beginscan (rel , false, SnapshotNow , 0 , NULL );
1141
+ AssertState (scan != NULL );
1142
+
1143
+ /*
1144
+ *We need to make a parse state and range table to allow us
1145
+ * to transformExpr and fix_opids to get a version of the
1146
+ * expression we can pass to ExecQual
1147
+ */
1148
+ pstate = make_parsestate (NULL );
1149
+ makeRangeTable (pstate , NULL );
1150
+ addRangeTableEntry (pstate , relationName ,
1151
+ makeAttr (relationName , NULL ), false, true,true);
1152
+ constlist = lcons (constr , NIL );
1153
+
1154
+ /* Convert the A_EXPR in raw_expr into an EXPR */
1155
+ expr = transformExpr (pstate , constr -> raw_expr , EXPR_COLUMN_FIRST );
1156
+
1157
+ /*
1158
+ * Make sure it yields a boolean result.
1159
+ */
1160
+ if (exprType (expr ) != BOOLOID )
1161
+ elog (ERROR , "CHECK '%s' does not yield boolean result" ,
1162
+ name );
1163
+
1164
+ /*
1165
+ * Make sure no outside relations are referred to.
1166
+ */
1167
+ if (length (pstate -> p_rtable ) != 1 )
1168
+ elog (ERROR , "Only relation '%s' can be referenced in CHECK" ,
1169
+ relationName );
1170
+
1171
+ /*
1172
+ * Might as well try to reduce any constant expressions.
1173
+ */
1174
+ expr = eval_const_expressions (expr );
1175
+
1176
+ /* And fix the opids */
1177
+ fix_opids (expr );
1178
+
1179
+ qual = lcons (expr , NIL );
1180
+ rte -> relname = relationName ;
1181
+ rte -> ref = makeNode (Attr );
1182
+ rte -> ref -> relname = rte -> relname ;
1183
+ rte -> relid = RelationGetRelid (rel );
1184
+ rtlist = lcons (rte , NIL );
1185
+
1186
+ /*
1187
+ * Scan through the rows now, making the necessary things for
1188
+ * ExecQual, and then call it to evaluate the expression.
1189
+ */
1190
+ while (HeapTupleIsValid (tuple = heap_getnext (scan , 0 )))
1191
+ {
1192
+ slot -> val = tuple ;
1193
+ slot -> ttc_shouldFree = false;
1194
+ slot -> ttc_descIsNew = true;
1195
+ slot -> ttc_tupleDescriptor = rel -> rd_att ;
1196
+ slot -> ttc_buffer = InvalidBuffer ;
1197
+ slot -> ttc_whichplan = -1 ;
1198
+
1199
+ econtext = MakeExprContext (slot , CurrentMemoryContext );
1200
+ econtext -> ecxt_range_table = rtlist ; /* range table */
1201
+ if (!ExecQual (qual , econtext , true)) {
1202
+ successful = false;
1203
+ break ;
1204
+ }
1205
+ FreeExprContext (econtext );
1206
+ }
1207
+
1208
+ pfree (slot );
1209
+ pfree (rtlist );
1210
+ pfree (rte );
1211
+
1212
+ heap_endscan (scan );
1213
+ heap_close (rel , NoLock );
1214
+
1215
+ if (!successful )
1216
+ {
1217
+ elog (ERROR , "AlterTableAddConstraint: rejected due to CHECK constraint %s" , name );
1218
+ }
1219
+ /*
1220
+ * Call AddRelationRawConstraints to do the real adding -- It duplicates some
1221
+ * of the above, but does not check the validity of the constraint against
1222
+ * tuples already in the table.
1223
+ */
1224
+ AddRelationRawConstraints (rel , NIL , constlist );
1225
+ pfree (constlist );
1226
+
1227
+ break ;
1228
+ }
1229
+ default :
1230
+ elog (ERROR , "ALTER TABLE / ADD CONSTRAINT is not implemented for that constraint type." );
1231
+ }
1232
+ }
1233
+ break ;
1077
1234
case T_FkConstraint :
1078
1235
{
1079
1236
FkConstraint * fkconstraint = (FkConstraint * ) newConstraint ;
@@ -1084,6 +1241,26 @@ AlterTableAddConstraint(const char *relationName,
1084
1241
List * list ;
1085
1242
int count ;
1086
1243
1244
+ if (get_temp_rel_by_username (fkconstraint -> pktable_name )!= NULL &&
1245
+ get_temp_rel_by_username (relationName )== NULL ) {
1246
+ elog (ERROR , "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint." );
1247
+ }
1248
+
1249
+ /* check to see if the referenced table is a view. */
1250
+ sprintf (rulequery , "select * from pg_views where viewname='%s'" , fkconstraint -> pktable_name );
1251
+ if (SPI_connect ()!= SPI_OK_CONNECT )
1252
+ elog (ERROR , "ALTER TABLE: Unable to determine if %s is a view." , relationName );
1253
+ qplan = SPI_prepare (rulequery , 0 , NULL );
1254
+ if (!qplan )
1255
+ elog (ERROR , "ALTER TABLE: Unable to determine if %s is a view." , relationName );
1256
+ qplan = SPI_saveplan (qplan );
1257
+ if (SPI_execp (qplan , NULL , nulls , 1 )!= SPI_OK_SELECT )
1258
+ elog (ERROR , "ALTER TABLE: Unable to determine if %s is a view." , relationName );
1259
+ if (SPI_processed != 0 )
1260
+ elog (ERROR , "ALTER TABLE: Cannot add constraints to views." );
1261
+ if (SPI_finish () != SPI_OK_FINISH )
1262
+ elog (NOTICE , "SPI_finish() failed in RI_FKey_check()" );
1263
+
1087
1264
/*
1088
1265
* Grab an exclusive lock on the pk table, so that someone
1089
1266
* doesn't delete rows out from under us.
@@ -1101,7 +1278,10 @@ AlterTableAddConstraint(const char *relationName,
1101
1278
*/
1102
1279
rel = heap_openr (relationName , AccessExclusiveLock );
1103
1280
trig .tgoid = 0 ;
1104
- trig .tgname = "<unknown>" ;
1281
+ if (fkconstraint -> constr_name )
1282
+ trig .tgname = fkconstraint -> constr_name ;
1283
+ else
1284
+ trig .tgname = "<unknown>" ;
1105
1285
trig .tgfoid = 0 ;
1106
1286
trig .tgtype = 0 ;
1107
1287
trig .tgenabled = TRUE;
@@ -1113,7 +1293,10 @@ AlterTableAddConstraint(const char *relationName,
1113
1293
sizeof (char * ) * (4 + length (fkconstraint -> fk_attrs )
1114
1294
+ length (fkconstraint -> pk_attrs )));
1115
1295
1116
- trig .tgargs [0 ] = "<unnamed>" ;
1296
+ if (fkconstraint -> constr_name )
1297
+ trig .tgargs [0 ] = fkconstraint -> constr_name ;
1298
+ else
1299
+ trig .tgargs [0 ] = "<unknown>" ;
1117
1300
trig .tgargs [1 ] = (char * ) relationName ;
1118
1301
trig .tgargs [2 ] = fkconstraint -> pktable_name ;
1119
1302
trig .tgargs [3 ] = fkconstraint -> match_type ;
@@ -1446,3 +1629,4 @@ LockTableCommand(LockStmt *lockstmt)
1446
1629
1447
1630
heap_close (rel , NoLock ); /* close rel, keep lock */
1448
1631
}
1632
+
0 commit comments