diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 1679776f019faf1a4ced3f9d809f5373c79481cb..bce0e076837f57857c8c19d82b08f5cb51b1f766 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -1284,6 +1284,7 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender, rte.type = T_RangeTblEntry; rte.rtekind = RTE_RELATION; rte.relid = relId; + rte.relkind = RELKIND_RELATION; /* no need for exactness here */ context.rtables = list_make1(list_make1(&rte)); diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 44f568f396414f69485ab0538b0086741e5068c9..3c504e96be2d3f426269bdbd61ef4632c6ceb75f 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -763,6 +763,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString) rte = makeNode(RangeTblEntry); rte->rtekind = RTE_RELATION; rte->relid = RelationGetRelid(rel); + rte->relkind = rel->rd_rel->relkind; rte->requiredPerms = required_access; tupDesc = RelationGetDescr(rel); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 1ba746bb4d893c0145e8376553c468d5b086fe1c..04763d44ebb6e38342d2c4d483e780e6b3360a4f 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -1927,6 +1927,7 @@ _copyRangeTblEntry(RangeTblEntry *from) COPY_SCALAR_FIELD(rtekind); COPY_SCALAR_FIELD(relid); + COPY_SCALAR_FIELD(relkind); COPY_NODE_FIELD(subquery); COPY_SCALAR_FIELD(jointype); COPY_NODE_FIELD(joinaliasvars); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index dd332f19f00d91baec544229a6b98772028a9f5b..c896f49ff6f3a7d809063f13a2defc63f5c90e79 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -2286,6 +2286,7 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b) { COMPARE_SCALAR_FIELD(rtekind); COMPARE_SCALAR_FIELD(relid); + COMPARE_SCALAR_FIELD(relkind); COMPARE_NODE_FIELD(subquery); COMPARE_SCALAR_FIELD(jointype); COMPARE_NODE_FIELD(joinaliasvars); diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 8a23047d382e9474aa3eea0bffa89ac2259a3a81..d4b9242917197263578fd949c6c29b06a1b99a03 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -1671,7 +1671,6 @@ range_table_walker(List *rtable, switch (rte->rtekind) { case RTE_RELATION: - case RTE_SPECIAL: case RTE_CTE: /* nothing to do */ break; @@ -2374,7 +2373,6 @@ range_table_mutator(List *rtable, switch (rte->rtekind) { case RTE_RELATION: - case RTE_SPECIAL: case RTE_CTE: /* we don't bother to copy eref, aliases, etc; OK? */ break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 10f630e27f5b14f695540984feee31c096655ce2..706b2425cf2b1516b47128824083af1e0b127dad 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -2275,8 +2275,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node) switch (node->rtekind) { case RTE_RELATION: - case RTE_SPECIAL: WRITE_OID_FIELD(relid); + WRITE_CHAR_FIELD(relkind); break; case RTE_SUBQUERY: WRITE_NODE_FIELD(subquery); diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c index 14487f25a1044cfa240f3cdc1ad4bfb0d41551f1..cd119dbabb8c78a72af30a0902397680328c26db 100644 --- a/src/backend/nodes/print.c +++ b/src/backend/nodes/print.c @@ -265,8 +265,8 @@ print_rt(List *rtable) switch (rte->rtekind) { case RTE_RELATION: - printf("%d\t%s\t%u", - i, rte->eref->aliasname, rte->relid); + printf("%d\t%s\t%u\t%c", + i, rte->eref->aliasname, rte->relid, rte->relkind); break; case RTE_SUBQUERY: printf("%d\t%s\t[subquery]", @@ -276,10 +276,6 @@ print_rt(List *rtable) printf("%d\t%s\t[join]", i, rte->eref->aliasname); break; - case RTE_SPECIAL: - printf("%d\t%s\t[special]", - i, rte->eref->aliasname); - break; case RTE_FUNCTION: printf("%d\t%s\t[rangefunction]", i, rte->eref->aliasname); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index b007caeee3e1ecb4238632e53c7de6c2b3328c8e..c76884e991f4b2eeca8a38b4ef32ae24017b86f8 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -1171,8 +1171,8 @@ _readRangeTblEntry(void) switch (local_node->rtekind) { case RTE_RELATION: - case RTE_SPECIAL: READ_OID_FIELD(relid); + READ_CHAR_FIELD(relkind); break; case RTE_SUBQUERY: READ_NODE_FIELD(subquery); diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index c835a954ed97b29e87adb933af5078f27fc9971b..dc2a23bb2737313b43e1e6d7b272119863693cbc 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -176,41 +176,44 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, /* It's an "append relation", process accordingly */ set_append_rel_pathlist(root, rel, rti, rte); } - else if (rel->rtekind == RTE_SUBQUERY) - { - /* Subquery --- generate a separate plan for it */ - set_subquery_pathlist(root, rel, rti, rte); - } - else if (rel->rtekind == RTE_FUNCTION) - { - /* RangeFunction --- generate a suitable path for it */ - set_function_pathlist(root, rel, rte); - } - else if (rel->rtekind == RTE_VALUES) - { - /* Values list --- generate a suitable path for it */ - set_values_pathlist(root, rel, rte); - } - else if (rel->rtekind == RTE_CTE) - { - /* CTE reference --- generate a suitable path for it */ - if (rte->self_reference) - set_worktable_pathlist(root, rel, rte); - else - set_cte_pathlist(root, rel, rte); - } else { - Assert(rel->rtekind == RTE_RELATION); - if (get_rel_relkind(rte->relid) == RELKIND_FOREIGN_TABLE) - { - /* Foreign table */ - set_foreign_pathlist(root, rel, rte); - } - else + switch (rel->rtekind) { - /* Plain relation */ - set_plain_rel_pathlist(root, rel, rte); + case RTE_RELATION: + if (rte->relkind == RELKIND_FOREIGN_TABLE) + { + /* Foreign table */ + set_foreign_pathlist(root, rel, rte); + } + else + { + /* Plain relation */ + set_plain_rel_pathlist(root, rel, rte); + } + break; + case RTE_SUBQUERY: + /* Subquery --- generate a separate plan for it */ + set_subquery_pathlist(root, rel, rti, rte); + break; + case RTE_FUNCTION: + /* RangeFunction --- generate a suitable path for it */ + set_function_pathlist(root, rel, rte); + break; + case RTE_VALUES: + /* Values list --- generate a suitable path for it */ + set_values_pathlist(root, rel, rte); + break; + case RTE_CTE: + /* CTE reference --- generate a suitable path for it */ + if (rte->self_reference) + set_worktable_pathlist(root, rel, rte); + else + set_cte_pathlist(root, rel, rte); + break; + default: + elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind); + break; } } diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index b73b872b3128f40b9a4bcfff01fd2e1aac20f62c..ee09673051ff0e03f61622d5fee7c8d151886b87 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -1915,7 +1915,7 @@ preprocess_rowmarks(PlannerInfo *root) newrc->rowmarkId = ++(root->glob->lastRowMarkId); /* real tables support REFERENCE, anything else needs COPY */ if (rte->rtekind == RTE_RELATION && - get_rel_relkind(rte->relid) != RELKIND_FOREIGN_TABLE) + rte->relkind != RELKIND_FOREIGN_TABLE) newrc->markType = ROW_MARK_REFERENCE; else newrc->markType = ROW_MARK_COPY; @@ -3078,6 +3078,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid) rte = makeNode(RangeTblEntry); rte->rtekind = RTE_RELATION; rte->relid = tableOid; + rte->relkind = RELKIND_RELATION; rte->inh = false; rte->inFromCl = true; query->rtable = list_make1(rte); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index c7a7a230767889d332c037d866d42160e8e8f7f9..7f28d9df4f5ea701d21162a00da96e1bf3c5af1c 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -40,7 +40,6 @@ #include "parser/parse_target.h" #include "parser/parsetree.h" #include "rewrite/rewriteManip.h" -#include "utils/lsyscache.h" #include "utils/rel.h" @@ -2178,13 +2177,11 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, { case RTE_RELATION: /* ignore foreign tables */ - if (get_rel_relkind(rte->relid) != RELKIND_FOREIGN_TABLE) - { - applyLockingClause(qry, i, - lc->forUpdate, lc->noWait, - pushedDown); - rte->requiredPerms |= ACL_SELECT_FOR_UPDATE; - } + if (rte->relkind == RELKIND_FOREIGN_TABLE) + break; + applyLockingClause(qry, i, + lc->forUpdate, lc->noWait, pushedDown); + rte->requiredPerms |= ACL_SELECT_FOR_UPDATE; break; case RTE_SUBQUERY: applyLockingClause(qry, i, @@ -2231,11 +2228,11 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, switch (rte->rtekind) { case RTE_RELATION: - if (get_rel_relkind(rte->relid) == RELKIND_FOREIGN_TABLE) + if (rte->relkind == RELKIND_FOREIGN_TABLE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SELECT FOR UPDATE/SHARE cannot be used with foreign table \"%s\"", - get_rel_name(rte->relid)), + rte->eref->aliasname), parser_errposition(pstate, thisrel->location))); applyLockingClause(qry, i, lc->forUpdate, lc->noWait, @@ -2256,12 +2253,6 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a join"), parser_errposition(pstate, thisrel->location))); break; - case RTE_SPECIAL: - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("SELECT FOR UPDATE/SHARE cannot be applied to NEW or OLD"), - parser_errposition(pstate, thisrel->location))); - break; case RTE_FUNCTION: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 497c726f31455fc6f24a0533bc3c411ce545e87b..033ed411fde92d7bd60c9889d6e0872be73e9a7f 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -894,6 +894,7 @@ addRangeTableEntry(ParseState *pstate, lockmode = isLockedRefname(pstate, refname) ? RowShareLock : AccessShareLock; rel = parserOpenTable(pstate, relation, lockmode); rte->relid = RelationGetRelid(rel); + rte->relkind = rel->rd_rel->relkind; /* * Build the list of effective column names using user-supplied aliases @@ -956,6 +957,7 @@ addRangeTableEntryForRelation(ParseState *pstate, rte->rtekind = RTE_RELATION; rte->alias = alias; rte->relid = RelationGetRelid(rel); + rte->relkind = rel->rd_rel->relkind; /* * Build the list of effective column names using user-supplied aliases diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index a0761da875be78c7387bc0053e6b68f2852eab9b..e9ace37e2d803fd47b132ca228f16465dce5851f 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -305,7 +305,6 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle, markTargetListOrigin(pstate, tle, aliasvar, netlevelsup); } break; - case RTE_SPECIAL: case RTE_FUNCTION: case RTE_VALUES: /* not a simple relation, leave it unmarked */ @@ -1357,7 +1356,6 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup) switch (rte->rtekind) { case RTE_RELATION: - case RTE_SPECIAL: case RTE_VALUES: /* diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 3a50642fce8008d6b99b816515022cd10773d232..c0d25b15c60c3e20e887fa976cb3641b7352c6fd 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -144,6 +144,13 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown) lockmode = AccessShareLock; rel = heap_open(rte->relid, lockmode); + + /* + * While we have the relation open, update the RTE's relkind, + * just in case it changed since this rule was made. + */ + rte->relkind = rel->rd_rel->relkind; + heap_close(rel, NoLock); break; @@ -1393,7 +1400,7 @@ markQueryForLocking(Query *qry, Node *jtnode, if (rte->rtekind == RTE_RELATION) { /* ignore foreign tables */ - if (get_rel_relkind(rte->relid) != RELKIND_FOREIGN_TABLE) + if (rte->relkind != RELKIND_FOREIGN_TABLE) { applyLockingClause(qry, rti, forUpdate, noWait, pushedDown); rte->requiredPerms |= ACL_SELECT_FOR_UPDATE; diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 5ef1563d1c95a47b823b5032d11351d81204ad8a..591d2eb16b00e643107f53a75ae6157df4cc6f83 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -2651,11 +2651,13 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) pkrte = makeNode(RangeTblEntry); pkrte->rtekind = RTE_RELATION; pkrte->relid = RelationGetRelid(pk_rel); + pkrte->relkind = pk_rel->rd_rel->relkind; pkrte->requiredPerms = ACL_SELECT; fkrte = makeNode(RangeTblEntry); fkrte->rtekind = RTE_RELATION; fkrte->relid = RelationGetRelid(fk_rel); + fkrte->relkind = fk_rel->rd_rel->relkind; fkrte->requiredPerms = ACL_SELECT; for (i = 0; i < riinfo.nkeys; i++) diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index cd64235438e9f3b89a5e7eb40f08be09c4889a91..d9b359465a2fc96a10ee5b04ce3025da04473002 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -628,6 +628,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) if (!isnull) { Node *qual; + char relkind; deparse_context context; deparse_namespace dpns; RangeTblEntry *oldrte; @@ -637,10 +638,13 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) qual = stringToNode(TextDatumGetCString(value)); + relkind = get_rel_relkind(trigrec->tgrelid); + /* Build minimal OLD and NEW RTEs for the rel */ oldrte = makeNode(RangeTblEntry); oldrte->rtekind = RTE_RELATION; oldrte->relid = trigrec->tgrelid; + oldrte->relkind = relkind; oldrte->eref = makeAlias("old", NIL); oldrte->inh = false; oldrte->inFromCl = true; @@ -648,6 +652,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) newrte = makeNode(RangeTblEntry); newrte->rtekind = RTE_RELATION; newrte->relid = trigrec->tgrelid; + newrte->relkind = relkind; newrte->eref = makeAlias("new", NIL); newrte->inh = false; newrte->inFromCl = true; @@ -2125,6 +2130,7 @@ deparse_context_for(const char *aliasname, Oid relid) rte = makeNode(RangeTblEntry); rte->rtekind = RTE_RELATION; rte->relid = relid; + rte->relkind = RELKIND_RELATION; /* no need for exactness here */ rte->eref = makeAlias(aliasname, NIL); rte->inh = false; rte->inFromCl = true; @@ -4004,7 +4010,6 @@ get_name_for_var_field(Var *var, int fieldno, switch (rte->rtekind) { case RTE_RELATION: - case RTE_SPECIAL: case RTE_VALUES: /* diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 70106414cfe2b4e643a188de021657933cd12066..0a0544bc38aba4a930e33ef84e9e3e7ab23f3a5d 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201102221 +#define CATALOG_VERSION_NO 201102222 #endif diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 42bc8635a249558b4d70222ee70f6fa342a90fb1..e103530a3f24c582fd6643761e2cccdcffad3119 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -49,7 +49,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO Oid reltoastidxid; /* if toast table, OID of chunk_id index */ bool relhasindex; /* T if has (or has had) any indexes */ bool relisshared; /* T if shared across databases */ - char relpersistence; /* see RELPERSISTENCE_xxx constants */ + char relpersistence; /* see RELPERSISTENCE_xxx constants below */ char relkind; /* see RELKIND_xxx constants below */ int2 relnatts; /* number of user attributes */ @@ -139,17 +139,18 @@ DESCR(""); DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ )); DESCR(""); + +#define RELKIND_RELATION 'r' /* ordinary table */ #define RELKIND_INDEX 'i' /* secondary index */ -#define RELKIND_RELATION 'r' /* ordinary cataloged heap */ -#define RELKIND_SEQUENCE 'S' /* SEQUENCE relation */ -#define RELKIND_UNCATALOGED 'u' /* temporary heap */ -#define RELKIND_TOASTVALUE 't' /* moved off huge values */ +#define RELKIND_SEQUENCE 'S' /* sequence object */ +#define RELKIND_TOASTVALUE 't' /* for out-of-line values */ #define RELKIND_VIEW 'v' /* view */ #define RELKIND_COMPOSITE_TYPE 'c' /* composite type */ #define RELKIND_FOREIGN_TABLE 'f' /* foreign table */ +#define RELKIND_UNCATALOGED 'u' /* not yet cataloged */ -#define RELPERSISTENCE_PERMANENT 'p' -#define RELPERSISTENCE_UNLOGGED 'u' -#define RELPERSISTENCE_TEMP 't' +#define RELPERSISTENCE_PERMANENT 'p' /* regular table */ +#define RELPERSISTENCE_UNLOGGED 'u' /* unlogged permanent table */ +#define RELPERSISTENCE_TEMP 't' /* temporary table */ #endif /* PG_CLASS_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 63a61e3da248b2a1677d35eb56ff2b82b9c53b64..536c03245e3335da7b1d49e8cbb70d607fdbb387 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -597,6 +597,9 @@ typedef struct XmlSerialize * like outer joins and join-output-column aliasing.) Other special * RTE types also exist, as indicated by RTEKind. * + * Note that we consider RTE_RELATION to cover anything that has a pg_class + * entry. relkind distinguishes the sub-cases. + * * alias is an Alias node representing the AS alias-clause attached to the * FROM expression, or NULL if no clause. * @@ -643,7 +646,7 @@ typedef struct XmlSerialize * indicates no permissions checking). If checkAsUser is not zero, * then do the permissions checks using the access rights of that user, * not the current effective user ID. (This allows rules to act as - * setuid gateways.) + * setuid gateways.) Permissions checks only apply to RELATION RTEs. * * For SELECT/INSERT/UPDATE permissions, if the user doesn't have * table-wide permissions then it is sufficient to have the permissions @@ -660,7 +663,6 @@ typedef enum RTEKind RTE_RELATION, /* ordinary relation reference */ RTE_SUBQUERY, /* subquery in FROM */ RTE_JOIN, /* join */ - RTE_SPECIAL, /* special rule relation (NEW or OLD) */ RTE_FUNCTION, /* function in FROM */ RTE_VALUES, /* VALUES (<exprlist>), (<exprlist>), ... */ RTE_CTE /* common table expr (WITH list element) */ @@ -682,6 +684,7 @@ typedef struct RangeTblEntry * Fields valid for a plain relation RTE (else zero): */ Oid relid; /* OID of the relation */ + char relkind; /* relation kind (see pg_class.relkind) */ /* * Fields valid for a subquery RTE (else NULL):