PostgreSQL Source Code git master
Loading...
Searching...
No Matches
rewriteDefine.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/relation.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_rewrite.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/parse_utilcmd.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rewriteSupport.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for rewriteDefine.c:

Go to the source code of this file.

Functions

static void checkRuleResultList (List *targetList, TupleDesc resultDesc, bool isSelect, bool requireColumnNameMatch)
 
static bool setRuleCheckAsUser_walker (Node *node, Oid *context)
 
static void setRuleCheckAsUser_Query (Query *qry, Oid userid)
 
static Oid InsertRule (const char *rulname, int evtype, Oid eventrel_oid, bool evinstead, Node *event_qual, List *action, bool replace)
 
ObjectAddress DefineRule (RuleStmt *stmt, const char *queryString)
 
ObjectAddress DefineQueryRewrite (const char *rulename, Oid event_relid, Node *event_qual, CmdType event_type, bool is_instead, bool replace, List *action)
 
void setRuleCheckAsUser (Node *node, Oid userid)
 
void EnableDisableRule (Relation rel, const char *rulename, char fires_when)
 
static void RangeVarCallbackForRenameRule (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
ObjectAddress RenameRewriteRule (RangeVar *relation, const char *oldName, const char *newName)
 

Function Documentation

◆ checkRuleResultList()

static void checkRuleResultList ( List targetList,
TupleDesc  resultDesc,
bool  isSelect,
bool  requireColumnNameMatch 
)
static

Definition at line 503 of file rewriteDefine.c.

505{
507 int i;
508
509 /* Only a SELECT may require a column name match. */
511
512 i = 0;
513 foreach(tllist, targetList)
514 {
519 char *attname;
520
521 /* resjunk entries may be ignored */
522 if (tle->resjunk)
523 continue;
524 i++;
525 if (i > resultDesc->natts)
528 isSelect ?
529 errmsg("SELECT rule's target list has too many entries") :
530 errmsg("RETURNING list has too many entries")));
531
532 attr = TupleDescAttr(resultDesc, i - 1);
533 attname = NameStr(attr->attname);
534
535 /*
536 * Disallow dropped columns in the relation. This is not really
537 * expected to happen when creating an ON SELECT rule. It'd be
538 * possible if someone tried to convert a relation with dropped
539 * columns to a view, but the only case we care about supporting
540 * table-to-view conversion for is pg_dump, and pg_dump won't do that.
541 *
542 * Unfortunately, the situation is also possible when adding a rule
543 * with RETURNING to a regular table, and rejecting that case is
544 * altogether more annoying. In principle we could support it by
545 * modifying the targetlist to include dummy NULL columns
546 * corresponding to the dropped columns in the tupdesc. However,
547 * places like ruleutils.c would have to be fixed to not process such
548 * entries, and that would take an uncertain and possibly rather large
549 * amount of work. (Note we could not dodge that by marking the dummy
550 * columns resjunk, since it's precisely the non-resjunk tlist columns
551 * that are expected to correspond to table columns.)
552 */
553 if (attr->attisdropped)
556 isSelect ?
557 errmsg("cannot convert relation containing dropped columns to view") :
558 errmsg("cannot create a RETURNING list for a relation containing dropped columns")));
559
560 /* Check name match if required; no need for two error texts here */
561 if (requireColumnNameMatch && strcmp(tle->resname, attname) != 0)
564 errmsg("SELECT rule's target entry %d has different column name from column \"%s\"",
565 i, attname),
566 errdetail("SELECT target entry is named \"%s\".",
567 tle->resname)));
568
569 /* Check type match. */
570 tletypid = exprType((Node *) tle->expr);
571 if (attr->atttypid != tletypid)
574 isSelect ?
575 errmsg("SELECT rule's target entry %d has different type from column \"%s\"",
576 i, attname) :
577 errmsg("RETURNING list's entry %d has different type from column \"%s\"",
578 i, attname),
579 isSelect ?
580 errdetail("SELECT target entry has type %s, but column has type %s.",
582 format_type_be(attr->atttypid)) :
583 errdetail("RETURNING list entry has type %s, but column has type %s.",
585 format_type_be(attr->atttypid))));
586
587 /*
588 * Allow typmods to be different only if one of them is -1, ie,
589 * "unspecified". This is necessary for cases like "numeric", where
590 * the table will have a filled-in default length but the select
591 * rule's expression will probably have typmod = -1.
592 */
593 tletypmod = exprTypmod((Node *) tle->expr);
594 if (attr->atttypmod != tletypmod &&
595 attr->atttypmod != -1 && tletypmod != -1)
598 isSelect ?
599 errmsg("SELECT rule's target entry %d has different size from column \"%s\"",
600 i, attname) :
601 errmsg("RETURNING list's entry %d has different size from column \"%s\"",
602 i, attname),
603 isSelect ?
604 errdetail("SELECT target entry has type %s, but column has type %s.",
606 format_type_with_typemod(attr->atttypid,
607 attr->atttypmod)) :
608 errdetail("RETURNING list entry has type %s, but column has type %s.",
610 format_type_with_typemod(attr->atttypid,
611 attr->atttypmod))));
612 }
613
614 if (i != resultDesc->natts)
617 isSelect ?
618 errmsg("SELECT rule's target list has too few entries") :
619 errmsg("RETURNING list has too few entries")));
620}
#define NameStr(name)
Definition c.h:894
#define Assert(condition)
Definition c.h:1002
int32_t int32
Definition c.h:679
int errcode(int sqlerrcode)
Definition elog.c:875
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
char * format_type_with_typemod(Oid type_oid, int32 typemod)
char * format_type_be(Oid type_oid)
int i
Definition isn.c:77
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
static char * errmsg
NameData attname
FormData_pg_attribute * Form_pg_attribute
#define lfirst(lc)
Definition pg_list.h:172
unsigned int Oid
static int fb(int x)
Definition nodes.h:133
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178

