LCOV - differential code coverage report
Current view: top level - src/backend/rewrite - rewriteDefine.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DCB
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 85.2 % 237 202 35 2 200 2
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 10 10 1 9
Baseline: lcov-20250906-005545-baseline Branches: 55.5 % 254 141 1 112 1 140
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 2 2 2
(30,360] days: 100.0 % 1 1 1
(360..) days: 85.0 % 234 199 35 199
Function coverage date bins:
(360..) days: 100.0 % 10 10 1 9
Branch coverage date bins:
(7,30] days: 50.0 % 2 1 1 1
(360..) days: 55.6 % 252 140 112 140

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

Generated by: LCOV version 2.4-beta