From 1b4fb57774ab19c6045b0f01cd67d1941a092dab Mon Sep 17 00:00:00 2001 From: Yugo Nagata Date: Thu, 31 Aug 2023 21:06:23 +0900 Subject: [PATCH] Prohibit types without default btree opclass in the target list (#67) Currently, types that does not have an equality operator cannot be used in the target list of the view definition, because all of target list entries are used for comparison to identify rows to be updated or deleted in the view. Previously, an error is raised at the time such view is incrementally maintained, this is fixed to check that at the view creation time. This restriction may be relaxed in future after we can use an index to identify rows in the view. Issue #61 --- README.md | 5 ++++- createas.c | 21 +++++++++++++++++++++ expected/pg_ivm.out | 6 ++++++ sql/pg_ivm.sql | 6 ++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 850e9ac..ca4e6b9 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,10 @@ Currently, IMMV's view definition can contain inner joins, DISTINCT clause, some The base tables must be simple tables. Views, materialized views, inheritance parent tables, partitioned tables, partitions, and foreign tables can not be used. -The targetlist cannot contain system columns, columns whose name starts with `__ivm_`. +Any system column cannot be included in the view definition query. +The target list cannot columns whose name starts with `__ivm_`. + +Data type used in the target list in the view must have default operator class for access method btree. For example, `json`, `xml`, or `point` type cannot be in the target list. Logical replication is not supported, that is, even when a base table at a publisher node is modified, IMMVs at subscriber nodes defined on these base tables are not updated. diff --git a/createas.c b/createas.c index acf518e..8129415 100644 --- a/createas.c +++ b/createas.c @@ -17,6 +17,7 @@ #include "catalog/dependency.h" #include "catalog/index.h" #include "catalog/indexing.h" +#include "catalog/pg_am.h" #include "catalog/pg_constraint.h" #include "catalog/pg_inherits.h" #include "catalog/pg_trigger_d.h" @@ -828,6 +829,26 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context) errmsg("system column is not supported on incrementally maintainable materialized view"))); } } + + /* check if type in the top target list had an equality operator */ + if (context->sublevels_up == 0) + { + foreach(lc, qry->targetList) + { + TargetEntry *tle = (TargetEntry *) lfirst(lc); + Oid atttype = exprType((Node *) tle->expr); + Oid opclass; + + + opclass = GetDefaultOpClass(atttype, BTREE_AM_OID); + if (!OidIsValid(opclass)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("data type %s has no default operator class for access method \"%s\"", + format_type_be(atttype), "btree"))); + } + } + /* subquery restrictions */ if (context->sublevels_up > 0 && qry->distinctClause != NIL) ereport(ERROR, diff --git a/expected/pg_ivm.out b/expected/pg_ivm.out index a6c1fd2..bf559d3 100644 --- a/expected/pg_ivm.out +++ b/expected/pg_ivm.out @@ -1635,6 +1635,12 @@ NOTICE: created index "mv_idx6_index" on immv "mv_idx6" 0 (1 row) +ROLLBACK; +-- type that doesn't have default operator class for access method btree +BEGIN; +CREATE TABLE table_json (j json); +SELECT create_immv('mv_json', 'SELECT * from table_json'); +ERROR: data type json has no default operator class for access method "btree" ROLLBACK; -- prevent IMMV chanages INSERT INTO mv_ivm_1 VALUES(1,1,1); diff --git a/sql/pg_ivm.sql b/sql/pg_ivm.sql index a366d7a..f99224c 100644 --- a/sql/pg_ivm.sql +++ b/sql/pg_ivm.sql @@ -658,6 +658,12 @@ SELECT create_immv('mv_idx5', 'SELECT a.i, b.j FROM base_a a, 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'); ROLLBACK; +-- type that doesn't have default operator class for access method btree +BEGIN; +CREATE TABLE table_json (j json); +SELECT create_immv('mv_json', 'SELECT * from table_json'); +ROLLBACK; + -- prevent IMMV chanages INSERT INTO mv_ivm_1 VALUES(1,1,1); UPDATE mv_ivm_1 SET k = 1 WHERE i = 1;