References Assert, attname, ereport, errcode(), errdetail(), errmsg, ERROR, exprType(), exprTypmod(), fb(), format_type_be(), format_type_with_typemod(), i, lfirst, NameStr, TupleDescData::natts, and TupleDescAttr().

Referenced by DefineQueryRewrite().

◆ DefineQueryRewrite()

ObjectAddress DefineQueryRewrite ( const char rulename,
Oid  event_relid,
Node event_qual,
CmdType  event_type,
bool  is_instead,
bool  replace,
List action 
)

Definition at line 224 of file rewriteDefine.c.

231{
233 ListCell *l;
234 Query *query;
235 Oid ruleId = InvalidOid;
236 ObjectAddress address;
237
238 /*
239 * If we are installing an ON SELECT rule, we had better grab
240 * AccessExclusiveLock to ensure no SELECTs are currently running on the
241 * event relation. For other types of rules, it would be sufficient to
242 * grab ShareRowExclusiveLock to lock out insert/update/delete actions and
243 * to ensure that we lock out current CREATE RULE statements; but because
244 * of race conditions in access to catalog entries, we can't do that yet.
245 *
246 * Note that this lock level should match the one used in DefineRule.
247 */
249
250 /*
251 * Verify relation is of a type that rules can sensibly be applied to.
252 * Internal callers can target materialized views, but transformRuleStmt()
253 * blocks them for users. Don't mention them in the error message.
254 */
255 if (event_relation->rd_rel->relkind != RELKIND_RELATION &&
256 event_relation->rd_rel->relkind != RELKIND_MATVIEW &&
257 event_relation->rd_rel->relkind != RELKIND_VIEW &&
258 event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
261 errmsg("relation \"%s\" cannot have rules",
264
265 /*
266 * Conflict log tables are used internally for logical replication
267 * conflict logging and should not have rules, as it could disrupt
268 * conflict logging.
269 */
273 errmsg("conflict log table \"%s\" cannot have rules",
275 errdetail("Conflict log tables are system-managed tables for logical replication conflicts.")));
276
280 errmsg("permission denied: \"%s\" is a system catalog",
282
283 /*
284 * Check user has permission to apply rules to this relation.
285 */
289
290 /*
291 * No rule actions that modify OLD or NEW
292 */
293 foreach(l, action)
294 {
295 query = lfirst_node(Query, l);
296 if (query->resultRelation == 0)
297 continue;
298 /* Don't be fooled by INSERT/SELECT */
299 if (query != getInsertSelectQuery(query, NULL))
300 continue;
301 if (query->resultRelation == PRS2_OLD_VARNO)
304 errmsg("rule actions on OLD are not implemented"),
305 errhint("Use views or triggers instead.")));
306 if (query->resultRelation == PRS2_NEW_VARNO)
309 errmsg("rule actions on NEW are not implemented"),
310 errhint("Use triggers instead.")));
311 }
312
313 if (event_type == CMD_SELECT)
314 {
315 /*
316 * Rules ON SELECT are restricted to view definitions
317 *
318 * So this had better be a view, ...
319 */
320 if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
321 event_relation->rd_rel->relkind != RELKIND_MATVIEW)
324 errmsg("relation \"%s\" cannot have ON SELECT rules",
327
328 /*
329 * ... there cannot be INSTEAD NOTHING, ...
330 */
331 if (action == NIL)
334 errmsg("INSTEAD NOTHING rules on SELECT are not implemented"),
335 errhint("Use views instead.")));
336
337 /*
338 * ... there cannot be multiple actions, ...
339 */
340 if (list_length(action) > 1)
343 errmsg("multiple actions for rules on SELECT are not implemented")));
344
345 /*
346 * ... the one action must be a SELECT, ...
347 */
348 query = linitial_node(Query, action);
349 if (!is_instead ||
350 query->commandType != CMD_SELECT)
353 errmsg("rules on SELECT must have action INSTEAD SELECT")));
354
355 /*
356 * ... it cannot contain data-modifying WITH ...
357 */
358 if (query->hasModifyingCTE)
361 errmsg("rules on SELECT must not contain data-modifying statements in WITH")));
362
363 /*
364 * ... there can be no rule qual, ...
365 */
366 if (event_qual != NULL)
369 errmsg("event qualifications are not implemented for rules on SELECT")));
370
371 /*
372 * ... the targetlist of the SELECT action must exactly match the
373 * event relation, ...
374 */
377 true,
378 event_relation->rd_rel->relkind !=
380
381 /*
382 * ... there must not be another ON SELECT rule already ...
383 */
384 if (!replace && event_relation->rd_rules != NULL)
385 {
386 int i;
387
388 for (i = 0; i < event_relation->rd_rules->numLocks; i++)
389 {
391
392 rule = event_relation->rd_rules->rules[i];
393 if (rule->event == CMD_SELECT)
396 errmsg("\"%s\" is already a view",
398 }
399 }
400
401 /*
402 * ... and finally the rule must be named _RETURN.
403 */
404 if (strcmp(rulename, ViewSelectRuleName) != 0)
407 errmsg("view rule for \"%s\" must be named \"%s\"",
410 }
411 else
412 {
413 /*
414 * For non-SELECT rules, a RETURNING list can appear in at most one of
415 * the actions ... and there can't be any RETURNING list at all in a
416 * conditional or non-INSTEAD rule. (Actually, there can be at most
417 * one RETURNING list across all rules on the same event, but it seems
418 * best to enforce that at rule expansion time.) If there is a
419 * RETURNING list, it must match the event relation.
420 */
421 bool haveReturning = false;
422
423 foreach(l, action)
424 {
425 query = lfirst_node(Query, l);
426
427 if (!query->returningList)
428 continue;
429 if (haveReturning)
432 errmsg("cannot have multiple RETURNING lists in a rule")));
433 haveReturning = true;
434 if (event_qual != NULL)
437 errmsg("RETURNING lists are not supported in conditional rules")));
438 if (!is_instead)
441 errmsg("RETURNING lists are not supported in non-INSTEAD rules")));
444 false, false);
445 }
446
447 /*
448 * And finally, if it's not an ON SELECT rule then it must *not* be
449 * named _RETURN. This prevents accidentally or maliciously replacing
450 * a view's ON SELECT rule with some other kind of rule.
451 */
452 if (strcmp(rulename, ViewSelectRuleName) == 0)
455 errmsg("non-view rule for \"%s\" must not be named \"%s\"",
458 }
459
460 /*
461 * This rule is allowed - prepare to install it.
462 */
463
464 /* discard rule if it's null action and not INSTEAD; it's a no-op */
465 if (action != NIL || is_instead)
466 {
467 ruleId = InsertRule(rulename,
470 is_instead,
472 action,
473 replace);
474
475 /*
476 * Set pg_class 'relhasrules' field true for event relation.
477 *
478 * Important side effect: an SI notice is broadcast to force all
479 * backends (including me!) to update relcache entries with the new
480 * rule.
481 */
483 }
484
485 ObjectAddressSet(address, RewriteRelationId, ruleId);
486
487 /* Close rel, but keep lock till commit... */
489
490 return address;
491}
@ ACLCHECK_NOT_OWNER
Definition acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4156
bool IsConflictLogTableClass(Form_pg_class reltuple)
Definition catalog.c:242
bool IsSystemRelation(Relation relation)
Definition catalog.c:74
int errhint(const char *fmt,...) pg_attribute_printf(1
bool allowSystemTableMods
Definition globals.c:132
#define NoLock
Definition lockdefs.h:34
#define AccessExclusiveLock
Definition lockdefs.h:43
Oid GetUserId(void)
Definition miscinit.c:470
@ CMD_SELECT
Definition nodes.h:273
ObjectType get_relkind_objtype(char relkind)
#define ObjectAddressSet(addr, class_id, object_id)
int errdetail_relkind_not_supported(char relkind)
Definition pg_class.c:24
#define lfirst_node(type, lc)
Definition pg_list.h:176
static int list_length(const List *l)
Definition pg_list.h:152
#define linitial_node(type, l)
Definition pg_list.h:181
#define NIL
Definition pg_list.h:68
#define InvalidOid
#define PRS2_OLD_VARNO
Definition primnodes.h:251
#define PRS2_NEW_VARNO
Definition primnodes.h:252
#define RelationGetDescr(relation)
Definition rel.h:542
#define RelationGetRelationName(relation)
Definition rel.h:550
static Oid InsertRule(const char *rulname, int evtype, Oid eventrel_oid, bool evinstead, Node *event_qual, List *action, bool replace)
static void checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect, bool requireColumnNameMatch)
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
void SetRelationRuleStatus(Oid relationId, bool relHasRules)
#define ViewSelectRuleName
List * returningList
Definition parsenodes.h:219
CmdType commandType
Definition parsenodes.h:124
List * targetList
Definition parsenodes.h:203
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40

