From d954439b175ebe346252b099047113c16734a26b Mon Sep 17 00:00:00 2001 From: Yugo Nagata Date: Mon, 21 Oct 2024 19:26:38 +0900 Subject: [PATCH] Prevent automatic index creation with set-returning function Previously, a unique index is automatically created even when a set-returning function is contained in FROM clause, but this results in an error due to key duplication. Now, an index is not created automatically when a relation other than table, sub-query, or join is contained in FROM clause. Issue (#99) --- createas.c | 24 +++++++++++++++++------- expected/pg_ivm.out | 12 +++++++++++- sql/pg_ivm.sql | 6 +++++- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/createas.c b/createas.c index 5b1b877..86b3bd2 100644 --- a/createas.c +++ b/createas.c @@ -1597,13 +1597,13 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList) { RangeTblEntry *r = (RangeTblEntry*) lfirst(lc); Bitmapset *key_attnos; - bool has_pkey = true; + bool has_no_pkey = false; /* for subqueries, scan recursively */ if (r->rtekind == RTE_SUBQUERY) { key_attnos = get_primary_key_attnos_from_query(r->subquery, constraintList); - has_pkey = (key_attnos != NULL); + has_no_pkey = (key_attnos == NULL); } /* for tables, call get_primary_key_attnos */ else if (r->rtekind == RTE_RELATION) @@ -1611,17 +1611,27 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList) Oid constraintOid; key_attnos = get_primary_key_attnos(r->relid, false, &constraintOid); *constraintList = lappend_oid(*constraintList, constraintOid); - has_pkey = (key_attnos != NULL); + has_no_pkey = (key_attnos == NULL); } - /* for other RTEs, store NULL into key_attnos_list */ - else + /* + * Ignore join rels, because they are flatten later by + * flatten_join_alias_vars(). Store NULL into key_attnos_list + * as a dummy. + */ + else if (r->rtekind == RTE_JOIN) + { key_attnos = NULL; + } + /* for other RTEs, we assume they have no candidate key */ + else + has_no_pkey = true; /* - * If any table or subquery has no primary key or its pkey constraint is deferrable, + * If any table or subquery has no primary key or its pkey constraint + * is deferrable (i.e., get_primary_key_attnos returned NULL), * we cannot get key attributes for this query, so return NULL. */ - if (!has_pkey) + if (has_no_pkey) return NULL; key_attnos_list = lappend(key_attnos_list, key_attnos); diff --git a/expected/pg_ivm.out b/expected/pg_ivm.out index e8798ee..363c927 100644 --- a/expected/pg_ivm.out +++ b/expected/pg_ivm.out @@ -1663,7 +1663,7 @@ HINT: Create an index on the immv for efficient incremental maintenance. 0 (1 row) ---- subqueries +--- subqueries: create an index SELECT create_immv('mv_idx6(i_a, i_b)', 'SELECT a.i, b.i FROM (SELECT * FROM base_a) a, (SELECT * FROM base_b) b'); NOTICE: created index "mv_idx6_index" on immv "mv_idx6" create_immv @@ -1671,6 +1671,16 @@ NOTICE: created index "mv_idx6_index" on immv "mv_idx6" 0 (1 row) +--- with set-returning function: no index +SELECT create_immv('mv_idx7', 'SELECT i FROM base_a, generate_series(1,10)'); +NOTICE: could not create an index on immv "mv_idx7" automatically +DETAIL: This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause. +HINT: Create an index on the immv for efficient incremental maintenance. + create_immv +------------- + 0 +(1 row) + ROLLBACK; -- type that doesn't have default operator class for access method btree BEGIN; diff --git a/sql/pg_ivm.sql b/sql/pg_ivm.sql index d3c1a01..e2fbdea 100644 --- a/sql/pg_ivm.sql +++ b/sql/pg_ivm.sql @@ -662,8 +662,12 @@ SELECT create_immv('mv_idx3(i_a, i_b)', 'SELECT a.i, b.i FROM base_a a, base_b b SELECT create_immv('mv_idx4', 'SELECT j FROM base_a'); SELECT create_immv('mv_idx5', 'SELECT a.i, b.j FROM base_a a, base_b b'); ---- subqueries +--- subqueries: create an index SELECT create_immv('mv_idx6(i_a, i_b)', 'SELECT a.i, b.i FROM (SELECT * FROM base_a) a, (SELECT * FROM base_b) b'); + +--- with set-returning function: no index +SELECT create_immv('mv_idx7', 'SELECT i FROM base_a, generate_series(1,10)'); + ROLLBACK; -- type that doesn't have default operator class for access method btree