Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 739a056

Browse files
committed
This should be a slighly more complete patch for commands/command.c
AlterTableAddConstraint. The major changes from the last patch are that it should hopefully check for references to temp tables (not in the shadow case, but at defination time) from permanent tables in foreign keys and refuse them and that it doesn't allow the table(s) being constrained to be views (because those cases don't currently work). Stephan SzaboThis should be a slighly more complete patch for commands/command.c AlterTableAddConstraint. The major changes from the last patch are that it should hopefully check for references to temp tables (not in the shadow case, but at defination time) from permanent tables in foreign keys and refuse them and that it doesn't allow the table(s) being constrained to be views (because those cases don't currently work). Stephan Szabo
1 parent f2e3f62 commit 739a056

File tree

1 file changed

+188
-4
lines changed

1 file changed

+188
-4
lines changed

src/backend/commands/command.c

Lines changed: 188 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* 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 $
1212
*
1313
* NOTES
1414
* The PerformAddAttribute() code, like most of the relation
@@ -33,6 +33,18 @@
3333
#include "utils/acl.h"
3434
#include "utils/fmgroids.h"
3535
#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+
3648
#ifdef _DROP_COLUMN_HACK__
3749
#include "catalog/pg_index.h"
3850
#include "parser/parse.h"
@@ -1067,13 +1079,158 @@ void
10671079
AlterTableAddConstraint(const char *relationName,
10681080
bool inh, Node *newConstraint)
10691081
{
1082+
char rulequery[41+NAMEDATALEN];
1083+
void *qplan;
1084+
char nulls[1]="";
1085+
10701086
if (newConstraint == NULL)
10711087
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT passed invalid constraint.");
10721088

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+
10731109
switch (nodeTag(newConstraint))
10741110
{
10751111
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;
10771234
case T_FkConstraint:
10781235
{
10791236
FkConstraint *fkconstraint = (FkConstraint *) newConstraint;
@@ -1084,6 +1241,26 @@ AlterTableAddConstraint(const char *relationName,
10841241
List *list;
10851242
int count;
10861243

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+
10871264
/*
10881265
* Grab an exclusive lock on the pk table, so that someone
10891266
* doesn't delete rows out from under us.
@@ -1101,7 +1278,10 @@ AlterTableAddConstraint(const char *relationName,
11011278
*/
11021279
rel = heap_openr(relationName, AccessExclusiveLock);
11031280
trig.tgoid = 0;
1104-
trig.tgname = "<unknown>";
1281+
if (fkconstraint->constr_name)
1282+
trig.tgname = fkconstraint->constr_name;
1283+
else
1284+
trig.tgname = "<unknown>";
11051285
trig.tgfoid = 0;
11061286
trig.tgtype = 0;
11071287
trig.tgenabled = TRUE;
@@ -1113,7 +1293,10 @@ AlterTableAddConstraint(const char *relationName,
11131293
sizeof(char *) * (4 + length(fkconstraint->fk_attrs)
11141294
+ length(fkconstraint->pk_attrs)));
11151295

1116-
trig.tgargs[0] = "<unnamed>";
1296+
if (fkconstraint->constr_name)
1297+
trig.tgargs[0] = fkconstraint->constr_name;
1298+
else
1299+
trig.tgargs[0] = "<unknown>";
11171300
trig.tgargs[1] = (char *) relationName;
11181301
trig.tgargs[2] = fkconstraint->pktable_name;
11191302
trig.tgargs[3] = fkconstraint->match_type;
@@ -1446,3 +1629,4 @@ LockTableCommand(LockStmt *lockstmt)
14461629

14471630
heap_close(rel, NoLock); /* close rel, keep lock */
14481631
}
1632+

0 commit comments

Comments
 (0)