References AccessExclusiveLock, aclcheck_error(), ACLCHECK_NOT_OWNER, allowSystemTableMods, checkRuleResultList(), CMD_SELECT, Query::commandType, ereport, errcode(), errdetail(), errdetail_relkind_not_supported(), errhint(), errmsg, ERROR, fb(), get_relkind_objtype(), getInsertSelectQuery(), GetUserId(), i, InsertRule(), InvalidOid, IsConflictLogTableClass(), IsSystemRelation(), lfirst_node, linitial_node, list_length(), NIL, NoLock, object_ownercheck(), ObjectAddressSet, PRS2_NEW_VARNO, PRS2_OLD_VARNO, RelationGetDescr, RelationGetRelationName, Query::returningList, SetRelationRuleStatus(), table_close(), table_open(), Query::targetList, and ViewSelectRuleName.

Referenced by DefineRule(), and DefineViewRules().

◆ DefineRule()

ObjectAddress DefineRule ( RuleStmt stmt,
const char queryString 
)

Definition at line 190 of file rewriteDefine.c.

191{
192 List *actions;
193 Node *whereClause;
194 Oid relId;
195
196 /* Parse analysis. */
197 transformRuleStmt(stmt, queryString, &actions, &whereClause);
198
199 /*
200 * Find and lock the relation. Lock level should match
201 * DefineQueryRewrite.
202 */
203 relId = RangeVarGetRelid(stmt->relation, AccessExclusiveLock, false);
204
205 /* ... and execute */
206 return DefineQueryRewrite(stmt->rulename,
207 relId,
208 whereClause,
209 stmt->event,
210 stmt->instead,
211 stmt->replace,
212 actions);
213}
#define stmt
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition namespace.h:98
void transformRuleStmt(RuleStmt *stmt, const char *queryString, List **actions, Node **whereClause)
ObjectAddress DefineQueryRewrite(const char *rulename, Oid event_relid, Node *event_qual, CmdType event_type, bool is_instead, bool replace, List *action)
Definition pg_list.h:54

