@@ -31,7 +31,7 @@ static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, Oid use
31
31
static AclResult LockTableAclCheck (Oid relid , LOCKMODE lockmode , Oid userid );
32
32
static void RangeVarCallbackForLockTable (const RangeVar * rv , Oid relid ,
33
33
Oid oldrelid , void * arg );
34
- static void LockViewRecurse (Oid reloid , Oid root_reloid , LOCKMODE lockmode , bool nowait );
34
+ static void LockViewRecurse (Oid reloid , LOCKMODE lockmode , bool nowait , List * ancestor_views );
35
35
36
36
/*
37
37
* LOCK TABLE
@@ -67,7 +67,7 @@ LockTableCommand(LockStmt *lockstmt)
67
67
(void * ) & lockstmt -> mode );
68
68
69
69
if (get_rel_relkind (reloid ) == RELKIND_VIEW )
70
- LockViewRecurse (reloid , reloid , lockstmt -> mode , lockstmt -> nowait );
70
+ LockViewRecurse (reloid , lockstmt -> mode , lockstmt -> nowait , NIL );
71
71
else if (recurse )
72
72
LockTableRecurse (reloid , lockstmt -> mode , lockstmt -> nowait , GetUserId ());
73
73
}
@@ -92,7 +92,6 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
92
92
return ; /* woops, concurrently dropped; no permissions
93
93
* check */
94
94
95
-
96
95
/* Currently, we only allow plain tables or views to be locked */
97
96
if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
98
97
relkind != RELKIND_VIEW )
@@ -178,11 +177,11 @@ LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, Oid userid)
178
177
179
178
typedef struct
180
179
{
181
- Oid root_reloid ;
182
- LOCKMODE lockmode ;
183
- bool nowait ;
184
- Oid viewowner ;
185
- Oid viewoid ;
180
+ LOCKMODE lockmode ; /* lock mode to use */
181
+ bool nowait ; /* no wait mode */
182
+ Oid viewowner ; /* view owner for checking the privilege */
183
+ Oid viewoid ; /* OID of the view to be locked */
184
+ List * ancestor_views ; /* OIDs of ancestor views */
186
185
} LockViewRecurse_context ;
187
186
188
187
static bool
@@ -193,19 +192,22 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
193
192
194
193
if (IsA (node , Query ))
195
194
{
196
- Query * query = (Query * ) node ;
197
- ListCell * rtable ;
195
+ Query * query = (Query * ) node ;
196
+ ListCell * rtable ;
198
197
199
198
foreach (rtable , query -> rtable )
200
199
{
201
- RangeTblEntry * rte = lfirst (rtable );
202
- AclResult aclresult ;
200
+ RangeTblEntry * rte = lfirst (rtable );
201
+ AclResult aclresult ;
203
202
204
- Oid relid = rte -> relid ;
205
- char relkind = rte -> relkind ;
206
- char * relname = get_rel_name (relid );
203
+ Oid relid = rte -> relid ;
204
+ char relkind = rte -> relkind ;
205
+ char * relname = get_rel_name (relid );
207
206
208
- /* The OLD and NEW placeholder entries in the view's rtable are skipped. */
207
+ /*
208
+ * The OLD and NEW placeholder entries in the view's rtable are
209
+ * skipped.
210
+ */
209
211
if (relid == context -> viewoid &&
210
212
(!strcmp (rte -> eref -> aliasname , "old" ) || !strcmp (rte -> eref -> aliasname , "new" )))
211
213
continue ;
@@ -216,11 +218,11 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
216
218
continue ;
217
219
218
220
/* Check infinite recursion in the view definition. */
219
- if (relid == context -> root_reloid )
221
+ if (list_member_oid ( context -> ancestor_views , relid ) )
220
222
ereport (ERROR ,
221
223
(errcode (ERRCODE_INVALID_OBJECT_DEFINITION ),
222
- errmsg ("infinite recursion detected in rules for relation \"%s\"" ,
223
- get_rel_name (context -> root_reloid ))));
224
+ errmsg ("infinite recursion detected in rules for relation \"%s\"" ,
225
+ get_rel_name (relid ))));
224
226
225
227
/* Check permissions with the view owner's privilege. */
226
228
aclresult = LockTableAclCheck (relid , context -> lockmode , context -> viewowner );
@@ -233,11 +235,11 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
233
235
else if (!ConditionalLockRelationOid (relid , context -> lockmode ))
234
236
ereport (ERROR ,
235
237
(errcode (ERRCODE_LOCK_NOT_AVAILABLE ),
236
- errmsg ("could not obtain lock on relation \"%s\"" ,
238
+ errmsg ("could not obtain lock on relation \"%s\"" ,
237
239
relname )));
238
240
239
241
if (relkind == RELKIND_VIEW )
240
- LockViewRecurse (relid , context -> root_reloid , context -> lockmode , context -> nowait );
242
+ LockViewRecurse (relid , context -> lockmode , context -> nowait , context -> ancestor_views );
241
243
else if (rte -> inh )
242
244
LockTableRecurse (relid , context -> lockmode , context -> nowait , context -> viewowner );
243
245
}
@@ -254,24 +256,26 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
254
256
}
255
257
256
258
static void
257
- LockViewRecurse (Oid reloid , Oid root_reloid , LOCKMODE lockmode , bool nowait )
259
+ LockViewRecurse (Oid reloid , LOCKMODE lockmode , bool nowait , List * ancestor_views )
258
260
{
259
261
LockViewRecurse_context context ;
260
262
261
- Relation view ;
262
- Query * viewquery ;
263
+ Relation view ;
264
+ Query * viewquery ;
263
265
264
266
view = heap_open (reloid , NoLock );
265
267
viewquery = get_view_query (view );
266
268
267
- context .root_reloid = root_reloid ;
268
269
context .lockmode = lockmode ;
269
270
context .nowait = nowait ;
270
271
context .viewowner = view -> rd_rel -> relowner ;
271
272
context .viewoid = reloid ;
273
+ context .ancestor_views = lcons_oid (reloid , ancestor_views );
272
274
273
275
LockViewRecurse_walker ((Node * ) viewquery , & context );
274
276
277
+ ancestor_views = list_delete_oid (ancestor_views , reloid );
278
+
275
279
heap_close (view , NoLock );
276
280
}
277
281
0 commit comments