LCOV - differential code coverage report
Current view: top level - src/backend/rewrite - rewriteDefine.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 85.2 % 237 202 4 28 3 9 132 12 49 13 110 10 39
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 10 10 9 1 6 3
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (120,180] days: 90.9 % 11 10 1 1 9 4
Legend: Lines: hit not hit (180,240] days: 100.0 % 1 1 1
(240..) days: 84.9 % 225 191 3 28 3 9 131 2 49 13 106
Function coverage date bins:
(240..) days: 62.5 % 16 10 9 1 6

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * rewriteDefine.c
                                  4                 :  *    routines for defining a rewrite rule
                                  5                 :  *
                                  6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  7                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :  *
                                  9                 :  *
                                 10                 :  * IDENTIFICATION
                                 11                 :  *    src/backend/rewrite/rewriteDefine.c
                                 12                 :  *
                                 13                 :  *-------------------------------------------------------------------------
                                 14                 :  */
                                 15                 : #include "postgres.h"
                                 16                 : 
                                 17                 : #include "access/heapam.h"
                                 18                 : #include "access/htup_details.h"
                                 19                 : #include "access/multixact.h"
                                 20                 : #include "access/tableam.h"
                                 21                 : #include "access/transam.h"
                                 22                 : #include "access/xact.h"
                                 23                 : #include "catalog/catalog.h"
                                 24                 : #include "catalog/dependency.h"
                                 25                 : #include "catalog/heap.h"
                                 26                 : #include "catalog/namespace.h"
                                 27                 : #include "catalog/objectaccess.h"
                                 28                 : #include "catalog/pg_inherits.h"
                                 29                 : #include "catalog/pg_rewrite.h"
                                 30                 : #include "catalog/storage.h"
                                 31                 : #include "commands/policy.h"
                                 32                 : #include "miscadmin.h"
                                 33                 : #include "nodes/nodeFuncs.h"
                                 34                 : #include "parser/parse_utilcmd.h"
                                 35                 : #include "rewrite/rewriteDefine.h"
                                 36                 : #include "rewrite/rewriteManip.h"
                                 37                 : #include "rewrite/rewriteSupport.h"
                                 38                 : #include "utils/acl.h"
                                 39                 : #include "utils/builtins.h"
                                 40                 : #include "utils/inval.h"
                                 41                 : #include "utils/lsyscache.h"
                                 42                 : #include "utils/rel.h"
                                 43                 : #include "utils/snapmgr.h"
                                 44                 : #include "utils/syscache.h"
                                 45                 : 
                                 46                 : 
                                 47                 : static void checkRuleResultList(List *targetList, TupleDesc resultDesc,
                                 48                 :                                 bool isSelect, bool requireColumnNameMatch);
                                 49                 : static bool setRuleCheckAsUser_walker(Node *node, Oid *context);
                                 50                 : static void setRuleCheckAsUser_Query(Query *qry, Oid userid);
                                 51                 : 
                                 52                 : 
                                 53                 : /*
                                 54                 :  * InsertRule -
                                 55                 :  *    takes the arguments and inserts them as a row into the system
                                 56                 :  *    relation "pg_rewrite"
                                 57                 :  */
                                 58                 : static Oid
 1986 peter_e                    59 CBC       45249 : InsertRule(const char *rulname,
                                 60                 :            int evtype,
                                 61                 :            Oid eventrel_oid,
                                 62                 :            bool evinstead,
                                 63                 :            Node *event_qual,
                                 64                 :            List *action,
                                 65                 :            bool replace)
                                 66                 : {
 7572 tgl                        67           45249 :     char       *evqual = nodeToString(event_qual);
                                 68           45249 :     char       *actiontree = nodeToString((Node *) action);
                                 69                 :     Datum       values[Natts_pg_rewrite];
  267 peter                      70 GNC       45249 :     bool        nulls[Natts_pg_rewrite] = {0};
                                 71                 :     NameData    rname;
                                 72                 :     Relation    pg_rewrite_desc;
                                 73                 :     HeapTuple   tup,
                                 74                 :                 oldtup;
                                 75                 :     Oid         rewriteObjectId;
                                 76                 :     ObjectAddress myself,
 7522 bruce                      77 ECB             :                 referenced;
 7524 tgl                        78 GIC       45249 :     bool        is_update = false;
                                 79                 : 
                                 80                 :     /*
                                 81                 :      * Set up *nulls and *values arrays
 8320 tgl                        82 ECB             :      */
 8320 tgl                        83 CBC       45249 :     namestrcpy(&rname, rulname);
 4315                            84           45249 :     values[Anum_pg_rewrite_rulename - 1] = NameGetDatum(&rname);
                                 85           45249 :     values[Anum_pg_rewrite_ev_class - 1] = ObjectIdGetDatum(eventrel_oid);
                                 86           45249 :     values[Anum_pg_rewrite_ev_type - 1] = CharGetDatum(evtype + '0');
                                 87           45249 :     values[Anum_pg_rewrite_ev_enabled - 1] = CharGetDatum(RULE_FIRES_ON_ORIGIN);
 4315 tgl                        88 GIC       45249 :     values[Anum_pg_rewrite_is_instead - 1] = BoolGetDatum(evinstead);
                                 89           45249 :     values[Anum_pg_rewrite_ev_qual - 1] = CStringGetTextDatum(evqual);
                                 90           45249 :     values[Anum_pg_rewrite_ev_action - 1] = CStringGetTextDatum(actiontree);
                                 91                 : 
 8053 bruce                      92 ECB             :     /*
                                 93                 :      * Ready to store new pg_rewrite tuple
                                 94                 :      */
 1539 andres                     95 GIC       45249 :     pg_rewrite_desc = table_open(RewriteRelationId, RowExclusiveLock);
                                 96                 : 
 7524 tgl                        97 ECB             :     /*
                                 98                 :      * Check to see if we are replacing an existing tuple
                                 99                 :      */
 4802 rhaas                     100 GIC       45249 :     oldtup = SearchSysCache2(RULERELNAME,
 4802 rhaas                     101 ECB             :                              ObjectIdGetDatum(eventrel_oid),
                                102                 :                              PointerGetDatum(rulname));
 7524 tgl                       103                 : 
 7524 tgl                       104 GIC       45249 :     if (HeapTupleIsValid(oldtup))
 7524 tgl                       105 ECB             :     {
  267 peter                     106 GNC         121 :         bool        replaces[Natts_pg_rewrite] = {0};
                                107                 : 
 5185 peter_e                   108 GBC         121 :         if (!replace)
 7198 tgl                       109 UIC           0 :             ereport(ERROR,
                                110                 :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
                                111                 :                      errmsg("rule \"%s\" for relation \"%s\" already exists",
                                112                 :                             rulname, get_rel_name(eventrel_oid))));
                                113                 : 
                                114                 :         /*
                                115                 :          * When replacing, we don't need to replace every attribute
 7524 tgl                       116 ECB             :          */
 5271 tgl                       117 CBC         121 :         replaces[Anum_pg_rewrite_ev_type - 1] = true;
                                118             121 :         replaces[Anum_pg_rewrite_is_instead - 1] = true;
 5271 tgl                       119 GIC         121 :         replaces[Anum_pg_rewrite_ev_qual - 1] = true;
 5271 tgl                       120 CBC         121 :         replaces[Anum_pg_rewrite_ev_action - 1] = true;
                                121                 : 
 5271 tgl                       122 GIC         121 :         tup = heap_modify_tuple(oldtup, RelationGetDescr(pg_rewrite_desc),
 5050 bruce                     123 ECB             :                                 values, nulls, replaces);
                                124                 : 
 2259 alvherre                  125 CBC         121 :         CatalogTupleUpdate(pg_rewrite_desc, &tup->t_self, tup);
                                126                 : 
 7524 tgl                       127             121 :         ReleaseSysCache(oldtup);
 7524 tgl                       128 ECB             : 
 1601 andres                    129 GIC         121 :         rewriteObjectId = ((Form_pg_rewrite) GETSTRUCT(tup))->oid;
 7524 tgl                       130             121 :         is_update = true;
                                131                 :     }
 7524 tgl                       132 ECB             :     else
                                133                 :     {
 1601 andres                    134 GIC       45128 :         rewriteObjectId = GetNewOidWithIndex(pg_rewrite_desc,
 1601 andres                    135 ECB             :                                              RewriteOidIndexId,
                                136                 :                                              Anum_pg_rewrite_oid);
 1601 andres                    137 CBC       45128 :         values[Anum_pg_rewrite_oid - 1] = ObjectIdGetDatum(rewriteObjectId);
                                138                 : 
 5271 tgl                       139           45128 :         tup = heap_form_tuple(pg_rewrite_desc->rd_att, values, nulls);
                                140                 : 
 1601 andres                    141 GIC       45128 :         CatalogTupleInsert(pg_rewrite_desc, tup);
                                142                 :     }
 8320 tgl                       143 ECB             : 
                                144                 : 
 8320 tgl                       145 GIC       45249 :     heap_freetuple(tup);
 8571 tgl                       146 ECB             : 
 7524                           147                 :     /* If replacing, get rid of old dependencies and make new ones */
 7524 tgl                       148 GIC       45249 :     if (is_update)
 4443                           149             121 :         deleteDependencyRecordsFor(RewriteRelationId, rewriteObjectId, false);
                                150                 : 
                                151                 :     /*
                                152                 :      * Install dependency on rule's relation to ensure it will go away on
                                153                 :      * relation deletion.  If the rule is ON SELECT, make the dependency
                                154                 :      * implicit --- this prevents deleting a view's SELECT rule.  Other kinds
 6385 bruce                     155 ECB             :      * of rules can be AUTO.
 7576 tgl                       156                 :      */
 6569 tgl                       157 CBC       45249 :     myself.classId = RewriteRelationId;
 7576 tgl                       158 GIC       45249 :     myself.objectId = rewriteObjectId;
 7576 tgl                       159 CBC       45249 :     myself.objectSubId = 0;
 7576 tgl                       160 ECB             : 
 6569 tgl                       161 CBC       45249 :     referenced.classId = RelationRelationId;
 7576 tgl                       162 GIC       45249 :     referenced.objectId = eventrel_oid;
 7576 tgl                       163 CBC       45249 :     referenced.objectSubId = 0;
                                164                 : 
 7576 tgl                       165 GIC       45249 :     recordDependencyOn(&myself, &referenced,
                                166                 :                        (evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
                                167                 : 
                                168                 :     /*
 7572 tgl                       169 ECB             :      * Also install dependencies on objects referenced in action and qual.
                                170                 :      */
 7572 tgl                       171 GIC       45249 :     recordDependencyOnExpr(&myself, (Node *) action, NIL,
 7572 tgl                       172 ECB             :                            DEPENDENCY_NORMAL);
                                173                 : 
 7572 tgl                       174 GIC       45249 :     if (event_qual != NULL)
 7572 tgl                       175 ECB             :     {
                                176                 :         /* Find query containing OLD/NEW rtable entries */
 2190 tgl                       177 CBC         390 :         Query      *qry = linitial_node(Query, action);
 7572 tgl                       178 ECB             : 
 7572 tgl                       179 GIC         390 :         qry = getInsertSelectQuery(qry, NULL);
                                180             390 :         recordDependencyOnExpr(&myself, event_qual, qry->rtable,
                                181                 :                                DEPENDENCY_NORMAL);
                                182                 :     }
 7572 tgl                       183 ECB             : 
                                184                 :     /* Post creation hook for new rule */
 3686 rhaas                     185 CBC       45249 :     InvokeObjectPostCreateHook(RewriteRelationId, rewriteObjectId, 0);
                                186                 : 
 1539 andres                    187           45249 :     table_close(pg_rewrite_desc, RowExclusiveLock);
                                188                 : 
 8320 tgl                       189 GIC       45249 :     return rewriteObjectId;
                                190                 : }
                                191                 : 
                                192                 : /*
                                193                 :  * DefineRule
                                194                 :  *      Execute a CREATE RULE command.
 5871 tgl                       195 ECB             :  */
                                196                 : ObjectAddress
 5871 tgl                       197 GIC        1031 : DefineRule(RuleStmt *stmt, const char *queryString)
                                198                 : {
                                199                 :     List       *actions;
                                200                 :     Node       *whereClause;
                                201                 :     Oid         relId;
 5871 tgl                       202 ECB             : 
                                203                 :     /* Parse analysis. */
 5769 tgl                       204 GIC        1031 :     transformRuleStmt(stmt, queryString, &actions, &whereClause);
                                205                 : 
                                206                 :     /*
                                207                 :      * Find and lock the relation.  Lock level should match
 4293 rhaas                     208 ECB             :      * DefineQueryRewrite.
                                209                 :      */
 4148 rhaas                     210 GIC        1022 :     relId = RangeVarGetRelid(stmt->relation, AccessExclusiveLock, false);
 5704 tgl                       211 ECB             : 
                                212                 :     /* ... and execute */
 3753 rhaas                     213 GIC        2031 :     return DefineQueryRewrite(stmt->rulename,
                                214                 :                               relId,
 3753 rhaas                     215 ECB             :                               whereClause,
                                216                 :                               stmt->event,
 3753 rhaas                     217 GIC        1022 :                               stmt->instead,
                                218            1022 :                               stmt->replace,
                                219                 :                               actions);
                                220                 : }
                                221                 : 
                                222                 : 
                                223                 : /*
                                224                 :  * DefineQueryRewrite
                                225                 :  *      Create a rule
                                226                 :  *
                                227                 :  * This is essentially the same as DefineRule() except that the rule's
                                228                 :  * action and qual have already been passed through parse analysis.
 5871 tgl                       229 ECB             :  */
                                230                 : ObjectAddress
 1986 peter_e                   231 GIC       45262 : DefineQueryRewrite(const char *rulename,
                                232                 :                    Oid event_relid,
                                233                 :                    Node *event_qual,
                                234                 :                    CmdType event_type,
                                235                 :                    bool is_instead,
                                236                 :                    bool replace,
                                237                 :                    List *action)
                                238                 : {
                                239                 :     Relation    event_relation;
 6892 neilc                     240 ECB             :     ListCell   *l;
                                241                 :     Query      *query;
 3602 bruce                     242 GIC       45262 :     Oid         ruleId = InvalidOid;
                                243                 :     ObjectAddress address;
                                244                 : 
                                245                 :     /*
                                246                 :      * If we are installing an ON SELECT rule, we had better grab
                                247                 :      * AccessExclusiveLock to ensure no SELECTs are currently running on the
                                248                 :      * event relation. For other types of rules, it would be sufficient to
                                249                 :      * grab ShareRowExclusiveLock to lock out insert/update/delete actions and
                                250                 :      * to ensure that we lock out current CREATE RULE statements; but because
                                251                 :      * of race conditions in access to catalog entries, we can't do that yet.
 4293 rhaas                     252 ECB             :      *
                                253                 :      * Note that this lock level should match the one used in DefineRule.
                                254                 :      */
 1539 andres                    255 GIC       45262 :     event_relation = table_open(event_relid, AccessExclusiveLock);
                                256                 : 
                                257                 :     /*
                                258                 :      * Verify relation is of a type that rules can sensibly be applied to.
 3565 noah                      259 ECB             :      * Internal callers can target materialized views, but transformRuleStmt()
                                260                 :      * blocks them for users.  Don't mention them in the error message.
 5079 tgl                       261                 :      */
 5079 tgl                       262 CBC       45262 :     if (event_relation->rd_rel->relkind != RELKIND_RELATION &&
 3689 kgrittn                   263 GBC       44978 :         event_relation->rd_rel->relkind != RELKIND_MATVIEW &&
 2314 rhaas                     264 GIC       44766 :         event_relation->rd_rel->relkind != RELKIND_VIEW &&
                                265               6 :         event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 5079 tgl                       266 UIC           0 :         ereport(ERROR,
                                267                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                268                 :                  errmsg("relation \"%s\" cannot have rules",
  640 peter                     269 ECB             :                         RelationGetRelationName(event_relation)),
                                270                 :                  errdetail_relkind_not_supported(event_relation->rd_rel->relkind)));
                                271                 : 
 5079 tgl                       272 GIC       45262 :     if (!allowSystemTableMods && IsSystemRelation(event_relation))
                                273               1 :         ereport(ERROR,
                                274                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                275                 :                  errmsg("permission denied: \"%s\" is a system catalog",
                                276                 :                         RelationGetRelationName(event_relation))));
                                277                 : 
 7689 tgl                       278 ECB             :     /*
 7689 tgl                       279 EUB             :      * Check user has permission to apply rules to this relation.
                                280                 :      */
  147 peter                     281 GNC       45261 :     if (!object_ownercheck(RelationRelationId, event_relid, GetUserId()))
 1954 peter_e                   282 UIC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(event_relation->rd_rel->relkind),
 7191 tgl                       283               0 :                        RelationGetRelationName(event_relation));
                                284                 : 
 8955 bruce                     285 ECB             :     /*
                                286                 :      * No rule actions that modify OLD or NEW
                                287                 :      */
 8318 tgl                       288 CBC       90545 :     foreach(l, action)
 8986 bruce                     289 ECB             :     {
 2190 tgl                       290 GIC       45284 :         query = lfirst_node(Query, l);
 8160 tgl                       291 CBC       45284 :         if (query->resultRelation == 0)
                                292           44916 :             continue;
 8160 tgl                       293 ECB             :         /* Don't be fooled by INSERT/SELECT */
 8160 tgl                       294 GBC         368 :         if (query != getInsertSelectQuery(query, NULL))
 8160 tgl                       295 GIC          26 :             continue;
 8244                           296             342 :         if (query->resultRelation == PRS2_OLD_VARNO)
 7198 tgl                       297 UIC           0 :             ereport(ERROR,
 7198 tgl                       298 ECB             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 7198 tgl                       299 EUB             :                      errmsg("rule actions on OLD are not implemented"),
                                300                 :                      errhint("Use views or triggers instead.")));
 8244 tgl                       301 GIC         342 :         if (query->resultRelation == PRS2_NEW_VARNO)
 7198 tgl                       302 UIC           0 :             ereport(ERROR,
                                303                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                304                 :                      errmsg("rule actions on NEW are not implemented"),
 7198 tgl                       305 ECB             :                      errhint("Use triggers instead.")));
                                306                 :     }
                                307                 : 
 8986 bruce                     308 GIC       45261 :     if (event_type == CMD_SELECT)
                                309                 :     {
                                310                 :         /*
                                311                 :          * Rules ON SELECT are restricted to view definitions
 6063 tgl                       312 ECB             :          *
                                313                 :          * So this had better be a view, ...
  128                           314                 :          */
  128 tgl                       315 GNC       44249 :         if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
                                316             221 :             event_relation->rd_rel->relkind != RELKIND_MATVIEW)
                                317               9 :             ereport(ERROR,
                                318                 :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                319                 :                      errmsg("relation \"%s\" cannot have ON SELECT rules",
                                320                 :                             RelationGetRelationName(event_relation)),
                                321                 :                      errdetail_relkind_not_supported(event_relation->rd_rel->relkind)));
                                322                 : 
                                323                 :         /*
                                324                 :          * ... there cannot be INSTEAD NOTHING, ...
                                325                 :          */
  235                           326           44240 :         if (action == NIL)
 7198 tgl                       327 UIC           0 :             ereport(ERROR,
                                328                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                329                 :                      errmsg("INSTEAD NOTHING rules on SELECT are not implemented"),
                                330                 :                      errhint("Use views instead.")));
                                331                 : 
                                332                 :         /*
                                333                 :          * ... there cannot be multiple actions, ...
 8955 bruce                     334 ECB             :          */
 6888 neilc                     335 GBC       44240 :         if (list_length(action) > 1)
 7198 tgl                       336 UIC           0 :             ereport(ERROR,
                                337                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                338                 :                      errmsg("multiple actions for rules on SELECT are not implemented")));
                                339                 : 
                                340                 :         /*
                                341                 :          * ... the one action must be a SELECT, ...
                                342                 :          */
 2190 tgl                       343 CBC       44240 :         query = linitial_node(Query, action);
 6084 tgl                       344 GBC       44240 :         if (!is_instead ||
 2276 tgl                       345 GIC       44240 :             query->commandType != CMD_SELECT)
 7198 tgl                       346 UIC           0 :             ereport(ERROR,
                                347                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                348                 :                      errmsg("rules on SELECT must have action INSTEAD SELECT")));
                                349                 : 
                                350                 :         /*
 4426 tgl                       351 ECB             :          * ... it cannot contain data-modifying WITH ...
                                352                 :          */
 4426 tgl                       353 CBC       44240 :         if (query->hasModifyingCTE)
 4426 tgl                       354 UBC           0 :             ereport(ERROR,
                                355                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                356                 :                      errmsg("rules on SELECT must not contain data-modifying statements in WITH")));
                                357                 : 
                                358                 :         /*
                                359                 :          * ... there can be no rule qual, ...
                                360                 :          */
 8955 bruce                     361 CBC       44240 :         if (event_qual != NULL)
 7198 tgl                       362 UBC           0 :             ereport(ERROR,
                                363                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                364                 :                      errmsg("event qualifications are not implemented for rules on SELECT")));
                                365                 : 
                                366                 :         /*
                                367                 :          * ... the targetlist of the SELECT action must exactly match the
                                368                 :          * event relation, ...
 8955 bruce                     369 ECB             :          */
 6063 tgl                       370 GBC       44240 :         checkRuleResultList(query->targetList,
                                371                 :                             RelationGetDescr(event_relation),
                                372                 :                             true,
 3443 kgrittn                   373 GIC       44240 :                             event_relation->rd_rel->relkind !=
                                374                 :                             RELKIND_MATVIEW);
                                375                 : 
                                376                 :         /*
                                377                 :          * ... there must not be another ON SELECT rule already ...
 8955 bruce                     378 ECB             :          */
 7524 tgl                       379 GIC       44240 :         if (!replace && event_relation->rd_rules != NULL)
                                380                 :         {
 6031 bruce                     381 ECB             :             int         i;
                                382                 : 
 8720 bruce                     383 UIC           0 :             for (i = 0; i < event_relation->rd_rules->numLocks; i++)
                                384                 :             {
                                385                 :                 RewriteRule *rule;
                                386                 : 
 8955 bruce                     387 LBC           0 :                 rule = event_relation->rd_rules->rules[i];
 8955 bruce                     388 UIC           0 :                 if (rule->event == CMD_SELECT)
 7198 tgl                       389               0 :                     ereport(ERROR,
                                390                 :                             (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 2118 tgl                       391 EUB             :                              errmsg("\"%s\" is already a view",
                                392                 :                                     RelationGetRelationName(event_relation))));
                                393                 :             }
                                394                 :         }
 8955 bruce                     395                 : 
 8951                           396                 :         /*
 7660 tgl                       397                 :          * ... and finally the rule must be named _RETURN.
                                398                 :          */
 5871 tgl                       399 GIC       44240 :         if (strcmp(rulename, ViewSelectRuleName) != 0)
                                400                 :         {
                                401                 :             /*
                                402                 :              * In versions before 7.3, the expected name was _RETviewname. For
                                403                 :              * backwards compatibility with old pg_dump output, accept that
                                404                 :              * and silently change it to _RETURN.  Since this is just a quick
                                405                 :              * backwards-compatibility hack, limit the number of characters
                                406                 :              * checked to a few less than NAMEDATALEN; this saves having to
 6385 bruce                     407 ECB             :              * worry about where a multibyte character might have gotten
                                408                 :              * truncated.
                                409                 :              */
 5871 tgl                       410 UIC           0 :             if (strncmp(rulename, "_RET", 4) != 0 ||
 5704                           411               0 :                 strncmp(rulename + 4, RelationGetRelationName(event_relation),
                                412                 :                         NAMEDATALEN - 4 - 4) != 0)
 7198                           413               0 :                 ereport(ERROR,
                                414                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                415                 :                          errmsg("view rule for \"%s\" must be named \"%s\"",
                                416                 :                                 RelationGetRelationName(event_relation),
                                417                 :                                 ViewSelectRuleName)));
 5871 tgl                       418 UBC           0 :             rulename = pstrdup(ViewSelectRuleName);
 8951 bruce                     419 EUB             :         }
                                420                 :     }
 6063 tgl                       421 ECB             :     else
                                422                 :     {
                                423                 :         /*
                                424                 :          * For non-SELECT rules, a RETURNING list can appear in at most one of
                                425                 :          * the actions ... and there can't be any RETURNING list at all in a
                                426                 :          * conditional or non-INSTEAD rule.  (Actually, there can be at most
                                427                 :          * one RETURNING list across all rules on the same event, but it seems
                                428                 :          * best to enforce that at rule expansion time.)  If there is a
                                429                 :          * RETURNING list, it must match the event relation.
                                430                 :          */
 6031 bruce                     431 GIC        1012 :         bool        haveReturning = false;
                                432                 : 
 6063 tgl                       433            2044 :         foreach(l, action)
 6063 tgl                       434 ECB             :         {
 2190 tgl                       435 GIC        1035 :             query = lfirst_node(Query, l);
                                436                 : 
 6063                           437            1035 :             if (!query->returningList)
                                438             979 :                 continue;
                                439              56 :             if (haveReturning)
 6063 tgl                       440 UIC           0 :                 ereport(ERROR,
 6063 tgl                       441 ECB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                442                 :                          errmsg("cannot have multiple RETURNING lists in a rule")));
 6063 tgl                       443 CBC          56 :             haveReturning = true;
                                444              56 :             if (event_qual != NULL)
 6063 tgl                       445 UIC           0 :                 ereport(ERROR,
 6063 tgl                       446 ECB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                447                 :                          errmsg("RETURNING lists are not supported in conditional rules")));
 6063 tgl                       448 GIC          56 :             if (!is_instead)
 6063 tgl                       449 UIC           0 :                 ereport(ERROR,
                                450                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                451                 :                          errmsg("RETURNING lists are not supported in non-INSTEAD rules")));
 6063 tgl                       452 GIC          56 :             checkRuleResultList(query->returningList,
 6063 tgl                       453 ECB             :                                 RelationGetDescr(event_relation),
 3443 kgrittn                   454                 :                                 false, false);
 6063 tgl                       455                 :         }
  174                           456                 : 
                                457                 :         /*
                                458                 :          * And finally, if it's not an ON SELECT rule then it must *not* be
                                459                 :          * named _RETURN.  This prevents accidentally or maliciously replacing
                                460                 :          * a view's ON SELECT rule with some other kind of rule.
                                461                 :          */
  174 tgl                       462 GIC        1009 :         if (strcmp(rulename, ViewSelectRuleName) == 0)
  174 tgl                       463 LBC           0 :             ereport(ERROR,
  174 tgl                       464 ECB             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                465                 :                      errmsg("non-view rule for \"%s\" must not be named \"%s\"",
                                466                 :                             RelationGetRelationName(event_relation),
                                467                 :                             ViewSelectRuleName)));
                                468                 :     }
                                469                 : 
                                470                 :     /*
                                471                 :      * This rule is allowed - prepare to install it.
                                472                 :      */
                                473                 : 
                                474                 :     /* discard rule if it's null action and not INSTEAD; it's a no-op */
 8244 tgl                       475 GIC       45249 :     if (action != NIL || is_instead)
                                476                 :     {
 3753 rhaas                     477           45249 :         ruleId = InsertRule(rulename,
                                478                 :                             event_type,
                                479                 :                             event_relid,
                                480                 :                             is_instead,
                                481                 :                             event_qual,
                                482                 :                             action,
                                483                 :                             replace);
 9345 bruce                     484 ECB             : 
 8318 tgl                       485 EUB             :         /*
                                486                 :          * Set pg_class 'relhasrules' field true for event relation.
                                487                 :          *
                                488                 :          * Important side effect: an SI notice is broadcast to force all
                                489                 :          * backends (including me!) to update relcache entries with the new
                                490                 :          * rule.
                                491                 :          */
 3689 tgl                       492 CBC       45249 :         SetRelationRuleStatus(event_relid, true);
 9345 bruce                     493 EUB             :     }
                                494                 : 
 2959 alvherre                  495 GIC       45249 :     ObjectAddressSet(address, RewriteRelationId, ruleId);
 2959 alvherre                  496 ECB             : 
                                497                 :     /* Close rel, but keep lock till commit... */
 1539 andres                    498 CBC       45249 :     table_close(event_relation, NoLock);
                                499                 : 
 2959 alvherre                  500           45249 :     return address;
                                501                 : }
                                502                 : 
                                503                 : /*
 6063 tgl                       504 ECB             :  * checkRuleResultList
                                505                 :  *      Verify that targetList produces output compatible with a tupledesc
                                506                 :  *
                                507                 :  * The targetList might be either a SELECT targetlist, or a RETURNING list;
 3443 kgrittn                   508                 :  * isSelect tells which.  This is used for choosing error messages.
                                509                 :  *
                                510                 :  * A SELECT targetlist may optionally require that column names match.
                                511                 :  */
                                512                 : static void
 3443 kgrittn                   513 CBC       44296 : checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect,
                                514                 :                     bool requireColumnNameMatch)
 6063 tgl                       515 ECB             : {
                                516                 :     ListCell   *tllist;
                                517                 :     int         i;
                                518                 : 
                                519                 :     /* Only a SELECT may require a column name match. */
 3443 kgrittn                   520 GIC       44296 :     Assert(isSelect || !requireColumnNameMatch);
 3443 kgrittn                   521 ECB             : 
 6063 tgl                       522 CBC       44296 :     i = 0;
 6063 tgl                       523 GIC      485640 :     foreach(tllist, targetList)
 6063 tgl                       524 ECB             :     {
 6063 tgl                       525 GIC      441347 :         TargetEntry *tle = (TargetEntry *) lfirst(tllist);
                                526                 :         Oid         tletypid;
                                527                 :         int32       tletypmod;
                                528                 :         Form_pg_attribute attr;
                                529                 :         char       *attname;
                                530                 : 
 6063 tgl                       531 ECB             :         /* resjunk entries may be ignored */
 6063 tgl                       532 GIC      441347 :         if (tle->resjunk)
                                533            1852 :             continue;
                                534          439495 :         i++;
 6063 tgl                       535 CBC      439495 :         if (i > resultDesc->natts)
 6063 tgl                       536 GIC           3 :             ereport(ERROR,
                                537                 :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                538                 :                      isSelect ?
 2118 tgl                       539 ECB             :                      errmsg("SELECT rule's target list has too many entries") :
                                540                 :                      errmsg("RETURNING list has too many entries")));
                                541                 : 
 2058 andres                    542 GIC      439492 :         attr = TupleDescAttr(resultDesc, i - 1);
 6063 tgl                       543          439492 :         attname = NameStr(attr->attname);
 6063 tgl                       544 ECB             : 
                                545                 :         /*
                                546                 :          * Disallow dropped columns in the relation.  This is not really
                                547                 :          * expected to happen when creating an ON SELECT rule.  It'd be
 2596                           548                 :          * possible if someone tried to convert a relation with dropped
 2596 tgl                       549 EUB             :          * columns to a view, but the only case we care about supporting
                                550                 :          * table-to-view conversion for is pg_dump, and pg_dump won't do that.
                                551                 :          *
                                552                 :          * Unfortunately, the situation is also possible when adding a rule
                                553                 :          * with RETURNING to a regular table, and rejecting that case is
 2596 tgl                       554 ECB             :          * altogether more annoying.  In principle we could support it by
                                555                 :          * modifying the targetlist to include dummy NULL columns
                                556                 :          * corresponding to the dropped columns in the tupdesc.  However,
                                557                 :          * places like ruleutils.c would have to be fixed to not process such
                                558                 :          * entries, and that would take an uncertain and possibly rather large
                                559                 :          * amount of work.  (Note we could not dodge that by marking the dummy
                                560                 :          * columns resjunk, since it's precisely the non-resjunk tlist columns
                                561                 :          * that are expected to correspond to table columns.)
 6063 tgl                       562 EUB             :          */
 6063 tgl                       563 GBC      439492 :         if (attr->attisdropped)
 6063 tgl                       564 UIC           0 :             ereport(ERROR,
                                565                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                566                 :                      isSelect ?
                                567                 :                      errmsg("cannot convert relation containing dropped columns to view") :
 2596 tgl                       568 ECB             :                      errmsg("cannot create a RETURNING list for a relation containing dropped columns")));
                                569                 : 
                                570                 :         /* Check name match if required; no need for two error texts here */
 3443 kgrittn                   571 CBC      439492 :         if (requireColumnNameMatch && strcmp(tle->resname, attname) != 0)
 6063 tgl                       572 LBC           0 :             ereport(ERROR,
                                573                 :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 3203 tgl                       574 ECB             :                      errmsg("SELECT rule's target entry %d has different column name from column \"%s\"",
                                575                 :                             i, attname),
                                576                 :                      errdetail("SELECT target entry is named \"%s\".",
                                577                 :                                tle->resname)));
                                578                 : 
                                579                 :         /* Check type match. */
 3203 tgl                       580 CBC      439492 :         tletypid = exprType((Node *) tle->expr);
 3203 tgl                       581 GIC      439492 :         if (attr->atttypid != tletypid)
 6063 tgl                       582 UIC           0 :             ereport(ERROR,
                                583                 :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                584                 :                      isSelect ?
                                585                 :                      errmsg("SELECT rule's target entry %d has different type from column \"%s\"",
                                586                 :                             i, attname) :
 6063 tgl                       587 ECB             :                      errmsg("RETURNING list's entry %d has different type from column \"%s\"",
 3203                           588                 :                             i, attname),
                                589                 :                      isSelect ?
                                590                 :                      errdetail("SELECT target entry has type %s, but column has type %s.",
                                591                 :                                format_type_be(tletypid),
                                592                 :                                format_type_be(attr->atttypid)) :
                                593                 :                      errdetail("RETURNING list entry has type %s, but column has type %s.",
                                594                 :                                format_type_be(tletypid),
                                595                 :                                format_type_be(attr->atttypid))));
 6063                           596                 : 
                                597                 :         /*
                                598                 :          * Allow typmods to be different only if one of them is -1, ie,
                                599                 :          * "unspecified".  This is necessary for cases like "numeric", where
                                600                 :          * the table will have a filled-in default length but the select
                                601                 :          * rule's expression will probably have typmod = -1.
                                602                 :          */
 6063 tgl                       603 CBC      439492 :         tletypmod = exprTypmod((Node *) tle->expr);
 6063 tgl                       604 GBC      439492 :         if (attr->atttypmod != tletypmod &&
 6063 tgl                       605 LBC           0 :             attr->atttypmod != -1 && tletypmod != -1)
 6063 tgl                       606 UIC           0 :             ereport(ERROR,
                                607                 :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 6063 tgl                       608 ECB             :                      isSelect ?
                                609                 :                      errmsg("SELECT rule's target entry %d has different size from column \"%s\"",
                                610                 :                             i, attname) :
 6063 tgl                       611 EUB             :                      errmsg("RETURNING list's entry %d has different size from column \"%s\"",
                                612                 :                             i, attname),
                                613                 :                      isSelect ?
                                614                 :                      errdetail("SELECT target entry has type %s, but column has type %s.",
                                615                 :                                format_type_with_typemod(tletypid, tletypmod),
 3203 tgl                       616 ECB             :                                format_type_with_typemod(attr->atttypid,
                                617                 :                                                         attr->atttypmod)) :
                                618                 :                      errdetail("RETURNING list entry has type %s, but column has type %s.",
                                619                 :                                format_type_with_typemod(tletypid, tletypmod),
                                620                 :                                format_type_with_typemod(attr->atttypid,
                                621                 :                                                         attr->atttypmod))));
                                622                 :     }
 6063                           623                 : 
 6063 tgl                       624 GBC       44293 :     if (i != resultDesc->natts)
 6063 tgl                       625 UIC           0 :         ereport(ERROR,
 6063 tgl                       626 ECB             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                627                 :                  isSelect ?
                                628                 :                  errmsg("SELECT rule's target list has too few entries") :
                                629                 :                  errmsg("RETURNING list has too few entries")));
 6063 tgl                       630 GIC       44293 : }
                                631                 : 
                                632                 : /*
 6060 tgl                       633 ECB             :  * setRuleCheckAsUser
                                634                 :  *      Recursively scan a query or expression tree and set the checkAsUser
                                635                 :  *      field to the given userid in all RTEPermissionInfos of the query.
                                636                 :  */
                                637                 : void
 6060 tgl                       638 GIC      121894 : setRuleCheckAsUser(Node *node, Oid userid)
                                639                 : {
                                640          121894 :     (void) setRuleCheckAsUser_walker(node, &userid);
 6060 tgl                       641 CBC      121894 : }
                                642                 : 
                                643                 : static bool
 6060 tgl                       644 GIC      783266 : setRuleCheckAsUser_walker(Node *node, Oid *context)
                                645                 : {
                                646          783266 :     if (node == NULL)
 6060 tgl                       647 CBC      156528 :         return false;
 6060 tgl                       648 GIC      626738 :     if (IsA(node, Query))
                                649                 :     {
 6060 tgl                       650 CBC       68992 :         setRuleCheckAsUser_Query((Query *) node, *context);
 6060 tgl                       651 GIC       68992 :         return false;
                                652                 :     }
 6060 tgl                       653 CBC      557746 :     return expression_tree_walker(node, setRuleCheckAsUser_walker,
                                654                 :                                   (void *) context);
                                655                 : }
 6060 tgl                       656 ECB             : 
 8227                           657                 : static void
 6494 tgl                       658 GIC      113179 : setRuleCheckAsUser_Query(Query *qry, Oid userid)
                                659                 : {
                                660                 :     ListCell   *l;
 8227 tgl                       661 ECB             : 
                                662                 :     /* Set in all RTEPermissionInfos for this query. */
  124 alvherre                  663 GNC      298073 :     foreach(l, qry->rteperminfos)
                                664                 :     {
                                665          184894 :         RTEPermissionInfo *perminfo = lfirst_node(RTEPermissionInfo, l);
                                666                 : 
                                667          184894 :         perminfo->checkAsUser = userid;
                                668                 :     }
                                669                 : 
                                670                 :     /* Now recurse to any subquery RTEs */
 8227 tgl                       671 GIC      420757 :     foreach(l, qry->rtable)
                                672                 :     {
 8227 tgl                       673 CBC      307578 :         RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
 8227 tgl                       674 ECB             : 
 7637 tgl                       675 GIC      307578 :         if (rte->rtekind == RTE_SUBQUERY)
 6900                           676           44085 :             setRuleCheckAsUser_Query(rte->subquery, userid);
                                677                 :     }
 8227 tgl                       678 ECB             : 
 5300                           679                 :     /* Recurse into subquery-in-WITH */
 5300 tgl                       680 GIC      113281 :     foreach(l, qry->cteList)
                                681                 :     {
                                682             102 :         CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
                                683                 : 
 2264 tgl                       684 CBC         102 :         setRuleCheckAsUser_Query(castNode(Query, cte->ctequery), userid);
                                685                 :     }
 5300 tgl                       686 ECB             : 
                                687                 :     /* If there are sublinks, search for them and process their RTEs */
 8227 tgl                       688 CBC      113179 :     if (qry->hasSubLinks)
 8221 tgl                       689 GIC        6149 :         query_tree_walker(qry, setRuleCheckAsUser_walker, (void *) &userid,
 5300 tgl                       690 ECB             :                           QTW_IGNORE_RC_SUBQUERIES);
 8227 tgl                       691 CBC      113179 : }
                                692                 : 
                                693                 : 
                                694                 : /*
                                695                 :  * Change the firing semantics of an existing rule.
                                696                 :  */
                                697                 : void
 5865 JanWieck                  698               9 : EnableDisableRule(Relation rel, const char *rulename,
                                699                 :                   char fires_when)
 5865 JanWieck                  700 ECB             : {
                                701                 :     Relation    pg_rewrite_desc;
 5865 JanWieck                  702 GIC           9 :     Oid         owningRel = RelationGetRelid(rel);
                                703                 :     Oid         eventRelationOid;
                                704                 :     HeapTuple   ruletup;
 1601 andres                    705 ECB             :     Form_pg_rewrite ruleform;
 5865 JanWieck                  706 GIC           9 :     bool        changed = false;
 5865 JanWieck                  707 ECB             : 
                                708                 :     /*
                                709                 :      * Find the rule tuple to change.
                                710                 :      */
 1539 andres                    711 GIC           9 :     pg_rewrite_desc = table_open(RewriteRelationId, RowExclusiveLock);
 4802 rhaas                     712               9 :     ruletup = SearchSysCacheCopy2(RULERELNAME,
                                713                 :                                   ObjectIdGetDatum(owningRel),
                                714                 :                                   PointerGetDatum(rulename));
 5865 JanWieck                  715               9 :     if (!HeapTupleIsValid(ruletup))
 5865 JanWieck                  716 UIC           0 :         ereport(ERROR,
                                717                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                                718                 :                  errmsg("rule \"%s\" for relation \"%s\" does not exist",
                                719                 :                         rulename, get_rel_name(owningRel))));
                                720                 : 
 1601 andres                    721 GIC           9 :     ruleform = (Form_pg_rewrite) GETSTRUCT(ruletup);
                                722                 : 
                                723                 :     /*
                                724                 :      * Verify that the user has appropriate permissions.
                                725                 :      */
                                726               9 :     eventRelationOid = ruleform->ev_class;
 5865 JanWieck                  727               9 :     Assert(eventRelationOid == owningRel);
  147 peter                     728 GNC           9 :     if (!object_ownercheck(RelationRelationId, eventRelationOid, GetUserId()))
 1954 peter_e                   729 UIC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(eventRelationOid)),
 5624 bruce                     730               0 :                        get_rel_name(eventRelationOid));
                                731                 : 
                                732                 :     /*
                                733                 :      * Change ev_enabled if it is different from the desired new state.
                                734                 :      */
 1601 andres                    735 GIC           9 :     if (DatumGetChar(ruleform->ev_enabled) !=
                                736                 :         fires_when)
                                737                 :     {
                                738               9 :         ruleform->ev_enabled = CharGetDatum(fires_when);
 2259 alvherre                  739               9 :         CatalogTupleUpdate(pg_rewrite_desc, &ruletup->t_self, ruletup);
                                740                 : 
 5865 JanWieck                  741               9 :         changed = true;
                                742                 :     }
                                743                 : 
 1601 andres                    744               9 :     InvokeObjectPostAlterHook(RewriteRelationId, ruleform->oid, 0);
                                745                 : 
 5865 JanWieck                  746               9 :     heap_freetuple(ruletup);
 1539 andres                    747               9 :     table_close(pg_rewrite_desc, RowExclusiveLock);
                                748                 : 
                                749                 :     /*
                                750                 :      * If we changed anything, broadcast a SI inval message to force each
                                751                 :      * backend (including our own!) to rebuild relation's relcache entry.
                                752                 :      * Otherwise they will fail to apply the change promptly.
                                753                 :      */
 5865 JanWieck                  754               9 :     if (changed)
                                755               9 :         CacheInvalidateRelcache(rel);
                                756               9 : }
                                757                 : 
                                758                 : 
                                759                 : /*
                                760                 :  * Perform permissions and integrity checks before acquiring a relation lock.
                                761                 :  */
                                762                 : static void
 3712 tgl                       763              17 : RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid,
                                764                 :                               void *arg)
                                765                 : {
                                766                 :     HeapTuple   tuple;
                                767                 :     Form_pg_class form;
                                768                 : 
                                769              17 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
                                770              17 :     if (!HeapTupleIsValid(tuple))
 3712 tgl                       771 UIC           0 :         return;                 /* concurrently dropped */
 3712 tgl                       772 GIC          17 :     form = (Form_pg_class) GETSTRUCT(tuple);
                                773                 : 
                                774                 :     /* only tables and views can have rules */
 2189 rhaas                     775              17 :     if (form->relkind != RELKIND_RELATION &&
                                776              15 :         form->relkind != RELKIND_VIEW &&
                                777               3 :         form->relkind != RELKIND_PARTITIONED_TABLE)
 3712 tgl                       778 UIC           0 :         ereport(ERROR,
                                779                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                780                 :                  errmsg("relation \"%s\" cannot have rules", rv->relname),
                                781                 :                  errdetail_relkind_not_supported(form->relkind)));
                                782                 : 
 3419 rhaas                     783 GIC          17 :     if (!allowSystemTableMods && IsSystemClass(relid, form))
 3712 tgl                       784               1 :         ereport(ERROR,
                                785                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                786                 :                  errmsg("permission denied: \"%s\" is a system catalog",
                                787                 :                         rv->relname)));
                                788                 : 
                                789                 :     /* you must own the table to rename one of its rules */
  147 peter                     790 GNC          16 :     if (!object_ownercheck(RelationRelationId, relid, GetUserId()))
 1954 peter_e                   791 UIC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname);
                                792                 : 
 3712 tgl                       793 GIC          16 :     ReleaseSysCache(tuple);
                                794                 : }
                                795                 : 
                                796                 : /*
                                797                 :  * Rename an existing rewrite rule.
                                798                 :  */
                                799                 : ObjectAddress
                                800              17 : RenameRewriteRule(RangeVar *relation, const char *oldName,
                                801                 :                   const char *newName)
                                802                 : {
                                803                 :     Oid         relid;
                                804                 :     Relation    targetrel;
                                805                 :     Relation    pg_rewrite_desc;
                                806                 :     HeapTuple   ruletup;
                                807                 :     Form_pg_rewrite ruleform;
                                808                 :     Oid         ruleOid;
                                809                 :     ObjectAddress address;
                                810                 : 
                                811                 :     /*
                                812                 :      * Look up name, check permissions, and acquire lock (which we will NOT
                                813                 :      * release until end of transaction).
                                814                 :      */
                                815              17 :     relid = RangeVarGetRelidExtended(relation, AccessExclusiveLock,
                                816                 :                                      0,
                                817                 :                                      RangeVarCallbackForRenameRule,
                                818                 :                                      NULL);
                                819                 : 
                                820                 :     /* Have lock already, so just need to build relcache entry. */
                                821              16 :     targetrel = relation_open(relid, NoLock);
                                822                 : 
                                823                 :     /* Prepare to modify pg_rewrite */
 1539 andres                    824              16 :     pg_rewrite_desc = table_open(RewriteRelationId, RowExclusiveLock);
                                825                 : 
                                826                 :     /* Fetch the rule's entry (it had better exist) */
 4802 rhaas                     827              16 :     ruletup = SearchSysCacheCopy2(RULERELNAME,
                                828                 :                                   ObjectIdGetDatum(relid),
                                829                 :                                   PointerGetDatum(oldName));
 7910 tgl                       830              16 :     if (!HeapTupleIsValid(ruletup))
 7198                           831               3 :         ereport(ERROR,
                                832                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                                833                 :                  errmsg("rule \"%s\" for relation \"%s\" does not exist",
                                834                 :                         oldName, RelationGetRelationName(targetrel))));
 3712                           835              13 :     ruleform = (Form_pg_rewrite) GETSTRUCT(ruletup);
 1601 andres                    836              13 :     ruleOid = ruleform->oid;
                                837                 : 
                                838                 :     /* rule with the new name should not already exist */
 3712 tgl                       839              13 :     if (IsDefinedRewriteRule(relid, newName))
 7198                           840               3 :         ereport(ERROR,
                                841                 :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
                                842                 :                  errmsg("rule \"%s\" for relation \"%s\" already exists",
                                843                 :                         newName, RelationGetRelationName(targetrel))));
                                844                 : 
                                845                 :     /*
                                846                 :      * We disallow renaming ON SELECT rules, because they should always be
                                847                 :      * named "_RETURN".
                                848                 :      */
 3712                           849              10 :     if (ruleform->ev_type == CMD_SELECT + '0')
                                850               3 :         ereport(ERROR,
                                851                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                852                 :                  errmsg("renaming an ON SELECT rule is not allowed")));
                                853                 : 
                                854                 :     /* OK, do the update */
                                855               7 :     namestrcpy(&(ruleform->rulename), newName);
                                856                 : 
 2259 alvherre                  857               7 :     CatalogTupleUpdate(pg_rewrite_desc, &ruletup->t_self, ruletup);
                                858                 : 
 1051 michael                   859               7 :     InvokeObjectPostAlterHook(RewriteRelationId, ruleOid, 0);
                                860                 : 
 7910 tgl                       861               7 :     heap_freetuple(ruletup);
 1539 andres                    862               7 :     table_close(pg_rewrite_desc, RowExclusiveLock);
                                863                 : 
                                864                 :     /*
                                865                 :      * Invalidate relation's relcache entry so that other backends (and this
                                866                 :      * one too!) are sent SI message to make them rebuild relcache entries.
                                867                 :      * (Ideally this should happen automatically...)
                                868                 :      */
 3712 tgl                       869               7 :     CacheInvalidateRelcache(targetrel);
                                870                 : 
 2959 alvherre                  871               7 :     ObjectAddressSet(address, RewriteRelationId, ruleOid);
                                872                 : 
                                873                 :     /*
                                874                 :      * Close rel, but keep exclusive lock!
                                875                 :      */
 3712 tgl                       876               7 :     relation_close(targetrel, NoLock);
                                877                 : 
 2959 alvherre                  878               7 :     return address;
                                879                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a