References AccessExclusiveLock, DefineQueryRewrite(), RangeVarGetRelid, stmt, and transformRuleStmt().

Referenced by ProcessUtilitySlow().

◆ EnableDisableRule()

void EnableDisableRule ( Relation  rel,
const char rulename,
char  fires_when 
)

Definition at line 688 of file rewriteDefine.c.

690{
696 bool changed = false;
697
698 /*
699 * Find the rule tuple to change.
700 */
704 PointerGetDatum(rulename));
708 errmsg("rule \"%s\" for relation \"%s\" does not exist",
709 rulename, get_rel_name(owningRel))));
710
712
713 /*
714 * Verify that the user has appropriate permissions.
715 */
716 eventRelationOid = ruleform->ev_class;
721
722 /*
723 * Change ev_enabled if it is different from the desired new state.
724 */
725 if (ruleform->ev_enabled != fires_when)
726 {
727 ruleform->ev_enabled = fires_when;
729
730 changed = true;
731 }
732
734
737
738 /*
739 * If we changed anything, broadcast a SI inval message to force each
740 * backend (including our own!) to rebuild relation's relcache entry.
741 * Otherwise they will fail to apply the change promptly.
742 */
743 if (changed)
745}
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CacheInvalidateRelcache(Relation relation)
Definition inval.c:1632
#define RowExclusiveLock
Definition lockdefs.h:38
char * get_rel_name(Oid relid)
Definition lsyscache.c:2242
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2317
#define InvokeObjectPostAlterHook(classId, objectId, subId)
END_CATALOG_STRUCT typedef FormData_pg_rewrite * Form_pg_rewrite
Definition pg_rewrite.h:56
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
#define PointerGetDatum(X)
Definition postgres.h:354
#define RelationGetRelid(relation)
Definition rel.h:516
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition syscache.h:93

