diff --git a/expected/create_immv.out b/expected/create_immv.out index 085cf17..8bebe42 100644 --- a/expected/create_immv.out +++ b/expected/create_immv.out @@ -16,11 +16,14 @@ NOTICE: created index "mv2_index" on immv "mv2" SELECT create_immv('mv3', 'WITH d AS (DELETE FROM t RETURNING NULL) SELECT * FROM t'); ERROR: materialized views must not use data-modifying statements in WITH -SELECT immvrelid FROM pg_ivm_immv ORDER BY 1; - immvrelid ------------ - mv - mv2 +SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1; + immvrelid | get_immv_def +-----------+----------------------- + mv | SELECT i + + | FROM t + mv2 | SELECT i AS x + + | FROM t + + | WHERE ((i % 2) = 0) (2 rows) DROP TABLE t; @@ -29,16 +32,18 @@ DETAIL: table mv depends on table t table mv2 depends on table t HINT: Use DROP ... CASCADE to drop the dependent objects too. DROP TABLE mv; -SELECT immvrelid FROM pg_ivm_immv ORDER BY 1; - immvrelid ------------ - mv2 +SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1; + immvrelid | get_immv_def +-----------+----------------------- + mv2 | SELECT i AS x + + | FROM t + + | WHERE ((i % 2) = 0) (1 row) DROP TABLE mv2; -SELECT immvrelid FROM pg_ivm_immv ORDER BY 1; - immvrelid ------------ +SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1; + immvrelid | get_immv_def +-----------+-------------- (0 rows) DROP TABLE t; diff --git a/expected/pg_ivm.out b/expected/pg_ivm.out index f6d8220..9b62a4f 100644 --- a/expected/pg_ivm.out +++ b/expected/pg_ivm.out @@ -1043,6 +1043,24 @@ DELETE FROM mv_ivm_1; ERROR: cannot change materialized view "mv_ivm_1" TRUNCATE mv_ivm_1; ERROR: cannot change materialized view "mv_ivm_1" +-- get_immv_def function +SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1; + immvrelid | get_immv_def +-----------+---------------------------------- + mv_ivm_1 | SELECT a.i, + + | a.j, + + | b.k + + | FROM (mv_base_a a + + | JOIN mv_base_b b USING (i)) +(1 row) + +-- mv_base_b is not immv +SELECT 'mv_base_b'::regclass, get_immv_def('mv_base_b'); + regclass | get_immv_def +-----------+-------------- + mv_base_b | +(1 row) + DROP TABLE mv_base_b CASCADE; NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to table mv_ivm_1 diff --git a/pg_ivm--1.2--1.3.sql b/pg_ivm--1.2--1.3.sql index 040182a..1555567 100644 --- a/pg_ivm--1.2--1.3.sql +++ b/pg_ivm--1.2--1.3.sql @@ -5,3 +5,9 @@ RETURNS bool STABLE AS 'MODULE_PATHNAME', 'ivm_visible_in_prestate' LANGUAGE C; + +CREATE FUNCTION get_immv_def(IN immvrelid regclass) +RETURNS text +STRICT +AS 'MODULE_PATHNAME', 'get_immv_def' +LANGUAGE C; diff --git a/pg_ivm.c b/pg_ivm.c index e8b895d..8db5ac0 100644 --- a/pg_ivm.c +++ b/pg_ivm.c @@ -11,6 +11,7 @@ */ #include "postgres.h" +#include "access/table.h" #include "access/xact.h" #include "catalog/dependency.h" #include "catalog/namespace.h" @@ -45,6 +46,7 @@ static void parseNameAndColumns(const char *string, List **names, List **colName PG_FUNCTION_INFO_V1(create_immv); PG_FUNCTION_INFO_V1(refresh_immv); PG_FUNCTION_INFO_V1(IVM_prevent_immv_change); +PG_FUNCTION_INFO_V1(get_immv_def); /* * Call back functions for cleaning up @@ -320,3 +322,31 @@ PgIvmImmvPrimaryKeyIndexId(void) return pg_ivm_immv_pkey_id; } +/* + * Return the SELECT part of a IMMV + */ +Datum +get_immv_def(PG_FUNCTION_ARGS) +{ + Oid matviewOid = PG_GETARG_OID(0); + Relation matviewRel = NULL; + Query *query = NULL; + char *querystring = NULL; + + /* Make sure IMMV is a table. */ + if (get_rel_relkind(matviewOid) != RELKIND_RELATION) + PG_RETURN_NULL(); + + matviewRel = table_open(matviewOid, AccessShareLock); + query = get_immv_query(matviewRel); + if (query == NULL) + { + table_close(matviewRel, NoLock); + PG_RETURN_NULL(); + } + + querystring = pg_ivm_get_viewdef(matviewRel, false); + + table_close(matviewRel, NoLock); + PG_RETURN_TEXT_P(cstring_to_text(querystring)); +} diff --git a/pg_ivm.h b/pg_ivm.h index de47f1e..0bfa306 100644 --- a/pg_ivm.h +++ b/pg_ivm.h @@ -43,6 +43,7 @@ extern void makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *resname, /* matview.c */ +extern Query *get_immv_query(Relation matviewRel); extern ObjectAddress ExecRefreshImmv(const RangeVar *relation, bool skipData, const char *queryString, QueryCompletion *qc); extern bool ImmvIncrementalMaintenanceIsEnabled(void); diff --git a/sql/create_immv.sql b/sql/create_immv.sql index b76792d..6265cb8 100644 --- a/sql/create_immv.sql +++ b/sql/create_immv.sql @@ -6,14 +6,14 @@ SELECT create_immv(' mv2 ( x ) ', 'SELECT * FROM t WHERE i%2 = 0'); SELECT create_immv('mv3', 'WITH d AS (DELETE FROM t RETURNING NULL) SELECT * FROM t'); -SELECT immvrelid FROM pg_ivm_immv ORDER BY 1; +SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1; DROP TABLE t; DROP TABLE mv; -SELECT immvrelid FROM pg_ivm_immv ORDER BY 1; +SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1; DROP TABLE mv2; -SELECT immvrelid FROM pg_ivm_immv ORDER BY 1; +SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1; DROP TABLE t; diff --git a/sql/pg_ivm.sql b/sql/pg_ivm.sql index 32dfe14..6c6a9f4 100644 --- a/sql/pg_ivm.sql +++ b/sql/pg_ivm.sql @@ -460,5 +460,10 @@ UPDATE mv_ivm_1 SET k = 1 WHERE i = 1; DELETE FROM mv_ivm_1; TRUNCATE mv_ivm_1; +-- get_immv_def function +SELECT immvrelid, get_immv_def(immvrelid) FROM pg_ivm_immv ORDER BY 1; +-- mv_base_b is not immv +SELECT 'mv_base_b'::regclass, get_immv_def('mv_base_b'); + DROP TABLE mv_base_b CASCADE; DROP TABLE mv_base_a CASCADE;