Compare commits

...

1 commit

Author SHA1 Message Date
Yugo Nagata
d954439b17 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)
2024-12-09 19:46:58 +09:00
3 changed files with 33 additions and 9 deletions

View file

@ -1597,13 +1597,13 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList)
{ {
RangeTblEntry *r = (RangeTblEntry*) lfirst(lc); RangeTblEntry *r = (RangeTblEntry*) lfirst(lc);
Bitmapset *key_attnos; Bitmapset *key_attnos;
bool has_pkey = true; bool has_no_pkey = false;
/* for subqueries, scan recursively */ /* for subqueries, scan recursively */
if (r->rtekind == RTE_SUBQUERY) if (r->rtekind == RTE_SUBQUERY)
{ {
key_attnos = get_primary_key_attnos_from_query(r->subquery, constraintList); 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 */ /* for tables, call get_primary_key_attnos */
else if (r->rtekind == RTE_RELATION) else if (r->rtekind == RTE_RELATION)
@ -1611,17 +1611,27 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList)
Oid constraintOid; Oid constraintOid;
key_attnos = get_primary_key_attnos(r->relid, false, &constraintOid); key_attnos = get_primary_key_attnos(r->relid, false, &constraintOid);
*constraintList = lappend_oid(*constraintList, 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; 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. * we cannot get key attributes for this query, so return NULL.
*/ */
if (!has_pkey) if (has_no_pkey)
return NULL; return NULL;
key_attnos_list = lappend(key_attnos_list, key_attnos); key_attnos_list = lappend(key_attnos_list, key_attnos);

View file

@ -1663,7 +1663,7 @@ HINT: Create an index on the immv for efficient incremental maintenance.
0 0
(1 row) (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'); 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" NOTICE: created index "mv_idx6_index" on immv "mv_idx6"
create_immv create_immv
@ -1671,6 +1671,16 @@ NOTICE: created index "mv_idx6_index" on immv "mv_idx6"
0 0
(1 row) (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; ROLLBACK;
-- type that doesn't have default operator class for access method btree -- type that doesn't have default operator class for access method btree
BEGIN; BEGIN;

View file

@ -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_idx4', 'SELECT j FROM base_a');
SELECT create_immv('mv_idx5', 'SELECT a.i, b.j FROM base_a a, base_b b'); 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'); 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; ROLLBACK;
-- type that doesn't have default operator class for access method btree -- type that doesn't have default operator class for access method btree