References aclcheck_error(), ACLCHECK_NOT_OWNER, Assert, CacheInvalidateRelcache(), CatalogTupleUpdate(), ereport, errcode(), errmsg, ERROR, fb(), Form_pg_rewrite, get_rel_name(), get_rel_relkind(), get_relkind_objtype(), GETSTRUCT(), GetUserId(), heap_freetuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, object_ownercheck(), ObjectIdGetDatum(), PointerGetDatum, RelationGetRelid, RowExclusiveLock, SearchSysCacheCopy2, table_close(), and table_open().

Referenced by ATExecEnableDisableRule().

◆ InsertRule()

static Oid InsertRule ( const char rulname,
int  evtype,
Oid  eventrel_oid,
bool  evinstead,
Node event_qual,
List action,
bool  replace 
)
static

Definition at line 52 of file rewriteDefine.c.

59{
61 char *actiontree = nodeToString((Node *) action);
63 bool nulls[Natts_pg_rewrite] = {0};
67 oldtup;
71 bool is_update = false;
72
73 /*
74 * Set up *nulls and *values arrays
75 */
84
85 /*
86 * Ready to store new pg_rewrite tuple
87 */
89
90 /*
91 * Check to see if we are replacing an existing tuple
92 */
96
98 {
99 bool replaces[Natts_pg_rewrite] = {0};
100
101 if (!replace)
104 errmsg("rule \"%s\" for relation \"%s\" already exists",
106
107 /*
108 * When replacing, we don't need to replace every attribute
109 */
114
116 values, nulls, replaces);
117
119
121
123 is_update = true;
124 }
125 else
126 {
131
132 tup = heap_form_tuple(pg_rewrite_desc->rd_att, values, nulls);
133
135 }
136
137
139
140 /* If replacing, get rid of old dependencies and make new ones */
141 if (is_update)
143
144 /*
145 * Install dependency on rule's relation to ensure it will go away on
146 * relation deletion. If the rule is ON SELECT, make the dependency
147 * implicit --- this prevents deleting a view's SELECT rule. Other kinds
148 * of rules can be AUTO.
149 */
150 myself.classId = RewriteRelationId;
151 myself.objectId = rewriteObjectId;
152 myself.objectSubId = 0;
153
155 referenced.objectId = eventrel_oid;
156 referenced.objectSubId = 0;
157
160
161 /*
162 * Also install dependencies on objects referenced in action and qual.
163 */
166
167 if (event_qual != NULL)
168 {
169 /* Find query containing OLD/NEW rtable entries */
170 Query *qry = linitial_node(Query, action);
171
172 qry = getInsertSelectQuery(qry, NULL);
175 }
176
177 /* Post creation hook for new rule */
179
181
182 return rewriteObjectId;
183}
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define CStringGetTextDatum(s)
Definition builtins.h:98
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:475
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
@ DEPENDENCY_AUTO
Definition dependency.h:34
@ DEPENDENCY_INTERNAL
Definition dependency.h:35
@ DEPENDENCY_NORMAL
Definition dependency.h:33
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1118
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
void namestrcpy(Name name, const char *str)
Definition name.c:233
#define InvokeObjectPostCreateHook(classId, objectId, subId)
char * nodeToString(const void *obj)
Definition outfuncs.c:811
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition pg_depend.c:51
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition pg_depend.c:314
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:406
uint64_t Datum
Definition postgres.h:70
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define RULE_FIRES_ON_ORIGIN
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30
List * rtable
Definition parsenodes.h:180
Definition c.h:889
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:231

