35a36,47 > > #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" > #include "rewrite/rewriteSupport.h" > #include "commands/view.h" > #include "utils/temprel.h" > #include "executor/spi_priv.h" > 1069a1082,1085 > char rulequery[41+NAMEDATALEN]; > void *qplan; > char nulls[1]=""; > 1072a1089,1108 > #ifndef NO_SECURITY > if (!pg_ownercheck(UserName, relationName, RELNAME)) > elog(ERROR, "ALTER TABLE: permission denied"); > #endif > > /* check to see if the table to be constrained is a view. */ > sprintf(rulequery, "select * from pg_views where viewname='%s'", relationName); > if (SPI_connect()!=SPI_OK_CONNECT) > elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view - SPI_connect failure..", relationName); > qplan=SPI_prepare(rulequery, 0, NULL); > if (!qplan) > elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view - SPI_prepare failure.", relationName); > qplan=SPI_saveplan(qplan); > if (SPI_execp(qplan, NULL, nulls, 1)!=SPI_OK_SELECT) > elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view - SPI_execp failure.", relationName); > if (SPI_processed != 0) > elog(ERROR, "ALTER TABLE: Cannot add constraints to views."); > if (SPI_finish() != SPI_OK_FINISH) > elog(NOTICE, "SPI_finish() failed in ALTER TABLE"); > 1076c1112,1233 < elog(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented"); --- > { > Constraint *constr=(Constraint *)newConstraint; > switch (constr->contype) { > case CONSTR_CHECK: > { > ParseState *pstate; > bool successful=TRUE; > HeapScanDesc scan; > ExprContext *econtext; > 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; > > econtext = MakeExprContext(slot, CurrentMemoryContext); > econtext->ecxt_range_table = rtlist; /* range table */ > if (!ExecQual(qual, econtext, true)) { > successful=false; > break; > } > FreeExprContext(econtext); > } > > pfree(slot); > pfree(rtlist); > pfree(rte); > > heap_endscan(scan); > 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; 1086a1244,1263 > if (get_temp_rel_by_username(fkconstraint->pktable_name)!=NULL && > get_temp_rel_by_username(relationName)==NULL) { > elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint."); > } > > /* check to see if the referenced table is a view. */ > sprintf(rulequery, "select * from pg_views where viewname='%s'", fkconstraint->pktable_name); > if (SPI_connect()!=SPI_OK_CONNECT) > elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view.", relationName); > qplan=SPI_prepare(rulequery, 0, NULL); > if (!qplan) > elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view.", relationName); > qplan=SPI_saveplan(qplan); > if (SPI_execp(qplan, NULL, nulls, 1)!=SPI_OK_SELECT) > elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view.", relationName); > if (SPI_processed != 0) > elog(ERROR, "ALTER TABLE: Cannot add constraints to views."); > if (SPI_finish() != SPI_OK_FINISH) > elog(NOTICE, "SPI_finish() failed in RI_FKey_check()"); > 1104c1281,1284 < trig.tgname = ""; --- > if (fkconstraint->constr_name) > trig.tgname = fkconstraint->constr_name; > else > trig.tgname = ""; 1116c1296,1299 < trig.tgargs[0] = ""; --- > if (fkconstraint->constr_name) > trig.tgargs[0] = fkconstraint->constr_name; > else > trig.tgargs[0] = ""; 1439a1623 >