*** pgsql.orig/src/backend/commands/command.c Wed Jul 5 16:11:09 2000 --- pgsql/src/backend/commands/command.c Sun Jul 9 14:28:25 2000 *************** *** 33,38 **** --- 33,46 ---- #include "utils/acl.h" #include "utils/fmgroids.h" #include "commands/trigger.h" + + #include "parser/parse_expr.h" + #include "parser/parse_clause.h" + #include "parser/parse_relation.h" + #include "nodes/makefuncs.h" + #include "optimizer/planmain.h" + #include "optimizer/clauses.h" + #ifdef _DROP_COLUMN_HACK__ #include "catalog/pg_index.h" #include "parser/parse.h" *************** *** 1070,1079 **** if (newConstraint == NULL) elog(ERROR, "ALTER TABLE / ADD CONSTRAINT passed invalid constraint."); switch (nodeTag(newConstraint)) { case T_Constraint: ! elog(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented"); case T_FkConstraint: { FkConstraint *fkconstraint = (FkConstraint *) newConstraint; --- 1078,1223 ---- if (newConstraint == NULL) elog(ERROR, "ALTER TABLE / ADD CONSTRAINT passed invalid constraint."); + #ifndef NO_SECURITY + if (!pg_ownercheck(UserName, relationName, RELNAME)) + elog(ERROR, "ALTER TABLE: permission denied"); + #endif + switch (nodeTag(newConstraint)) { case T_Constraint: ! { ! Constraint *constr=(Constraint *)newConstraint; ! switch (constr->contype) { ! case CONSTR_CHECK: ! { ! ParseState *pstate; ! bool successful=TRUE; ! HeapScanDesc scan; ! ExprContext *econtext = makeNode(ExprContext); ! TupleTableSlot *slot = makeNode(TupleTableSlot); ! HeapTuple tuple; ! RangeTblEntry *rte = makeNode(RangeTblEntry); ! List *rtlist; ! List *qual; ! List *constlist; ! Relation rel; ! Node *expr; ! char *name; ! if (constr->name) ! name=constr->name; ! else ! name=""; ! ! rel = heap_openr(relationName, AccessExclusiveLock); ! ! /* ! * Scan all of the rows, looking for a false match ! */ ! scan = heap_beginscan(rel, false, SnapshotNow, 0, NULL); ! AssertState(scan != NULL); ! ! /* ! *We need to make a parse state and range table to allow us ! * to transformExpr and fix_opids to get a version of the ! * expression we can pass to ExecQual ! */ ! pstate = make_parsestate(NULL); ! makeRangeTable(pstate, NULL); ! addRangeTableEntry(pstate, relationName, ! makeAttr(relationName, NULL), false, true,true); ! constlist=lcons(constr, NIL); ! ! /* Convert the A_EXPR in raw_expr into an EXPR */ ! expr = transformExpr(pstate, constr->raw_expr, EXPR_COLUMN_FIRST); ! ! /* ! * Make sure it yields a boolean result. ! */ ! if (exprType(expr) != BOOLOID) ! elog(ERROR, "CHECK '%s' does not yield boolean result", ! name); ! ! /* ! * Make sure no outside relations are referred to. ! */ ! if (length(pstate->p_rtable) != 1) ! elog(ERROR, "Only relation '%s' can be referenced in CHECK", ! relationName); ! ! /* ! * Might as well try to reduce any constant expressions. ! */ ! expr = eval_const_expressions(expr); ! ! /* And fix the opids */ ! fix_opids(expr); ! ! qual = lcons(expr, NIL); ! rte->relname = relationName; ! rte->ref = makeNode(Attr); ! rte->ref->relname = rte->relname; ! rte->relid = RelationGetRelid(rel); ! rtlist = lcons(rte, NIL); ! ! /* ! * Scan through the rows now, making the necessary things for ! * ExecQual, and then call it to evaluate the expression. ! */ ! while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) ! { ! slot->val = tuple; ! slot->ttc_shouldFree = false; ! slot->ttc_descIsNew = true; ! slot->ttc_tupleDescriptor = rel->rd_att; ! slot->ttc_buffer = InvalidBuffer; ! slot->ttc_whichplan = -1; ! /* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */ ! econtext->ecxt_scantuple = slot; /* scan tuple slot */ ! econtext->ecxt_innertuple = NULL; /* inner tuple slot */ ! econtext->ecxt_outertuple = NULL; /* outer tuple slot */ ! econtext->ecxt_relation = rel; /* relation */ ! econtext->ecxt_relid = 0; /* relid */ ! econtext->ecxt_param_list_info = NULL; /* param list info */ ! econtext->ecxt_param_exec_vals = NULL; /* exec param values */ ! econtext->ecxt_range_table = rtlist; /* range table */ ! if (!ExecQual(qual, econtext, true)) { ! successful=false; ! break; ! } ! } ! ! pfree(slot); ! pfree(rtlist); ! pfree(rte); ! pfree(econtext); ! ! heap_endscan(scan); ! /* ! * We want to close our copy (to make sure we don't get an annoying ! * changed while in use message), but we want to keep our lock. ! */ ! heap_close(rel, NoLock); ! ! if (!successful) ! { ! elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s", name); ! } ! /* ! * Call AddRelationRawConstraints to do the real adding -- It duplicates some ! * of the above, but does not check the validity of the constraint against ! * tuples already in the table. ! */ ! AddRelationRawConstraints(rel, NIL, constlist); ! pfree(constlist); ! ! break; ! } ! default: ! elog(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented for that constraint type."); ! } ! } ! break; case T_FkConstraint: { FkConstraint *fkconstraint = (FkConstraint *) newConstraint; *************** *** 1101,1107 **** */ rel = heap_openr(relationName, AccessExclusiveLock); trig.tgoid = 0; ! trig.tgname = ""; trig.tgfoid = 0; trig.tgtype = 0; trig.tgenabled = TRUE; --- 1245,1254 ---- */ rel = heap_openr(relationName, AccessExclusiveLock); trig.tgoid = 0; ! if (fkconstraint->constr_name) ! trig.tgargs[0] = fkconstraint->constr_name; ! else ! trig.tgargs[0] = ""; trig.tgfoid = 0; trig.tgtype = 0; trig.tgenabled = TRUE; *************** *** 1113,1119 **** sizeof(char *) * (4 + length(fkconstraint->fk_attrs) + length(fkconstraint->pk_attrs))); ! trig.tgargs[0] = ""; trig.tgargs[1] = (char *) relationName; trig.tgargs[2] = fkconstraint->pktable_name; trig.tgargs[3] = fkconstraint->match_type; --- 1260,1269 ---- sizeof(char *) * (4 + length(fkconstraint->fk_attrs) + length(fkconstraint->pk_attrs))); ! if (fkconstraint->constr_name) ! trig.tgargs[0] = fkconstraint->constr_name; ! else ! trig.tgargs[0] = ""; trig.tgargs[1] = (char *) relationName; trig.tgargs[2] = fkconstraint->pktable_name; trig.tgargs[3] = fkconstraint->match_type;