PostgreSQL Source Code: src/backend/rewrite/rewriteDefine.c Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
16
38
39
41 bool isSelect, bool requireColumnNameMatch);
44
45
46
47
48
49
50
53 int evtype,
54 Oid eventrel_oid,
55 bool evinstead,
56 Node *event_qual,
58 bool replace)
59{
63 bool nulls[Natts_pg_rewrite] = {0};
67 oldtup;
68 Oid rewriteObjectId;
70 referenced;
71 bool is_update = false;
72
73
74
75
84
85
86
87
89
90
91
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
109
110 replaces[Anum_pg_rewrite_ev_type - 1] = true;
111 replaces[Anum_pg_rewrite_is_instead - 1] = true;
112 replaces[Anum_pg_rewrite_ev_qual - 1] = true;
113 replaces[Anum_pg_rewrite_ev_action - 1] = true;
114
116 values, nulls, replaces);
117
119
121
123 is_update = true;
124 }
125 else
126 {
128 RewriteOidIndexId,
129 Anum_pg_rewrite_oid);
131
133
135 }
136
137
139
140
141 if (is_update)
143
144
145
146
147
148
149
150 myself.classId = RewriteRelationId;
151 myself.objectId = rewriteObjectId;
153
154 referenced.classId = RelationRelationId;
155 referenced.objectId = eventrel_oid;
157
160
161
162
163
166
167 if (event_qual != NULL)
168 {
169
171
175 }
176
177
179
181
182 return rewriteObjectId;
183}
184
185
186
187
188
191{
192 List *actions;
193 Node *whereClause;
194 Oid relId;
195
196
198
199
200
201
202
204
205
207 relId,
208 whereClause,
210 stmt->instead,
211 stmt->replace,
212 actions);
213}
214
215
216
217
218
219
220
221
222
225 Oid event_relid,
226 Node *event_qual,
228 bool is_instead,
229 bool replace,
231{
237
238
239
240
241
242
243
244
245
246
247
249
250
251
252
253
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)
260 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
261 errmsg("relation \"%s\" cannot have rules",
264
267 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
268 errmsg("permission denied: \"%s\" is a system catalog",
270
271
272
273
277
278
279
280
282 {
284 if (query->resultRelation == 0)
285 continue;
286
288 continue;
291 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
292 errmsg("rule actions on OLD are not implemented"),
293 errhint("Use views or triggers instead.")));
296 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
297 errmsg("rule actions on NEW are not implemented"),
298 errhint("Use triggers instead.")));
299 }
300
302 {
303
304
305
306
307
308 if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
309 event_relation->rd_rel->relkind != RELKIND_MATVIEW)
311 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
312 errmsg("relation \"%s\" cannot have ON SELECT rules",
315
316
317
318
321 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
322 errmsg("INSTEAD NOTHING rules on SELECT are not implemented"),
323 errhint("Use views instead.")));
324
325
326
327
330 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
331 errmsg("multiple actions for rules on SELECT are not implemented")));
332
333
334
335
337 if (!is_instead ||
340 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
341 errmsg("rules on SELECT must have action INSTEAD SELECT")));
342
343
344
345
346 if (query->hasModifyingCTE)
348 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
349 errmsg("rules on SELECT must not contain data-modifying statements in WITH")));
350
351
352
353
354 if (event_qual != NULL)
356 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
357 errmsg("event qualifications are not implemented for rules on SELECT")));
358
359
360
361
362
365 true,
366 event_relation->rd_rel->relkind !=
367 RELKIND_MATVIEW);
368
369
370
371
372 if (!replace && event_relation->rd_rules != NULL)
373 {
374 int i;
375
377 {
379
383 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
384 errmsg("\"%s\" is already a view",
386 }
387 }
388
389
390
391
393 {
394
395
396
397
398
399
400
401
402
403 if (strncmp(rulename, "_RET", 4) != 0 ||
407 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
408 errmsg("view rule for \"%s\" must be named \"%s\"",
412 }
413 }
414 else
415 {
416
417
418
419
420
421
422
423
424 bool haveReturning = false;
425
427 {
429
431 continue;
432 if (haveReturning)
434 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
435 errmsg("cannot have multiple RETURNING lists in a rule")));
436 haveReturning = true;
437 if (event_qual != NULL)
439 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
440 errmsg("RETURNING lists are not supported in conditional rules")));
441 if (!is_instead)
443 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
444 errmsg("RETURNING lists are not supported in non-INSTEAD rules")));
447 false, false);
448 }
449
450
451
452
453
454
457 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
458 errmsg("non-view rule for \"%s\" must not be named \"%s\"",
461 }
462
463
464
465
466
467
469 {
471 event_type,
472 event_relid,
473 is_instead,
474 event_qual,
476 replace);
477
478
479
480
481
482
483
484
486 }
487
489
490
492
493 return address;
494}
495
496
497
498
499
500
501
502
503
504
505static void
507 bool requireColumnNameMatch)
508{
510 int i;
511
512
513 Assert(isSelect || !requireColumnNameMatch);
514
515 i = 0;
516 foreach(tllist, targetList)
517 {
519 Oid tletypid;
523
524
525 if (tle->resjunk)
526 continue;
527 i++;
528 if (i > resultDesc->natts)
530 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
531 isSelect ?
532 errmsg("SELECT rule's target list has too many entries") :
533 errmsg("RETURNING list has too many entries")));
534
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556 if (attr->attisdropped)
558 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
559 isSelect ?
560 errmsg("cannot convert relation containing dropped columns to view") :
561 errmsg("cannot create a RETURNING list for a relation containing dropped columns")));
562
563
564 if (requireColumnNameMatch && strcmp(tle->resname, attname) != 0)
566 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
567 errmsg("SELECT rule's target entry %d has different column name from column \"%s\"",
569 errdetail("SELECT target entry is named \"%s\".",
570 tle->resname)));
571
572
574 if (attr->atttypid != tletypid)
576 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
577 isSelect ?
578 errmsg("SELECT rule's target entry %d has different type from column \"%s\"",
580 errmsg("RETURNING list's entry %d has different type from column \"%s\"",
582 isSelect ?
583 errdetail("SELECT target entry has type %s, but column has type %s.",
586 errdetail("RETURNING list entry has type %s, but column has type %s.",
589
590
591
592
593
594
595
597 if (attr->atttypmod != tletypmod &&
598 attr->atttypmod != -1 && tletypmod != -1)
600 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
601 isSelect ?
602 errmsg("SELECT rule's target entry %d has different size from column \"%s\"",
604 errmsg("RETURNING list's entry %d has different size from column \"%s\"",
606 isSelect ?
607 errdetail("SELECT target entry has type %s, but column has type %s.",
610 attr->atttypmod)) :
611 errdetail("RETURNING list entry has type %s, but column has type %s.",
614 attr->atttypmod))));
615 }
616
617 if (i != resultDesc->natts)
619 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
620 isSelect ?
621 errmsg("SELECT rule's target list has too few entries") :
622 errmsg("RETURNING list has too few entries")));
623}
624
625
626
627
628
629
630void
632{
634}
635
636static bool
638{
639 if (node == NULL)
640 return false;
642 {
644 return false;
645 }
647 context);
648}
649
650static void
652{
654
655
656 foreach(l, qry->rteperminfos)
657 {
659
661 }
662
663
664 foreach(l, qry->rtable)
665 {
667
670 }
671
672
674 {
676
678 }
679
680
681 if (qry->hasSubLinks)
684}
685
686
687
688
689
690void
692 char fires_when)
693{
696 Oid eventRelationOid;
699 bool changed = false;
700
701
702
703
710 (errcode(ERRCODE_UNDEFINED_OBJECT),
711 errmsg("rule \"%s\" for relation \"%s\" does not exist",
713
715
716
717
718
719 eventRelationOid = ruleform->ev_class;
720 Assert(eventRelationOid == owningRel);
724
725
726
727
729 fires_when)
730 {
731 ruleform->ev_enabled = CharGetDatum(fires_when);
733
734 changed = true;
735 }
736
738
741
742
743
744
745
746
747 if (changed)
749}
750
751
752
753
754
755static void
757 void *arg)
758{
761
764 return;
766
767
768 if (form->relkind != RELKIND_RELATION &&
769 form->relkind != RELKIND_VIEW &&
770 form->relkind != RELKIND_PARTITIONED_TABLE)
772 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
773 errmsg("relation \"%s\" cannot have rules", rv->relname),
775
778 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
779 errmsg("permission denied: \"%s\" is a system catalog",
781
782
785
787}
788
789
790
791
794 const char *newName)
795{
796 Oid relid;
801 Oid ruleOid;
803
804
805
806
807
809 0,
811 NULL);
812
813
815
816
818
819
825 (errcode(ERRCODE_UNDEFINED_OBJECT),
826 errmsg("rule \"%s\" for relation \"%s\" does not exist",
829 ruleOid = ruleform->oid;
830
831
835 errmsg("rule \"%s\" for relation \"%s\" already exists",
837
838
839
840
841
842 if (ruleform->ev_type == CMD_SELECT + '0')
844 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
845 errmsg("renaming an ON SELECT rule is not allowed")));
846
847
848 namestrcpy(&(ruleform->rulename), newName);
849
851
853
856
857
858
859
860
861
863
865
866
867
868
870
871 return address;
872}
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
static Datum values[MAXATTR]
#define CStringGetTextDatum(s)
bool IsSystemRelation(Relation relation)
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
int errdetail(const char *fmt,...)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
char * format_type_with_typemod(Oid type_oid, int32 typemod)
char * format_type_be(Oid type_oid)
bool allowSystemTableMods
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
void heap_freetuple(HeapTuple htup)
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
void CacheInvalidateRelcache(Relation relation)
#define AccessExclusiveLock
char * get_rel_name(Oid relid)
char get_rel_relkind(Oid relid)
char * pstrdup(const char *in)
void namestrcpy(Name name, const char *str)
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Oid exprType(const Node *expr)
int32 exprTypmod(const Node *expr)
#define query_tree_walker(q, w, c, f)
#define expression_tree_walker(n, w, c)
#define QTW_IGNORE_RC_SUBQUERIES
#define IsA(nodeptr, _type_)
#define castNode(_type_, nodeptr)
#define InvokeObjectPostCreateHook(classId, objectId, subId)
#define InvokeObjectPostAlterHook(classId, objectId, subId)
ObjectType get_relkind_objtype(char relkind)
#define ObjectAddressSet(addr, class_id, object_id)
char * nodeToString(const void *obj)
void transformRuleStmt(RuleStmt *stmt, const char *queryString, List **actions, Node **whereClause)
FormData_pg_attribute * Form_pg_attribute
int errdetail_relkind_not_supported(char relkind)
FormData_pg_class * Form_pg_class
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
#define lfirst_node(type, lc)
static int list_length(const List *l)
#define linitial_node(type, l)
FormData_pg_rewrite * Form_pg_rewrite
static Datum PointerGetDatum(const void *X)
static Datum BoolGetDatum(bool X)
static Datum ObjectIdGetDatum(Oid X)
static Datum NameGetDatum(const NameData *X)
static char DatumGetChar(Datum X)
static Datum CharGetDatum(char X)
#define RelationGetRelid(relation)
#define RelationGetDescr(relation)
#define RelationGetRelationName(relation)
static Oid InsertRule(const char *rulname, int evtype, Oid eventrel_oid, bool evinstead, Node *event_qual, List *action, bool replace)
void setRuleCheckAsUser(Node *node, Oid userid)
static bool setRuleCheckAsUser_walker(Node *node, Oid *context)
ObjectAddress DefineRule(RuleStmt *stmt, const char *queryString)
static void RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
static void checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect, bool requireColumnNameMatch)
static void setRuleCheckAsUser_Query(Query *qry, Oid userid)
ObjectAddress DefineQueryRewrite(const char *rulename, Oid event_relid, Node *event_qual, CmdType event_type, bool is_instead, bool replace, List *action)
void EnableDisableRule(Relation rel, const char *rulename, char fires_when)
ObjectAddress RenameRewriteRule(RangeVar *relation, const char *oldName, const char *newName)
#define RULE_FIRES_ON_ORIGIN
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
void SetRelationRuleStatus(Oid relationId, bool relHasRules)
bool IsDefinedRewriteRule(Oid owningRel, const char *ruleName)
#define ViewSelectRuleName
void relation_close(Relation relation, LOCKMODE lockmode)
Relation relation_open(Oid relationId, LOCKMODE lockmode)
#define ERRCODE_DUPLICATE_OBJECT
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
#define SearchSysCacheCopy2(cacheId, key1, key2)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)