aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/rewrite/rewriteHandler.c21
-rw-r--r--src/backend/utils/adt/misc.c4
-rw-r--r--src/include/rewrite/rewriteHandler.h1
3 files changed, 24 insertions, 2 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 3e38007643e..334efba7db6 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -27,6 +27,7 @@
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "foreign/fdwapi.h"
+#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
@@ -2619,6 +2620,11 @@ view_cols_are_auto_updatable(Query *viewquery,
* non-NULL, then only the specified columns are considered when testing for
* updatability.
*
+ * Unlike the preceding functions, this does recurse to look at a view's
+ * base relations, so it needs to detect recursion. To do that, we pass
+ * a list of currently-considered outer relations. External callers need
+ * only pass NIL.
+ *
* This is used for the information_schema views, which have separate concepts
* of "updatable" and "trigger updatable". A relation is "updatable" if it
* can be updated without the need for triggers (either because it has a
@@ -2637,6 +2643,7 @@ view_cols_are_auto_updatable(Query *viewquery,
*/
int
relation_is_updatable(Oid reloid,
+ List *outer_reloids,
bool include_triggers,
Bitmapset *include_cols)
{
@@ -2646,6 +2653,9 @@ relation_is_updatable(Oid reloid,
#define ALL_EVENTS ((1 << CMD_INSERT) | (1 << CMD_UPDATE) | (1 << CMD_DELETE))
+ /* Since this function recurses, it could be driven to stack overflow */
+ check_stack_depth();
+
rel = try_relation_open(reloid, AccessShareLock);
/*
@@ -2657,6 +2667,13 @@ relation_is_updatable(Oid reloid,
if (rel == NULL)
return 0;
+ /* If we detect a recursive view, report that it is not updatable */
+ if (list_member_oid(outer_reloids, RelationGetRelid(rel)))
+ {
+ relation_close(rel, AccessShareLock);
+ return 0;
+ }
+
/* If the relation is a table, it is always updatable */
if (rel->rd_rel->relkind == RELKIND_RELATION ||
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
@@ -2777,11 +2794,15 @@ relation_is_updatable(Oid reloid,
base_rte->relkind != RELKIND_PARTITIONED_TABLE)
{
baseoid = base_rte->relid;
+ outer_reloids = lappend_oid(outer_reloids,
+ RelationGetRelid(rel));
include_cols = adjust_view_column_set(updatable_cols,
viewquery->targetList);
auto_events &= relation_is_updatable(baseoid,
+ outer_reloids,
include_triggers,
include_cols);
+ outer_reloids = list_delete_last(outer_reloids);
}
events |= auto_events;
}
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 27474a62535..fed2818c21f 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -509,7 +509,7 @@ pg_relation_is_updatable(PG_FUNCTION_ARGS)
Oid reloid = PG_GETARG_OID(0);
bool include_triggers = PG_GETARG_BOOL(1);
- PG_RETURN_INT32(relation_is_updatable(reloid, include_triggers, NULL));
+ PG_RETURN_INT32(relation_is_updatable(reloid, NIL, include_triggers, NULL));
}
/*
@@ -533,7 +533,7 @@ pg_column_is_updatable(PG_FUNCTION_ARGS)
if (attnum <= 0)
PG_RETURN_BOOL(false);
- events = relation_is_updatable(reloid, include_triggers,
+ events = relation_is_updatable(reloid, NIL, include_triggers,
bms_make_singleton(col));
/* We require both updatability and deletability of the relation */
diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h
index c55fe81a0a3..77b2ffa9621 100644
--- a/src/include/rewrite/rewriteHandler.h
+++ b/src/include/rewrite/rewriteHandler.h
@@ -30,6 +30,7 @@ extern Query *get_view_query(Relation view);
extern const char *view_query_is_auto_updatable(Query *viewquery,
bool check_cols);
extern int relation_is_updatable(Oid reloid,
+ List *outer_reloids,
bool include_triggers,
Bitmapset *include_cols);