Skip to content

Commit

Permalink
Prevent automatic index creation with set-returning function
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
yugo-n committed Dec 9, 2024
1 parent 48ddc99 commit d954439
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 9 deletions.
24 changes: 17 additions & 7 deletions createas.c
Original file line number Diff line number Diff line change
Expand Up @@ -1597,31 +1597,41 @@ 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)
{
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);
Expand Down
12 changes: 11 additions & 1 deletion expected/pg_ivm.out
Original file line number Diff line number Diff line change
Expand Up @@ -1663,14 +1663,24 @@ 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
-------------
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;
Expand Down
6 changes: 5 additions & 1 deletion sql/pg_ivm.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit d954439

Please sign in to comment.