References BoolGetDatum(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum(), CMD_SELECT, CStringGetTextDatum, deleteDependencyRecordsFor(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), Form_pg_rewrite, get_rel_name(), getInsertSelectQuery(), GetNewOidWithIndex(), GETSTRUCT(), heap_form_tuple(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostCreateHook, linitial_node, NameGetDatum(), namestrcpy(), NIL, nodeToString(), ObjectIdGetDatum(), PointerGetDatum, recordDependencyOn(), recordDependencyOnExpr(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, Query::rtable, RULE_FIRES_ON_ORIGIN, SearchSysCache2(), table_close(), table_open(), and values.

Referenced by DefineQueryRewrite().

◆ RangeVarCallbackForRenameRule()

static void RangeVarCallbackForRenameRule ( const RangeVar rv,
Oid  relid,
Oid  oldrelid,
void arg 
)
static

Definition at line 752 of file rewriteDefine.c.

754{
755 HeapTuple tuple;
757
758 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
759 if (!HeapTupleIsValid(tuple))
760 return; /* concurrently dropped */
761 form = (Form_pg_class) GETSTRUCT(tuple);
762
763 /* only tables and views can have rules */
764 if (form->relkind != RELKIND_RELATION &&
765 form->relkind != RELKIND_VIEW &&
769 errmsg("relation \"%s\" cannot have rules", rv->relname),
771
772 /*
773 * Conflict log tables are used internally for logical replication
774 * conflict logging and should not have rules, as it could disrupt
775 * conflict logging.
776 */
780 errmsg("conflict log table \"%s\" cannot have rules",
781 rv->relname),
782 errdetail("Conflict log tables are system-managed tables for logical replication conflicts.")));
783
787 errmsg("permission denied: \"%s\" is a system catalog",
788 rv->relname)));
789
790 /* you must own the table to rename one of its rules */
793
794 ReleaseSysCache(tuple);
795}
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition catalog.c:86
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
char * relname
Definition primnodes.h:84
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221

References aclcheck_error(), ACLCHECK_NOT_OWNER, allowSystemTableMods, ereport, errcode(), errdetail(), errdetail_relkind_not_supported(), errmsg, ERROR, fb(), get_rel_relkind(), get_relkind_objtype(), GETSTRUCT(), GetUserId(), HeapTupleIsValid, IsConflictLogTableClass(), IsSystemClass(), object_ownercheck(), ObjectIdGetDatum(), ReleaseSysCache(), RangeVar::relname, and SearchSysCache1().

Referenced by RenameRewriteRule().

◆ RenameRewriteRule()

ObjectAddress RenameRewriteRule ( RangeVar relation,
const char oldName,
const char newName 
)

Definition at line 801 of file rewriteDefine.c.

803{
804 Oid relid;
809 Oid ruleOid;
810 ObjectAddress address;
811
812 /*
813 * Look up name, check permissions, and acquire lock (which we will NOT
814 * release until end of transaction).
815 */
817 0,
819 NULL);
820
821 /* Have lock already, so just need to build relcache entry. */
823
824 /* Prepare to modify pg_rewrite */
826
827 /* Fetch the rule's entry (it had better exist) */
829 ObjectIdGetDatum(relid),
834 errmsg("rule \"%s\" for relation \"%s\" does not exist",
837 ruleOid = ruleform->oid;
838
839 /* rule with the new name should not already exist */
840 if (IsDefinedRewriteRule(relid, newName))
843 errmsg("rule \"%s\" for relation \"%s\" already exists",
845
846 /*
847 * We disallow renaming ON SELECT rules, because they should always be
848 * named "_RETURN".
849 */
850 if (ruleform->ev_type == CMD_SELECT + '0')
853 errmsg("renaming an ON SELECT rule is not allowed")));
854
855 /*
856 * Conversely, if it's not an ON SELECT rule then it must *not* be named
857 * _RETURN.
858 */
862 errmsg("non-view rule for \"%s\" must not be named \"%s\"",
865
866 /* OK, do the update */
867 namestrcpy(&(ruleform->rulename), newName);
868
870
872
875
876 /*
877 * Invalidate relation's relcache entry so that other backends (and this
878 * one too!) are sent SI message to make them rebuild relcache entries.
879 * (Ideally this should happen automatically...)
880 */
882
884
885 /*
886 * Close rel, but keep exclusive lock!
887 */
889
890 return address;
891}
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition namespace.c:442
static void RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
bool IsDefinedRewriteRule(Oid owningRel, const char *ruleName)
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:48

