00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/heapam.h"
00018 #include "access/htup_details.h"
00019 #include "access/multixact.h"
00020 #include "access/transam.h"
00021 #include "access/xact.h"
00022 #include "catalog/catalog.h"
00023 #include "catalog/dependency.h"
00024 #include "catalog/heap.h"
00025 #include "catalog/indexing.h"
00026 #include "catalog/namespace.h"
00027 #include "catalog/objectaccess.h"
00028 #include "catalog/pg_rewrite.h"
00029 #include "catalog/storage.h"
00030 #include "miscadmin.h"
00031 #include "nodes/nodeFuncs.h"
00032 #include "parser/parse_utilcmd.h"
00033 #include "rewrite/rewriteDefine.h"
00034 #include "rewrite/rewriteManip.h"
00035 #include "rewrite/rewriteSupport.h"
00036 #include "utils/acl.h"
00037 #include "utils/builtins.h"
00038 #include "utils/inval.h"
00039 #include "utils/lsyscache.h"
00040 #include "utils/rel.h"
00041 #include "utils/syscache.h"
00042 #include "utils/tqual.h"
00043
00044
00045 static void checkRuleResultList(List *targetList, TupleDesc resultDesc,
00046 bool isSelect);
00047 static bool setRuleCheckAsUser_walker(Node *node, Oid *context);
00048 static void setRuleCheckAsUser_Query(Query *qry, Oid userid);
00049
00050
00051
00052
00053
00054
00055
00056 static Oid
00057 InsertRule(char *rulname,
00058 int evtype,
00059 Oid eventrel_oid,
00060 AttrNumber evslot_index,
00061 bool evinstead,
00062 Node *event_qual,
00063 List *action,
00064 bool replace)
00065 {
00066 char *evqual = nodeToString(event_qual);
00067 char *actiontree = nodeToString((Node *) action);
00068 Datum values[Natts_pg_rewrite];
00069 bool nulls[Natts_pg_rewrite];
00070 bool replaces[Natts_pg_rewrite];
00071 NameData rname;
00072 Relation pg_rewrite_desc;
00073 HeapTuple tup,
00074 oldtup;
00075 Oid rewriteObjectId;
00076 ObjectAddress myself,
00077 referenced;
00078 bool is_update = false;
00079
00080
00081
00082
00083 MemSet(nulls, false, sizeof(nulls));
00084
00085 namestrcpy(&rname, rulname);
00086 values[Anum_pg_rewrite_rulename - 1] = NameGetDatum(&rname);
00087 values[Anum_pg_rewrite_ev_class - 1] = ObjectIdGetDatum(eventrel_oid);
00088 values[Anum_pg_rewrite_ev_attr - 1] = Int16GetDatum(evslot_index);
00089 values[Anum_pg_rewrite_ev_type - 1] = CharGetDatum(evtype + '0');
00090 values[Anum_pg_rewrite_ev_enabled - 1] = CharGetDatum(RULE_FIRES_ON_ORIGIN);
00091 values[Anum_pg_rewrite_is_instead - 1] = BoolGetDatum(evinstead);
00092 values[Anum_pg_rewrite_ev_qual - 1] = CStringGetTextDatum(evqual);
00093 values[Anum_pg_rewrite_ev_action - 1] = CStringGetTextDatum(actiontree);
00094
00095
00096
00097
00098 pg_rewrite_desc = heap_open(RewriteRelationId, RowExclusiveLock);
00099
00100
00101
00102
00103 oldtup = SearchSysCache2(RULERELNAME,
00104 ObjectIdGetDatum(eventrel_oid),
00105 PointerGetDatum(rulname));
00106
00107 if (HeapTupleIsValid(oldtup))
00108 {
00109 if (!replace)
00110 ereport(ERROR,
00111 (errcode(ERRCODE_DUPLICATE_OBJECT),
00112 errmsg("rule \"%s\" for relation \"%s\" already exists",
00113 rulname, get_rel_name(eventrel_oid))));
00114
00115
00116
00117
00118 MemSet(replaces, false, sizeof(replaces));
00119 replaces[Anum_pg_rewrite_ev_attr - 1] = true;
00120 replaces[Anum_pg_rewrite_ev_type - 1] = true;
00121 replaces[Anum_pg_rewrite_is_instead - 1] = true;
00122 replaces[Anum_pg_rewrite_ev_qual - 1] = true;
00123 replaces[Anum_pg_rewrite_ev_action - 1] = true;
00124
00125 tup = heap_modify_tuple(oldtup, RelationGetDescr(pg_rewrite_desc),
00126 values, nulls, replaces);
00127
00128 simple_heap_update(pg_rewrite_desc, &tup->t_self, tup);
00129
00130 ReleaseSysCache(oldtup);
00131
00132 rewriteObjectId = HeapTupleGetOid(tup);
00133 is_update = true;
00134 }
00135 else
00136 {
00137 tup = heap_form_tuple(pg_rewrite_desc->rd_att, values, nulls);
00138
00139 rewriteObjectId = simple_heap_insert(pg_rewrite_desc, tup);
00140 }
00141
00142
00143 CatalogUpdateIndexes(pg_rewrite_desc, tup);
00144
00145 heap_freetuple(tup);
00146
00147
00148 if (is_update)
00149 deleteDependencyRecordsFor(RewriteRelationId, rewriteObjectId, false);
00150
00151
00152
00153
00154
00155
00156
00157 myself.classId = RewriteRelationId;
00158 myself.objectId = rewriteObjectId;
00159 myself.objectSubId = 0;
00160
00161 referenced.classId = RelationRelationId;
00162 referenced.objectId = eventrel_oid;
00163 referenced.objectSubId = 0;
00164
00165 recordDependencyOn(&myself, &referenced,
00166 (evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
00167
00168
00169
00170
00171 recordDependencyOnExpr(&myself, (Node *) action, NIL,
00172 DEPENDENCY_NORMAL);
00173
00174 if (event_qual != NULL)
00175 {
00176
00177 Query *qry = (Query *) linitial(action);
00178
00179 qry = getInsertSelectQuery(qry, NULL);
00180 recordDependencyOnExpr(&myself, event_qual, qry->rtable,
00181 DEPENDENCY_NORMAL);
00182 }
00183
00184
00185 InvokeObjectPostCreateHook(RewriteRelationId, rewriteObjectId, 0);
00186
00187 heap_close(pg_rewrite_desc, RowExclusiveLock);
00188
00189 return rewriteObjectId;
00190 }
00191
00192
00193
00194
00195
00196 Oid
00197 DefineRule(RuleStmt *stmt, const char *queryString)
00198 {
00199 List *actions;
00200 Node *whereClause;
00201 Oid relId;
00202
00203
00204 transformRuleStmt(stmt, queryString, &actions, &whereClause);
00205
00206
00207
00208
00209
00210 relId = RangeVarGetRelid(stmt->relation, AccessExclusiveLock, false);
00211
00212
00213 return DefineQueryRewrite(stmt->rulename,
00214 relId,
00215 whereClause,
00216 stmt->event,
00217 stmt->instead,
00218 stmt->replace,
00219 actions);
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 Oid
00231 DefineQueryRewrite(char *rulename,
00232 Oid event_relid,
00233 Node *event_qual,
00234 CmdType event_type,
00235 bool is_instead,
00236 bool replace,
00237 List *action)
00238 {
00239 Relation event_relation;
00240 int event_attno;
00241 ListCell *l;
00242 Query *query;
00243 bool RelisBecomingView = false;
00244 Oid ruleId = InvalidOid;
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 event_relation = heap_open(event_relid, AccessExclusiveLock);
00257
00258
00259
00260
00261 if (event_relation->rd_rel->relkind != RELKIND_RELATION &&
00262 event_relation->rd_rel->relkind != RELKIND_MATVIEW &&
00263 event_relation->rd_rel->relkind != RELKIND_VIEW)
00264 ereport(ERROR,
00265 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00266 errmsg("\"%s\" is not a table or view",
00267 RelationGetRelationName(event_relation))));
00268
00269 if (!allowSystemTableMods && IsSystemRelation(event_relation))
00270 ereport(ERROR,
00271 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00272 errmsg("permission denied: \"%s\" is a system catalog",
00273 RelationGetRelationName(event_relation))));
00274
00275
00276
00277
00278 if (!pg_class_ownercheck(event_relid, GetUserId()))
00279 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
00280 RelationGetRelationName(event_relation));
00281
00282
00283
00284
00285 foreach(l, action)
00286 {
00287 query = (Query *) lfirst(l);
00288 if (query->resultRelation == 0)
00289 continue;
00290
00291 if (query != getInsertSelectQuery(query, NULL))
00292 continue;
00293 if (query->resultRelation == PRS2_OLD_VARNO)
00294 ereport(ERROR,
00295 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00296 errmsg("rule actions on OLD are not implemented"),
00297 errhint("Use views or triggers instead.")));
00298 if (query->resultRelation == PRS2_NEW_VARNO)
00299 ereport(ERROR,
00300 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00301 errmsg("rule actions on NEW are not implemented"),
00302 errhint("Use triggers instead.")));
00303 }
00304
00305 if (event_type == CMD_SELECT)
00306 {
00307
00308
00309
00310
00311
00312 if (list_length(action) == 0)
00313 ereport(ERROR,
00314 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00315 errmsg("INSTEAD NOTHING rules on SELECT are not implemented"),
00316 errhint("Use views instead.")));
00317
00318
00319
00320
00321 if (list_length(action) > 1)
00322 ereport(ERROR,
00323 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00324 errmsg("multiple actions for rules on SELECT are not implemented")));
00325
00326
00327
00328
00329 query = (Query *) linitial(action);
00330 if (!is_instead ||
00331 query->commandType != CMD_SELECT ||
00332 query->utilityStmt != NULL)
00333 ereport(ERROR,
00334 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00335 errmsg("rules on SELECT must have action INSTEAD SELECT")));
00336
00337
00338
00339
00340 if (query->hasModifyingCTE)
00341 ereport(ERROR,
00342 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00343 errmsg("rules on SELECT must not contain data-modifying statements in WITH")));
00344
00345
00346
00347
00348 if (event_qual != NULL)
00349 ereport(ERROR,
00350 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00351 errmsg("event qualifications are not implemented for rules on SELECT")));
00352
00353
00354
00355
00356
00357 checkRuleResultList(query->targetList,
00358 RelationGetDescr(event_relation),
00359 true);
00360
00361
00362
00363
00364 if (!replace && event_relation->rd_rules != NULL)
00365 {
00366 int i;
00367
00368 for (i = 0; i < event_relation->rd_rules->numLocks; i++)
00369 {
00370 RewriteRule *rule;
00371
00372 rule = event_relation->rd_rules->rules[i];
00373 if (rule->event == CMD_SELECT)
00374 ereport(ERROR,
00375 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00376 errmsg("\"%s\" is already a view",
00377 RelationGetRelationName(event_relation))));
00378 }
00379 }
00380
00381
00382
00383
00384 if (strcmp(rulename, ViewSelectRuleName) != 0)
00385 {
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 if (strncmp(rulename, "_RET", 4) != 0 ||
00396 strncmp(rulename + 4, RelationGetRelationName(event_relation),
00397 NAMEDATALEN - 4 - 4) != 0)
00398 ereport(ERROR,
00399 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00400 errmsg("view rule for \"%s\" must be named \"%s\"",
00401 RelationGetRelationName(event_relation),
00402 ViewSelectRuleName)));
00403 rulename = pstrdup(ViewSelectRuleName);
00404 }
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
00418 event_relation->rd_rel->relkind != RELKIND_MATVIEW)
00419 {
00420 HeapScanDesc scanDesc;
00421
00422 scanDesc = heap_beginscan(event_relation, SnapshotNow, 0, NULL);
00423 if (heap_getnext(scanDesc, ForwardScanDirection) != NULL)
00424 ereport(ERROR,
00425 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00426 errmsg("could not convert table \"%s\" to a view because it is not empty",
00427 RelationGetRelationName(event_relation))));
00428 heap_endscan(scanDesc);
00429
00430 if (event_relation->rd_rel->relhastriggers)
00431 ereport(ERROR,
00432 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00433 errmsg("could not convert table \"%s\" to a view because it has triggers",
00434 RelationGetRelationName(event_relation)),
00435 errhint("In particular, the table cannot be involved in any foreign key relationships.")));
00436
00437 if (event_relation->rd_rel->relhasindex)
00438 ereport(ERROR,
00439 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00440 errmsg("could not convert table \"%s\" to a view because it has indexes",
00441 RelationGetRelationName(event_relation))));
00442
00443 if (event_relation->rd_rel->relhassubclass)
00444 ereport(ERROR,
00445 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00446 errmsg("could not convert table \"%s\" to a view because it has child tables",
00447 RelationGetRelationName(event_relation))));
00448
00449 RelisBecomingView = true;
00450 }
00451 }
00452 else
00453 {
00454
00455
00456
00457
00458
00459
00460
00461
00462 bool haveReturning = false;
00463
00464 foreach(l, action)
00465 {
00466 query = (Query *) lfirst(l);
00467
00468 if (!query->returningList)
00469 continue;
00470 if (haveReturning)
00471 ereport(ERROR,
00472 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00473 errmsg("cannot have multiple RETURNING lists in a rule")));
00474 haveReturning = true;
00475 if (event_qual != NULL)
00476 ereport(ERROR,
00477 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00478 errmsg("RETURNING lists are not supported in conditional rules")));
00479 if (!is_instead)
00480 ereport(ERROR,
00481 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00482 errmsg("RETURNING lists are not supported in non-INSTEAD rules")));
00483 checkRuleResultList(query->returningList,
00484 RelationGetDescr(event_relation),
00485 false);
00486 }
00487 }
00488
00489
00490
00491
00492 event_attno = -1;
00493
00494
00495 if (action != NIL || is_instead)
00496 {
00497 ruleId = InsertRule(rulename,
00498 event_type,
00499 event_relid,
00500 event_attno,
00501 is_instead,
00502 event_qual,
00503 action,
00504 replace);
00505
00506
00507
00508
00509
00510
00511
00512
00513 SetRelationRuleStatus(event_relid, true);
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 if (RelisBecomingView)
00530 {
00531 Relation relationRelation;
00532 Oid toastrelid;
00533 HeapTuple classTup;
00534 Form_pg_class classForm;
00535
00536 relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
00537 toastrelid = event_relation->rd_rel->reltoastrelid;
00538
00539
00540 RelationDropStorage(event_relation);
00541 DeleteSystemAttributeTuples(event_relid);
00542
00543
00544
00545
00546
00547
00548 if (OidIsValid(toastrelid))
00549 {
00550 ObjectAddress toastobject;
00551
00552
00553
00554
00555
00556 deleteDependencyRecordsFor(RelationRelationId, toastrelid,
00557 false);
00558
00559
00560 CommandCounterIncrement();
00561
00562
00563 toastobject.classId = RelationRelationId;
00564 toastobject.objectId = toastrelid;
00565 toastobject.objectSubId = 0;
00566 performDeletion(&toastobject, DROP_RESTRICT,
00567 PERFORM_DELETION_INTERNAL);
00568 }
00569
00570
00571
00572
00573
00574 CommandCounterIncrement();
00575
00576
00577
00578
00579
00580
00581 classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(event_relid));
00582 if (!HeapTupleIsValid(classTup))
00583 elog(ERROR, "cache lookup failed for relation %u", event_relid);
00584 classForm = (Form_pg_class) GETSTRUCT(classTup);
00585
00586 classForm->reltablespace = InvalidOid;
00587 classForm->relpages = 0;
00588 classForm->reltuples = 0;
00589 classForm->relallvisible = 0;
00590 classForm->reltoastrelid = InvalidOid;
00591 classForm->reltoastidxid = InvalidOid;
00592 classForm->relhasindex = false;
00593 classForm->relkind = RELKIND_VIEW;
00594 classForm->relhasoids = false;
00595 classForm->relhaspkey = false;
00596 classForm->relfrozenxid = InvalidTransactionId;
00597 classForm->relminmxid = InvalidMultiXactId;
00598
00599 simple_heap_update(relationRelation, &classTup->t_self, classTup);
00600 CatalogUpdateIndexes(relationRelation, classTup);
00601
00602 heap_freetuple(classTup);
00603 heap_close(relationRelation, RowExclusiveLock);
00604 }
00605
00606
00607 heap_close(event_relation, NoLock);
00608
00609 return ruleId;
00610 }
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620 static void
00621 checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect)
00622 {
00623 ListCell *tllist;
00624 int i;
00625
00626 i = 0;
00627 foreach(tllist, targetList)
00628 {
00629 TargetEntry *tle = (TargetEntry *) lfirst(tllist);
00630 int32 tletypmod;
00631 Form_pg_attribute attr;
00632 char *attname;
00633
00634
00635 if (tle->resjunk)
00636 continue;
00637 i++;
00638 if (i > resultDesc->natts)
00639 ereport(ERROR,
00640 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00641 isSelect ?
00642 errmsg("SELECT rule's target list has too many entries") :
00643 errmsg("RETURNING list has too many entries")));
00644
00645 attr = resultDesc->attrs[i - 1];
00646 attname = NameStr(attr->attname);
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656 if (attr->attisdropped)
00657 ereport(ERROR,
00658 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00659 errmsg("cannot convert relation containing dropped columns to view")));
00660
00661 if (isSelect && strcmp(tle->resname, attname) != 0)
00662 ereport(ERROR,
00663 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00664 errmsg("SELECT rule's target entry %d has different column name from \"%s\"", i, attname)));
00665
00666 if (attr->atttypid != exprType((Node *) tle->expr))
00667 ereport(ERROR,
00668 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00669 isSelect ?
00670 errmsg("SELECT rule's target entry %d has different type from column \"%s\"",
00671 i, attname) :
00672 errmsg("RETURNING list's entry %d has different type from column \"%s\"",
00673 i, attname)));
00674
00675
00676
00677
00678
00679
00680
00681 tletypmod = exprTypmod((Node *) tle->expr);
00682 if (attr->atttypmod != tletypmod &&
00683 attr->atttypmod != -1 && tletypmod != -1)
00684 ereport(ERROR,
00685 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00686 isSelect ?
00687 errmsg("SELECT rule's target entry %d has different size from column \"%s\"",
00688 i, attname) :
00689 errmsg("RETURNING list's entry %d has different size from column \"%s\"",
00690 i, attname)));
00691 }
00692
00693 if (i != resultDesc->natts)
00694 ereport(ERROR,
00695 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00696 isSelect ?
00697 errmsg("SELECT rule's target list has too few entries") :
00698 errmsg("RETURNING list has too few entries")));
00699 }
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713 void
00714 setRuleCheckAsUser(Node *node, Oid userid)
00715 {
00716 (void) setRuleCheckAsUser_walker(node, &userid);
00717 }
00718
00719 static bool
00720 setRuleCheckAsUser_walker(Node *node, Oid *context)
00721 {
00722 if (node == NULL)
00723 return false;
00724 if (IsA(node, Query))
00725 {
00726 setRuleCheckAsUser_Query((Query *) node, *context);
00727 return false;
00728 }
00729 return expression_tree_walker(node, setRuleCheckAsUser_walker,
00730 (void *) context);
00731 }
00732
00733 static void
00734 setRuleCheckAsUser_Query(Query *qry, Oid userid)
00735 {
00736 ListCell *l;
00737
00738
00739 foreach(l, qry->rtable)
00740 {
00741 RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
00742
00743 if (rte->rtekind == RTE_SUBQUERY)
00744 {
00745
00746 setRuleCheckAsUser_Query(rte->subquery, userid);
00747 }
00748 else
00749 rte->checkAsUser = userid;
00750 }
00751
00752
00753 foreach(l, qry->cteList)
00754 {
00755 CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
00756
00757 setRuleCheckAsUser_Query((Query *) cte->ctequery, userid);
00758 }
00759
00760
00761 if (qry->hasSubLinks)
00762 query_tree_walker(qry, setRuleCheckAsUser_walker, (void *) &userid,
00763 QTW_IGNORE_RC_SUBQUERIES);
00764 }
00765
00766
00767
00768
00769
00770 void
00771 EnableDisableRule(Relation rel, const char *rulename,
00772 char fires_when)
00773 {
00774 Relation pg_rewrite_desc;
00775 Oid owningRel = RelationGetRelid(rel);
00776 Oid eventRelationOid;
00777 HeapTuple ruletup;
00778 bool changed = false;
00779
00780
00781
00782
00783 pg_rewrite_desc = heap_open(RewriteRelationId, RowExclusiveLock);
00784 ruletup = SearchSysCacheCopy2(RULERELNAME,
00785 ObjectIdGetDatum(owningRel),
00786 PointerGetDatum(rulename));
00787 if (!HeapTupleIsValid(ruletup))
00788 ereport(ERROR,
00789 (errcode(ERRCODE_UNDEFINED_OBJECT),
00790 errmsg("rule \"%s\" for relation \"%s\" does not exist",
00791 rulename, get_rel_name(owningRel))));
00792
00793
00794
00795
00796 eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(ruletup))->ev_class;
00797 Assert(eventRelationOid == owningRel);
00798 if (!pg_class_ownercheck(eventRelationOid, GetUserId()))
00799 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
00800 get_rel_name(eventRelationOid));
00801
00802
00803
00804
00805 if (DatumGetChar(((Form_pg_rewrite) GETSTRUCT(ruletup))->ev_enabled) !=
00806 fires_when)
00807 {
00808 ((Form_pg_rewrite) GETSTRUCT(ruletup))->ev_enabled =
00809 CharGetDatum(fires_when);
00810 simple_heap_update(pg_rewrite_desc, &ruletup->t_self, ruletup);
00811
00812
00813 CatalogUpdateIndexes(pg_rewrite_desc, ruletup);
00814
00815 changed = true;
00816 }
00817
00818 InvokeObjectPostAlterHook(RewriteRelationId,
00819 HeapTupleGetOid(ruletup), 0);
00820
00821 heap_freetuple(ruletup);
00822 heap_close(pg_rewrite_desc, RowExclusiveLock);
00823
00824
00825
00826
00827
00828
00829 if (changed)
00830 CacheInvalidateRelcache(rel);
00831 }
00832
00833
00834
00835
00836
00837 static void
00838 RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid,
00839 void *arg)
00840 {
00841 HeapTuple tuple;
00842 Form_pg_class form;
00843
00844 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
00845 if (!HeapTupleIsValid(tuple))
00846 return;
00847 form = (Form_pg_class) GETSTRUCT(tuple);
00848
00849
00850 if (form->relkind != RELKIND_RELATION && form->relkind != RELKIND_VIEW)
00851 ereport(ERROR,
00852 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00853 errmsg("\"%s\" is not a table or view", rv->relname)));
00854
00855 if (!allowSystemTableMods && IsSystemClass(form))
00856 ereport(ERROR,
00857 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00858 errmsg("permission denied: \"%s\" is a system catalog",
00859 rv->relname)));
00860
00861
00862 if (!pg_class_ownercheck(relid, GetUserId()))
00863 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, rv->relname);
00864
00865 ReleaseSysCache(tuple);
00866 }
00867
00868
00869
00870
00871 Oid
00872 RenameRewriteRule(RangeVar *relation, const char *oldName,
00873 const char *newName)
00874 {
00875 Oid relid;
00876 Relation targetrel;
00877 Relation pg_rewrite_desc;
00878 HeapTuple ruletup;
00879 Form_pg_rewrite ruleform;
00880 Oid ruleOid;
00881
00882
00883
00884
00885
00886 relid = RangeVarGetRelidExtended(relation, AccessExclusiveLock,
00887 false, false,
00888 RangeVarCallbackForRenameRule,
00889 NULL);
00890
00891
00892 targetrel = relation_open(relid, NoLock);
00893
00894
00895 pg_rewrite_desc = heap_open(RewriteRelationId, RowExclusiveLock);
00896
00897
00898 ruletup = SearchSysCacheCopy2(RULERELNAME,
00899 ObjectIdGetDatum(relid),
00900 PointerGetDatum(oldName));
00901 if (!HeapTupleIsValid(ruletup))
00902 ereport(ERROR,
00903 (errcode(ERRCODE_UNDEFINED_OBJECT),
00904 errmsg("rule \"%s\" for relation \"%s\" does not exist",
00905 oldName, RelationGetRelationName(targetrel))));
00906 ruleform = (Form_pg_rewrite) GETSTRUCT(ruletup);
00907 ruleOid = HeapTupleGetOid(ruletup);
00908
00909
00910 if (IsDefinedRewriteRule(relid, newName))
00911 ereport(ERROR,
00912 (errcode(ERRCODE_DUPLICATE_OBJECT),
00913 errmsg("rule \"%s\" for relation \"%s\" already exists",
00914 newName, RelationGetRelationName(targetrel))));
00915
00916
00917
00918
00919
00920 if (ruleform->ev_type == CMD_SELECT + '0')
00921 ereport(ERROR,
00922 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00923 errmsg("renaming an ON SELECT rule is not allowed")));
00924
00925
00926 namestrcpy(&(ruleform->rulename), newName);
00927
00928 simple_heap_update(pg_rewrite_desc, &ruletup->t_self, ruletup);
00929
00930
00931 CatalogUpdateIndexes(pg_rewrite_desc, ruletup);
00932
00933 heap_freetuple(ruletup);
00934 heap_close(pg_rewrite_desc, RowExclusiveLock);
00935
00936
00937
00938
00939
00940
00941 CacheInvalidateRelcache(targetrel);
00942
00943
00944
00945
00946 relation_close(targetrel, NoLock);
00947
00948 return ruleOid;
00949 }