/* If replacing, get rid of old dependencies and make new ones */ if (is_update)
deleteDependencyRecordsFor(RewriteRelationId, rewriteObjectId, false);
if (!allowSystemTableMods && IsSystemRelation(event_relation))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied: \"%s\" is a system catalog",
RelationGetRelationName(event_relation))));
/* *Checkuserhaspermissiontoapplyrulestothisrelation.
*/ if (!object_ownercheck(RelationRelationId, event_relid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(event_relation->rd_rel->relkind),
RelationGetRelationName(event_relation));
/* *NoruleactionsthatmodifyOLDorNEW
*/
foreach(l, action)
{
query = lfirst_node(Query, l); if (query->resultRelation == 0) continue; /* Don't be fooled by INSERT/SELECT */ if (query != getInsertSelectQuery(query, NULL)) continue; if (query->resultRelation == PRS2_OLD_VARNO)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("rule actions on OLD are not implemented"),
errhint("Use views or triggers instead."))); if (query->resultRelation == PRS2_NEW_VARNO)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("rule actions on NEW are not implemented"),
errhint("Use triggers instead.")));
}
if (event_type == CMD_SELECT)
{ /* *RulesONSELECTarerestrictedtoviewdefinitions * *Sothishadbetterbeaview,...
*/ if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
event_relation->rd_rel->relkind != RELKIND_MATVIEW)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("relation \"%s\" cannot have ON SELECT rules",
RelationGetRelationName(event_relation)),
errdetail_relkind_not_supported(event_relation->rd_rel->relkind)));
/* *...therecannotbeINSTEADNOTHING,...
*/ if (action == NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("INSTEAD NOTHING rules on SELECT are not implemented"),
errhint("Use views instead.")));
/* *...therecannotbemultipleactions,...
*/ if (list_length(action) > 1)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("multiple actions for rules on SELECT are not implemented")));
/* *...theoneactionmustbeaSELECT,...
*/
query = linitial_node(Query, action); if (!is_instead ||
query->commandType != CMD_SELECT)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("rules on SELECT must have action INSTEAD SELECT")));
/* *...itcannotcontaindata-modifyingWITH...
*/ if (query->hasModifyingCTE)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("rules on SELECT must not contain data-modifying statements in WITH")));
/* *...therecanbenorulequal,...
*/ if (event_qual != NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("event qualifications are not implemented for rules on SELECT")));
if (!query->returningList) continue; if (haveReturning)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot have multiple RETURNING lists in a rule")));
haveReturning = true; if (event_qual != NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("RETURNING lists are not supported in conditional rules"))); if (!is_instead)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("RETURNING lists are not supported in non-INSTEAD rules")));
checkRuleResultList(query->returningList,
RelationGetDescr(event_relation), false, false);
}
/* *Andfinally,ifit'snotanONSELECTrulethenitmust*not*be *named_RETURN.Thispreventsaccidentallyormaliciouslyreplacing *aview'sONSELECTrulewithsomeotherkindofrule.
*/ if (strcmp(rulename, ViewSelectRuleName) == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("non-view rule for \"%s\" must not be named \"%s\"",
RelationGetRelationName(event_relation),
ViewSelectRuleName)));
}
/* *Thisruleisallowed-preparetoinstallit.
*/
/* discard rule if it's null action and not INSTEAD; it's a no-op */ if (action != NIL || is_instead)
{
ruleId = InsertRule(rulename,
event_type,
event_relid,
is_instead,
event_qual,
action,
replace);
/* Only a SELECT may require a column name match. */
Assert(isSelect || !requireColumnNameMatch);
i = 0;
foreach(tllist, targetList)
{
TargetEntry *tle = (TargetEntry *) lfirst(tllist);
Oid tletypid;
int32 tletypmod;
Form_pg_attribute attr; char *attname;
/* resjunk entries may be ignored */ if (tle->resjunk) continue;
i++; if (i > resultDesc->natts)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
isSelect ?
errmsg("SELECT rule's target list has too many entries") :
errmsg("RETURNING list has too many entries")));
attr = TupleDescAttr(resultDesc, i - 1);
attname = NameStr(attr->attname);
/* *Disallowdroppedcolumnsintherelation.Thisisnotreally *expectedtohappenwhencreatinganONSELECTrule.It'dbe *possibleifsomeonetriedtoconvertarelationwithdropped *columnstoaview,buttheonlycasewecareaboutsupporting *table-to-viewconversionforispg_dump,andpg_dumpwon'tdothat. * *Unfortunately,thesituationisalsopossiblewhenaddingarule *withRETURNINGtoaregulartable,andrejectingthatcaseis *altogethermoreannoying.Inprinciplewecouldsupportitby *modifyingthetargetlisttoincludedummyNULLcolumns *correspondingtothedroppedcolumnsinthetupdesc.However, *placeslikeruleutils.cwouldhavetobefixedtonotprocesssuch *entries,andthatwouldtakeanuncertainandpossiblyratherlarge *amountofwork.(Notewecouldnotdodgethatbymarkingthedummy *columnsresjunk,sinceit'spreciselythenon-resjunktlistcolumns *thatareexpectedtocorrespondtotablecolumns.)
*/ if (attr->attisdropped)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
isSelect ?
errmsg("cannot convert relation containing dropped columns to view") :
errmsg("cannot create a RETURNING list for a relation containing dropped columns")));
/* Check name match if required; no need for two error texts here */ if (requireColumnNameMatch && strcmp(tle->resname, attname) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("SELECT rule's target entry %d has different column name from column \"%s\"",
i, attname),
errdetail("SELECT target entry is named \"%s\".",
tle->resname)));
/* Check type match. */
tletypid = exprType((Node *) tle->expr); if (attr->atttypid != tletypid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
isSelect ?
errmsg("SELECT rule's target entry %d has different type from column \"%s\"",
i, attname) :
errmsg("RETURNING list's entry %d has different type from column \"%s\"",
i, attname),
isSelect ?
errdetail("SELECT target entry has type %s, but column has type %s.",
format_type_be(tletypid),
format_type_be(attr->atttypid)) :
errdetail("RETURNING list entry has type %s, but column has type %s.",
format_type_be(tletypid),
format_type_be(attr->atttypid))));
/* *Allowtypmodstobedifferentonlyifoneofthemis-1,ie, *"unspecified".Thisisnecessaryforcaseslike"numeric",where *thetablewillhaveafilled-indefaultlengthbuttheselect *rule'sexpressionwillprobablyhavetypmod=-1.
*/
tletypmod = exprTypmod((Node *) tle->expr); if (attr->atttypmod != tletypmod &&
attr->atttypmod != -1 && tletypmod != -1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
isSelect ?
errmsg("SELECT rule's target entry %d has different size from column \"%s\"",
i, attname) :
errmsg("RETURNING list's entry %d has different size from column \"%s\"",
i, attname),
isSelect ?
errdetail("SELECT target entry has type %s, but column has type %s.",
format_type_with_typemod(tletypid, tletypmod),
format_type_with_typemod(attr->atttypid,
attr->atttypmod)) :
errdetail("RETURNING list entry has type %s, but column has type %s.",
format_type_with_typemod(tletypid, tletypmod),
format_type_with_typemod(attr->atttypid,
attr->atttypmod))));
}
if (i != resultDesc->natts)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
isSelect ?
errmsg("SELECT rule's target list has too few entries") :
errmsg("RETURNING list has too few entries")));
}
/* If there are sublinks, search for them and process their RTEs */ if (qry->hasSubLinks)
query_tree_walker(qry, setRuleCheckAsUser_walker, &userid,
QTW_IGNORE_RC_SUBQUERIES);
}
/* *Ifwechangedanything,broadcastaSIinvalmessagetoforceeach *backend(includingourown!)torebuildrelation'srelcacheentry. *Otherwisetheywillfailtoapplythechangepromptly.
*/ if (changed)
CacheInvalidateRelcache(rel);
}
/* *Performpermissionsandintegritychecksbeforeacquiringarelationlock.
*/ staticvoid
RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
{
HeapTuple tuple;
Form_pg_class form;
tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); if (!HeapTupleIsValid(tuple)) return; /* concurrently dropped */
form = (Form_pg_class) GETSTRUCT(tuple);
/* only tables and views can have rules */ if (form->relkind != RELKIND_RELATION &&
form->relkind != RELKIND_VIEW &&
form->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("relation \"%s\" cannot have rules", rv->relname),
errdetail_relkind_not_supported(form->relkind)));
if (!allowSystemTableMods && IsSystemClass(relid, form))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied: \"%s\" is a system catalog",
rv->relname)));
/* you must own the table to rename one of its rules */ if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname);
/* Have lock already, so just need to build relcache entry. */
targetrel = relation_open(relid, NoLock);
/* Prepare to modify pg_rewrite */
pg_rewrite_desc = table_open(RewriteRelationId, RowExclusiveLock);
/* Fetch the rule's entry (it had better exist) */
ruletup = SearchSysCacheCopy2(RULERELNAME,
ObjectIdGetDatum(relid),
PointerGetDatum(oldName)); if (!HeapTupleIsValid(ruletup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("rule \"%s\" for relation \"%s\" does not exist",
oldName, RelationGetRelationName(targetrel))));
ruleform = (Form_pg_rewrite) GETSTRUCT(ruletup);
ruleOid = ruleform->oid;
/* rule with the new name should not already exist */ if (IsDefinedRewriteRule(relid, newName))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("rule \"%s\" for relation \"%s\" already exists",
newName, RelationGetRelationName(targetrel))));
/* *WedisallowrenamingONSELECTrules,becausetheyshouldalwaysbe *named"_RETURN".
*/ if (ruleform->ev_type == CMD_SELECT + '0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("renaming an ON SELECT rule is not allowed")));
/* OK, do the update */
namestrcpy(&(ruleform->rulename), newName);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.