References AccessExclusiveLock, CacheInvalidateRelcache(), CatalogTupleUpdate(), CMD_SELECT, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), Form_pg_rewrite, GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, IsDefinedRewriteRule(), namestrcpy(), NoLock, ObjectAddressSet, ObjectIdGetDatum(), PointerGetDatum, RangeVarCallbackForRenameRule(), RangeVarGetRelidExtended(), relation_close(), relation_open(), RelationGetRelationName, RowExclusiveLock, SearchSysCacheCopy2, table_close(), table_open(), and ViewSelectRuleName.

Referenced by ExecRenameStmt().

◆ setRuleCheckAsUser()

void setRuleCheckAsUser ( Node node,
Oid  userid 
)

Definition at line 628 of file rewriteDefine.c.

629{
630 (void) setRuleCheckAsUser_walker(node, &userid);
631}
static bool setRuleCheckAsUser_walker(Node *node, Oid *context)

References fb(), and setRuleCheckAsUser_walker().

Referenced by get_row_security_policies(), and RelationBuildRuleLock().

◆ setRuleCheckAsUser_Query()

static void setRuleCheckAsUser_Query ( Query qry,
Oid  userid 
)
static

Definition at line 648 of file rewriteDefine.c.

649{
650 ListCell *l;
651
652 /* Set in all RTEPermissionInfos for this query. */
653 foreach(l, qry->rteperminfos)
654 {
656
657 perminfo->checkAsUser = userid;
658 }
659
660 /* Now recurse to any subquery RTEs */
661 foreach(l, qry->rtable)
662 {
664
665 if (rte->rtekind == RTE_SUBQUERY)
666 setRuleCheckAsUser_Query(rte->subquery, userid);
667 }
668
669 /* Recurse into subquery-in-WITH */
670 foreach(l, qry->cteList)
671 {
673
675 }
676
677 /* If there are sublinks, search for them and process their RTEs */
678 if (qry->hasSubLinks)
681}
#define query_tree_walker(q, w, c, f)
Definition nodeFuncs.h:158
#define QTW_IGNORE_RC_SUBQUERIES
Definition nodeFuncs.h:24
#define castNode(_type_, nodeptr)
Definition nodes.h:180
@ RTE_SUBQUERY
static void setRuleCheckAsUser_Query(Query *qry, Oid userid)
List * cteList
Definition parsenodes.h:178

References castNode, Query::cteList, CommonTableExpr::ctequery, fb(), lfirst, lfirst_node, QTW_IGNORE_RC_SUBQUERIES, query_tree_walker, Query::rtable, RTE_SUBQUERY, setRuleCheckAsUser_Query(), and setRuleCheckAsUser_walker().

Referenced by setRuleCheckAsUser_Query(), and setRuleCheckAsUser_walker().

◆ setRuleCheckAsUser_walker()

static bool setRuleCheckAsUser_walker ( Node node,
Oid context 
)
static

Definition at line 634 of file rewriteDefine.c.

635{
636 if (node == NULL)
637 return false;
638 if (IsA(node, Query))
639 {
640 setRuleCheckAsUser_Query((Query *) node, *context);
641 return false;
642 }
644 context);
645}
#define expression_tree_walker(n, w, c)
Definition nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition nodes.h:162

References expression_tree_walker, fb(), IsA, setRuleCheckAsUser_Query(), and setRuleCheckAsUser_walker().

Referenced by setRuleCheckAsUser(), setRuleCheckAsUser_Query(), and setRuleCheckAsUser_walker().