rewritedefine.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 588 行 · 第 1/2 页
C
588 行
if (resdom->resjunk) continue; i++; if (i > event_relation->rd_att->natts) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("SELECT rule's target list has too many entries"))); attr = event_relation->rd_att->attrs[i - 1]; attname = NameStr(attr->attname); /* * Disallow dropped columns in the relation. This won't * happen in the cases we actually care about (namely creating * a view via CREATE TABLE then CREATE RULE). Trying to cope * with it is much more trouble than it's worth, because we'd * have to modify the rule to insert dummy NULLs at the right * positions. */ if (attr->attisdropped) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert relation containing dropped columns to view"))); if (strcmp(resdom->resname, attname) != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("SELECT rule's target entry %d has different column name from \"%s\"", i, attname))); if (attr->atttypid != resdom->restype) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("SELECT rule's target entry %d has different type from column \"%s\"", i, attname))); /* * Allow typmods to be different only if one of them is -1, * ie, "unspecified". This is necessary for cases like * "numeric", where the table will have a filled-in default * length but the select rule's expression will probably have * typmod = -1. */ if (attr->atttypmod != resdom->restypmod && attr->atttypmod != -1 && resdom->restypmod != -1) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("SELECT rule's target entry %d has different size from column \"%s\"", i, attname))); } if (i != event_relation->rd_att->natts) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("SELECT rule's target list has too few entries"))); /* * ... there must not be another ON SELECT rule already ... */ if (!replace && event_relation->rd_rules != NULL) { for (i = 0; i < event_relation->rd_rules->numLocks; i++) { RewriteRule *rule; rule = event_relation->rd_rules->rules[i]; if (rule->event == CMD_SELECT) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("\"%s\" is already a view", RelationGetRelationName(event_relation)))); } } /* * ... and finally the rule must be named _RETURN. */ if (strcmp(stmt->rulename, ViewSelectRuleName) != 0) { /* * In versions before 7.3, the expected name was _RETviewname. * For backwards compatibility with old pg_dump output, accept * that and silently change it to _RETURN. Since this is just * a quick backwards-compatibility hack, limit the number of * characters checked to a few less than NAMEDATALEN; this * saves having to worry about where a multibyte character * might have gotten truncated. */ if (strncmp(stmt->rulename, "_RET", 4) != 0 || strncmp(stmt->rulename + 4, event_obj->relname, NAMEDATALEN - 4 - 4) != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("view rule for \"%s\" must be named \"%s\"", event_obj->relname, ViewSelectRuleName))); stmt->rulename = pstrdup(ViewSelectRuleName); } /* * Are we converting a relation to a view? * * If so, check that the relation is empty because the storage for * the relation is going to be deleted. Also insist that the rel * not have any triggers, indexes, or child tables. */ if (event_relation->rd_rel->relkind != RELKIND_VIEW) { HeapScanDesc scanDesc; scanDesc = heap_beginscan(event_relation, SnapshotNow, 0, NULL); if (heap_getnext(scanDesc, ForwardScanDirection) != NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("could not convert table \"%s\" to a view because it is not empty", event_obj->relname))); heap_endscan(scanDesc); if (event_relation->rd_rel->reltriggers != 0) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("could not convert table \"%s\" to a view because it has triggers", event_obj->relname), errhint("In particular, the table may not be involved in any foreign key relationships."))); if (event_relation->rd_rel->relhasindex) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("could not convert table \"%s\" to a view because it has indexes", event_obj->relname))); if (event_relation->rd_rel->relhassubclass) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("could not convert table \"%s\" to a view because it has child tables", event_obj->relname))); RelisBecomingView = true; } } /* * This rule is allowed - prepare to install it. */ event_attno = -1; event_attype = InvalidOid; /* * We want the rule's table references to be checked as though by the * rule owner, not the user referencing the rule. Therefore, scan * through the rule's rtables and set the checkAsUser field on all * rtable entries. */ foreach(l, action) { query = (Query *) lfirst(l); setRuleCheckAsUser(query, GetUserId()); } /* discard rule if it's null action and not INSTEAD; it's a no-op */ if (action != NIL || is_instead) { ruleId = InsertRule(stmt->rulename, event_type, ev_relid, event_attno, is_instead, event_qual, action, replace); /* * Set pg_class 'relhasrules' field TRUE for event relation. If * appropriate, also modify the 'relkind' field to show that the * relation is now a view. * * Important side effect: an SI notice is broadcast to force all * backends (including me!) to update relcache entries with the * new rule. */ SetRelationRuleStatus(ev_relid, true, RelisBecomingView); } /* * IF the relation is becoming a view, delete the storage files * associated with it. NB: we had better have AccessExclusiveLock to * do this ... * * XXX what about getting rid of its TOAST table? For now, we don't. */ if (RelisBecomingView) smgrunlink(DEFAULT_SMGR, event_relation); /* Close rel, but keep lock till commit... */ heap_close(event_relation, NoLock);}/* * setRuleCheckAsUser * Recursively scan a query and set the checkAsUser field to the * given userid in all rtable entries. * * Note: for a view (ON SELECT rule), the checkAsUser field of the *OLD* * RTE entry will be overridden when the view rule is expanded, and the * checkAsUser field of the *NEW* entry is irrelevant because that entry's * checkFor bits will never be set. However, for other types of rules it's * important to set these fields to match the rule owner. So we just set * them always. */static voidsetRuleCheckAsUser(Query *qry, AclId userid){ List *l; /* Set all the RTEs in this query node */ foreach(l, qry->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); if (rte->rtekind == RTE_SUBQUERY) { /* Recurse into subquery in FROM */ setRuleCheckAsUser(rte->subquery, userid); } else rte->checkAsUser = userid; } /* If there are sublinks, search for them and process their RTEs */ /* ignore subqueries in rtable because we already processed them */ if (qry->hasSubLinks) query_tree_walker(qry, setRuleCheckAsUser_walker, (void *) &userid, QTW_IGNORE_RT_SUBQUERIES);}/* * Expression-tree walker to find sublink queries */static boolsetRuleCheckAsUser_walker(Node *node, Oid *context){ if (node == NULL) return false; if (IsA(node, Query)) { Query *qry = (Query *) node; setRuleCheckAsUser(qry, *context); return false; } return expression_tree_walker(node, setRuleCheckAsUser_walker, (void *) context);}/* * Rename an existing rewrite rule. * * This is unused code at the moment. */voidRenameRewriteRule(Oid owningRel, const char *oldName, const char *newName){ Relation pg_rewrite_desc; HeapTuple ruletup; pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock); ruletup = SearchSysCacheCopy(RULERELNAME, ObjectIdGetDatum(owningRel), PointerGetDatum(oldName), 0, 0); if (!HeapTupleIsValid(ruletup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("rule \"%s\" for relation \"%s\" does not exist", oldName, get_rel_name(owningRel)))); /* should not already exist */ if (IsDefinedRewriteRule(owningRel, newName)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("rule \"%s\" for relation \"%s\" already exists", newName, get_rel_name(owningRel)))); namestrcpy(&(((Form_pg_rewrite) GETSTRUCT(ruletup))->rulename), newName); simple_heap_update(pg_rewrite_desc, &ruletup->t_self, ruletup); /* keep system catalog indexes current */ CatalogUpdateIndexes(pg_rewrite_desc, ruletup); heap_freetuple(ruletup); heap_close(pg_rewrite_desc, RowExclusiveLock);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?