From d6f32e7b77ce5adbf47fa5a01c3f938e272439bf Mon Sep 17 00:00:00 2001 From: Adam Guo Date: Wed, 26 Mar 2025 17:07:26 +0000 Subject: [PATCH 1/8] Add querystring column to pg_ivm_immv. --- Makefile | 2 +- createas.c | 1 + pg_ivm--1.10--1.11.sql | 1 + pg_ivm.control | 2 +- pg_ivm.h | 3 ++- 5 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 pg_ivm--1.10--1.11.sql diff --git a/Makefile b/Makefile index 9f770f6..e225eaa 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ DATA = pg_ivm--1.0.sql \ pg_ivm--1.3--1.4.sql pg_ivm--1.4--1.5.sql pg_ivm--1.5--1.6.sql \ pg_ivm--1.6--1.7.sql pg_ivm--1.7--1.8.sql pg_ivm--1.8--1.9.sql \ pg_ivm--1.9--1.10.sql \ - pg_ivm--1.10.sql + pg_ivm--1.10.sql pg_ivm--1.10--1.11.sql REGRESS = pg_ivm create_immv refresh_immv diff --git a/createas.c b/createas.c index b41fd1d..8c6ce4d 100644 --- a/createas.c +++ b/createas.c @@ -1719,6 +1719,7 @@ StoreImmvQuery(Oid viewOid, Query *viewQuery) memset(values, 0, sizeof(values)); memset(isNulls, false, sizeof(isNulls)); + isNulls[Anum_pg_ivm_immv_querystring - 1] = true; values[Anum_pg_ivm_immv_immvrelid -1 ] = ObjectIdGetDatum(viewOid); values[Anum_pg_ivm_immv_ispopulated -1 ] = BoolGetDatum(false); diff --git a/pg_ivm--1.10--1.11.sql b/pg_ivm--1.10--1.11.sql new file mode 100644 index 0000000..b093d22 --- /dev/null +++ b/pg_ivm--1.10--1.11.sql @@ -0,0 +1 @@ +ALTER TABLE pgivm.pg_ivm_immv ADD COLUMN querystring text; diff --git a/pg_ivm.control b/pg_ivm.control index 27dc5af..fcfe90d 100644 --- a/pg_ivm.control +++ b/pg_ivm.control @@ -1,6 +1,6 @@ # incremental view maintenance extension_ comment = 'incremental view maintenance on PostgreSQL' -default_version = '1.10' +default_version = '1.11' module_pathname = '$libdir/pg_ivm' relocatable = false schema = pg_catalog diff --git a/pg_ivm.h b/pg_ivm.h index 88d7003..ae79e45 100644 --- a/pg_ivm.h +++ b/pg_ivm.h @@ -20,12 +20,13 @@ #include "tcop/dest.h" #include "utils/queryenvironment.h" -#define Natts_pg_ivm_immv 4 +#define Natts_pg_ivm_immv 5 #define Anum_pg_ivm_immv_immvrelid 1 #define Anum_pg_ivm_immv_viewdef 2 #define Anum_pg_ivm_immv_ispopulated 3 #define Anum_pg_ivm_immv_lastivmupdate 4 +#define Anum_pg_ivm_immv_querystring 5 /* pg_ivm.c */ From 7a36cc501ad4b7b0114fe847e4cf1d3dede4aaea Mon Sep 17 00:00:00 2001 From: Adam Guo Date: Wed, 26 Mar 2025 17:20:36 +0000 Subject: [PATCH 2/8] Add event trigger to update querystring. --- pg_ivm--1.10--1.11.sql | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pg_ivm--1.10--1.11.sql b/pg_ivm--1.10--1.11.sql index b093d22..6819be4 100644 --- a/pg_ivm--1.10--1.11.sql +++ b/pg_ivm--1.10--1.11.sql @@ -1 +1,23 @@ ALTER TABLE pgivm.pg_ivm_immv ADD COLUMN querystring text; + +CREATE FUNCTION pgivm.refresh_query_strings() +RETURNS event_trigger LANGUAGE plpgsql AS +$$ +DECLARE + old_search_path text; +BEGIN + -- Empty search path so that get_immv_def returns a fully-qualified query. + SELECT setting INTO old_search_path FROM pg_catalog.pg_settings + WHERE name = 'search_path'; + SET search_path = ''; + + UPDATE pgivm.pg_ivm_immv SET querystring = pgivm.get_immv_def(immvrelid); + + -- Reset search path to the original value. + EXECUTE format('SET search_path = %s', old_search_path); +END +$$; + +CREATE EVENT TRIGGER refresh_query_strings +ON ddl_command_end +EXECUTE FUNCTION pgivm.refresh_query_strings(); From 3524de96acdb554af3faf4619206a293abf8c659 Mon Sep 17 00:00:00 2001 From: Adam Guo Date: Wed, 26 Mar 2025 18:32:09 +0000 Subject: [PATCH 3/8] Store querystring on create. --- createas.c | 10 +++++++++- pg_ivm--1.10--1.11.sql | 4 ++-- pg_ivm.c | 9 +++++++++ pg_ivm.h | 5 +++++ ruleutils.c | 7 +++++++ 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/createas.c b/createas.c index 8c6ce4d..026cce3 100644 --- a/createas.c +++ b/createas.c @@ -41,6 +41,7 @@ #include "rewrite/rewriteManip.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/regproc.h" #include "utils/rel.h" @@ -1710,20 +1711,27 @@ static void StoreImmvQuery(Oid viewOid, Query *viewQuery) { char *querytree = nodeToString((Node *) viewQuery); + char *querystring; Datum values[Natts_pg_ivm_immv]; bool isNulls[Natts_pg_ivm_immv]; + Relation matviewRel; Relation pgIvmImmv; TupleDesc tupleDescriptor; HeapTuple heapTuple; ObjectAddress address; + RestrictSearchPath(); + matviewRel = table_open(viewOid, AccessShareLock); + querystring = pg_ivm_get_viewdef_internal(viewQuery, matviewRel, true); + table_close(matviewRel, NoLock); + memset(values, 0, sizeof(values)); memset(isNulls, false, sizeof(isNulls)); - isNulls[Anum_pg_ivm_immv_querystring - 1] = true; values[Anum_pg_ivm_immv_immvrelid -1 ] = ObjectIdGetDatum(viewOid); values[Anum_pg_ivm_immv_ispopulated -1 ] = BoolGetDatum(false); values[Anum_pg_ivm_immv_viewdef -1 ] = CStringGetTextDatum(querytree); + values[Anum_pg_ivm_immv_querystring - 1] = CStringGetTextDatum(querystring); pgIvmImmv = table_open(PgIvmImmvRelationId(), RowExclusiveLock); diff --git a/pg_ivm--1.10--1.11.sql b/pg_ivm--1.10--1.11.sql index 6819be4..745f3dc 100644 --- a/pg_ivm--1.10--1.11.sql +++ b/pg_ivm--1.10--1.11.sql @@ -1,7 +1,7 @@ -ALTER TABLE pgivm.pg_ivm_immv ADD COLUMN querystring text; +ALTER TABLE pgivm.pg_ivm_immv ADD COLUMN querystring text NOT NULL; CREATE FUNCTION pgivm.refresh_query_strings() -RETURNS event_trigger LANGUAGE plpgsql AS +RETURNS event_trigger LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE old_search_path text; diff --git a/pg_ivm.c b/pg_ivm.c index 19d0e0e..fe5c9bb 100644 --- a/pg_ivm.c +++ b/pg_ivm.c @@ -458,3 +458,12 @@ PgIvmFuncName(char *name) { return list_make2(makeString("pgivm"), makeString(name)); } + +#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM < 170000) +void +RestrictSearchPath(void) +{ + set_config_option("search_path", "pg_catalog, pg_temp", PGC_USERSET, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); +} +#endif diff --git a/pg_ivm.h b/pg_ivm.h index ae79e45..e334141 100644 --- a/pg_ivm.h +++ b/pg_ivm.h @@ -65,8 +65,13 @@ extern bool isIvmName(const char *s); /* ruleutils.c */ extern char *pg_ivm_get_viewdef(Relation immvrel, bool pretty); +extern char *pg_ivm_get_viewdef_internal(Query *query, Relation immvrel, bool pretty); /* subselect.c */ extern void inline_cte(PlannerInfo *root, CommonTableExpr *cte); +#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM < 170000) +extern void RestrictSearchPath(void); +#endif + #endif diff --git a/ruleutils.c b/ruleutils.c index dfe1fe4..2c7e080 100644 --- a/ruleutils.c +++ b/ruleutils.c @@ -43,6 +43,13 @@ char * pg_ivm_get_viewdef(Relation immvrel, bool pretty) { Query *query = get_immv_query(immvrel); + + return pg_ivm_get_viewdef_internal(query, immvrel, pretty); +} + +char * +pg_ivm_get_viewdef_internal(Query *query, Relation immvrel, bool pretty) +{ TupleDesc resultDesc = RelationGetDescr(immvrel); #if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 150000) From 0a5bd500e6fa3efcc265fa2976d4a963375a0b65 Mon Sep 17 00:00:00 2001 From: Adam Guo Date: Wed, 26 Mar 2025 21:42:06 +0000 Subject: [PATCH 4/8] refresh_immv: reparse the query string --- matview.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- pg_ivm.c | 33 ++++++++++++++++++----- pg_ivm.h | 2 ++ 3 files changed, 108 insertions(+), 7 deletions(-) diff --git a/matview.c b/matview.c index 66709b5..aa95b58 100644 --- a/matview.c +++ b/matview.c @@ -233,6 +233,7 @@ static void clean_up_IVM_hash_entry(MV_TriggerHashEntry *entry, bool is_abort, static void setLastUpdateXid(Oid immv_oid, FullTransactionId xid); static FullTransactionId getLastUpdateXid(Oid immv_oid); +static Query *recreate_immv_query(Relation matviewRel); /* SQL callable functions */ PG_FUNCTION_INFO_V1(IVM_immediate_before); @@ -388,7 +389,7 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData, systable_endscan(scan); table_close(pgIvmImmv, NoLock); - viewQuery = get_immv_query(matviewRel); + viewQuery = recreate_immv_query(matviewRel); /* For IMMV, we need to rewrite matview query */ if (!skipData) @@ -713,6 +714,83 @@ get_immv_query(Relation matviewRel) return query; } +/* + * recreate_immv_query + * + * Parse the querystring for this IMMV. Update the viewdef column in + * pg_ivm_immv and return the Query tree. + */ +static Query * +recreate_immv_query(Relation matviewRel) +{ + Relation pgIvmImmv = table_open(PgIvmImmvRelationId(), AccessShareLock); + TupleDesc tupdesc = RelationGetDescr(pgIvmImmv); + SysScanDesc scan; + ScanKeyData key; + HeapTuple tup; + bool isnull; + Datum datum; + Query *query = NULL; + IntoClause *into; + ParseState *pstate = NULL; + CreateTableAsStmt *stmt; + const char *querystring; + const char *relname; + const char *querytree; + + Datum values[Natts_pg_ivm_immv]; + bool nulls[Natts_pg_ivm_immv]; + bool replaces[Natts_pg_ivm_immv]; + HeapTuple newtup = NULL; + + ScanKeyInit(&key, + Anum_pg_ivm_immv_immvrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(matviewRel))); + scan = systable_beginscan(pgIvmImmv, PgIvmImmvPrimaryKeyIndexId(), + true, NULL, 1, &key); + + tup = systable_getnext(scan); + + if (!HeapTupleIsValid(tup)) + { + systable_endscan(scan); + table_close(pgIvmImmv, NoLock); + return NULL; + } + + datum = heap_getattr(tup, Anum_pg_ivm_immv_querystring, tupdesc, &isnull); + Assert(!isnull); + querystring = TextDatumGetCString(datum); + + relname = psprintf("%s.%s", + get_namespace_name(get_rel_namespace(matviewRel->rd_id)), + get_rel_name(matviewRel->rd_id)); + + parse_immv_query(relname, querystring, &query, &pstate); + stmt = castNode(CreateTableAsStmt, query->utilityStmt); + into = stmt->into; + + query = castNode(Query, stmt->query); + query = rewriteQueryForIMMV(query, into->colNames); + querytree = nodeToString((Node *) query); + + memset(values, 0, sizeof(values)); + memset(nulls, 0, sizeof(nulls)); + memset(replaces, 0, sizeof(replaces)); + values[Anum_pg_ivm_immv_viewdef - 1] = CStringGetTextDatum(querytree); + replaces[Anum_pg_ivm_immv_viewdef - 1] = true; + + newtup = heap_modify_tuple(tup, tupdesc, values, nulls, replaces); + CatalogTupleUpdate(pgIvmImmv, &newtup->t_self, newtup); + heap_freetuple(newtup); + + systable_endscan(scan); + table_close(pgIvmImmv, NoLock); + + return query; +} + static Tuplestorestate * tuplestore_copy(Tuplestorestate *tuplestore, Relation rel) { diff --git a/pg_ivm.c b/pg_ivm.c index fe5c9bb..a005e07 100644 --- a/pg_ivm.c +++ b/pg_ivm.c @@ -177,17 +177,39 @@ create_immv(PG_FUNCTION_ARGS) text *t_sql = PG_GETARG_TEXT_PP(1); char *relname = text_to_cstring(t_relname); char *sql = text_to_cstring(t_sql); + + Query *query = NULL; + QueryCompletion qc; + ParseState *pstate = NULL; + + parse_immv_query(relname, sql, &query, &pstate); + + ExecCreateImmv(pstate, (CreateTableAsStmt *) query->utilityStmt, &qc); + + PG_RETURN_INT64(qc.nprocessed); +} + +/* + * parse_immv_query + * + * Parse an IMMV definition query and return the Query tree and ParseState using + * the supplied pointers. + */ +void +parse_immv_query(const char *relname, const char *sql, Query **query_ret, + ParseState **pstate_ret) +{ List *parsetree_list; RawStmt *parsetree; - Query *query; - QueryCompletion qc; List *names = NIL; List *colNames = NIL; - ParseState *pstate = make_parsestate(NULL); CreateTableAsStmt *ctas; StringInfoData command_buf; + Query *query; + ParseState *pstate; + pstate = make_parsestate(NULL); parseNameAndColumns(relname, &names, &colNames); initStringInfo(&command_buf); @@ -230,9 +252,8 @@ create_immv(PG_FUNCTION_ARGS) query = transformStmt(pstate, (Node *)ctas); Assert(query->commandType == CMD_UTILITY && IsA(query->utilityStmt, CreateTableAsStmt)); - ExecCreateImmv(pstate, (CreateTableAsStmt *) query->utilityStmt, &qc); - - PG_RETURN_INT64(qc.nprocessed); + *query_ret = query; + *pstate_ret = pstate; } /* diff --git a/pg_ivm.h b/pg_ivm.h index e334141..04c83f0 100644 --- a/pg_ivm.h +++ b/pg_ivm.h @@ -35,6 +35,8 @@ extern Oid PgIvmImmvRelationId(void); extern Oid PgIvmImmvPrimaryKeyIndexId(void); extern bool isImmv(Oid immv_oid); extern List *PgIvmFuncName(char *name); +extern void parse_immv_query(const char *relname, const char *sql, + Query **query_ret, ParseState **pstate_ret); /* createas.c */ From 7bc34dfa908556c87b62e2ccb9af2315c5bc6710 Mon Sep 17 00:00:00 2001 From: Adam Guo Date: Wed, 26 Mar 2025 22:44:45 +0000 Subject: [PATCH 5/8] Add recreate_all_immvs function. Recreate change prevent triggers during refresh_immv in addition to base table triggers. --- matview.c | 6 +++++- pg_ivm--1.10--1.11.sql | 23 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/matview.c b/matview.c index aa95b58..8854124 100644 --- a/matview.c +++ b/matview.c @@ -444,7 +444,8 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData, tgform = (Form_pg_trigger) GETSTRUCT(tgtup); /* If trigger is created by IMMV, delete it. */ - if (strncmp(NameStr(tgform->tgname), "IVM_trigger_", 12) == 0) + if (strncmp(NameStr(tgform->tgname), "IVM_trigger_", 12) == 0 || + strncmp(NameStr(tgform->tgname), "IVM_prevent_", 12) == 0) { obj.classId = foundDep->classid; obj.objectId = foundDep->objid; @@ -474,7 +475,10 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData, * is created. */ if (!skipData && !oldPopulated) + { CreateIvmTriggersOnBaseTables(dataQuery, matviewOid); + CreateChangePreventTrigger(matviewOid); + } /* * Create the transient table that will receive the regenerated data. Lock diff --git a/pg_ivm--1.10--1.11.sql b/pg_ivm--1.10--1.11.sql index 745f3dc..4f99101 100644 --- a/pg_ivm--1.10--1.11.sql +++ b/pg_ivm--1.10--1.11.sql @@ -1,5 +1,24 @@ ALTER TABLE pgivm.pg_ivm_immv ADD COLUMN querystring text NOT NULL; +CREATE FUNCTION pgivm.recreate_all_immvs() RETURNS VOID LANGUAGE PLPGSQL AS +$$ +BEGIN + PERFORM pgivm.refresh_immv(n.nspname || '.' || c.relname, false) + FROM pgivm.pg_ivm_immv as ivm + JOIN pg_catalog.pg_class as c + ON c.oid = ivm.immvrelid + JOIN pg_catalog.pg_namespace as n + ON c.relnamespace = n.oid; + + PERFORM pgivm.refresh_immv(n.nspname || '.' || c.relname, true) + FROM pgivm.pg_ivm_immv as ivm + JOIN pg_catalog.pg_class as c + ON c.oid = ivm.immvrelid + JOIN pg_catalog.pg_namespace as n + ON c.relnamespace = n.oid; +END +$$; + CREATE FUNCTION pgivm.refresh_query_strings() RETURNS event_trigger LANGUAGE plpgsql SECURITY DEFINER AS $$ @@ -14,7 +33,9 @@ BEGIN UPDATE pgivm.pg_ivm_immv SET querystring = pgivm.get_immv_def(immvrelid); -- Reset search path to the original value. - EXECUTE format('SET search_path = %s', old_search_path); + IF old_search_path != '' AND old_search_path != '""' THEN + EXECUTE format('SET search_path = %s', old_search_path); + END IF; END $$; From 5b95cfddf4cd2711ca98d117e45fbc47bb7e4835 Mon Sep 17 00:00:00 2001 From: Adam Guo Date: Thu, 27 Mar 2025 14:14:05 +0000 Subject: [PATCH 6/8] Formatting, naming, comments --- matview.c | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/matview.c b/matview.c index 8854124..e6db540 100644 --- a/matview.c +++ b/matview.c @@ -233,7 +233,7 @@ static void clean_up_IVM_hash_entry(MV_TriggerHashEntry *entry, bool is_abort, static void setLastUpdateXid(Oid immv_oid, FullTransactionId xid); static FullTransactionId getLastUpdateXid(Oid immv_oid); -static Query *recreate_immv_query(Relation matviewRel); +static Query *update_immv_viewdef(Relation matviewRel); /* SQL callable functions */ PG_FUNCTION_INFO_V1(IVM_immediate_before); @@ -389,7 +389,18 @@ RefreshImmvByOid(Oid matviewOid, bool is_create, bool skipData, systable_endscan(scan); table_close(pgIvmImmv, NoLock); - viewQuery = recreate_immv_query(matviewRel); + /* + * Recreate the Query tree from the query string to account for changing + * base table OIDs (e.g. after dump/restore) or changing format of the Query + * node (after pg_upgrade). + * + * No need to create the Query tree a second time if we are creating a new + * IMMV. + */ + if (is_create) + viewQuery = get_immv_query(matviewRel); + else + viewQuery = update_immv_viewdef(matviewRel); /* For IMMV, we need to rewrite matview query */ if (!skipData) @@ -719,34 +730,36 @@ get_immv_query(Relation matviewRel) } /* - * recreate_immv_query + * update_immv_viewdef * - * Parse the querystring for this IMMV. Update the viewdef column in - * pg_ivm_immv and return the Query tree. + * Read the query string for this IMMV from pg_ivm_immv. Parse the query string + * and update the viewdef column with the new Query tree. Return the Query + * tree. */ static Query * -recreate_immv_query(Relation matviewRel) +update_immv_viewdef(Relation matviewRel) { - Relation pgIvmImmv = table_open(PgIvmImmvRelationId(), AccessShareLock); - TupleDesc tupdesc = RelationGetDescr(pgIvmImmv); - SysScanDesc scan; - ScanKeyData key; - HeapTuple tup; - bool isnull; + CreateTableAsStmt *stmt; Datum datum; - Query *query = NULL; + Datum values[Natts_pg_ivm_immv]; + HeapTuple newtup = NULL; + HeapTuple tup; IntoClause *into; ParseState *pstate = NULL; - CreateTableAsStmt *stmt; - const char *querystring; - const char *relname; - const char *querytree; + Query *query = NULL; + Relation pgIvmImmv = table_open(PgIvmImmvRelationId(), AccessShareLock); + ScanKeyData key; + SysScanDesc scan; + TupleDesc tupdesc = RelationGetDescr(pgIvmImmv); - Datum values[Natts_pg_ivm_immv]; + bool isnull; bool nulls[Natts_pg_ivm_immv]; bool replaces[Natts_pg_ivm_immv]; - HeapTuple newtup = NULL; + const char *querystring; + const char *querytree; + const char *relname; + /* Scan pg_ivm_immv for the given IMMV entry. */ ScanKeyInit(&key, Anum_pg_ivm_immv_immvrelid, BTEqualStrategyNumber, F_OIDEQ, @@ -763,10 +776,12 @@ recreate_immv_query(Relation matviewRel) return NULL; } + /* Read the query string column. */ datum = heap_getattr(tup, Anum_pg_ivm_immv_querystring, tupdesc, &isnull); Assert(!isnull); querystring = TextDatumGetCString(datum); + /* Parse the query string using the same logic as create_immv. */ relname = psprintf("%s.%s", get_namespace_name(get_rel_namespace(matviewRel->rd_id)), get_rel_name(matviewRel->rd_id)); @@ -779,6 +794,7 @@ recreate_immv_query(Relation matviewRel) query = rewriteQueryForIMMV(query, into->colNames); querytree = nodeToString((Node *) query); + /* Update the pg_ivm_immv tuple with the new query tree. */ memset(values, 0, sizeof(values)); memset(nulls, 0, sizeof(nulls)); memset(replaces, 0, sizeof(replaces)); From eefb16763e4a446978c6437e24bc38e19798effb Mon Sep 17 00:00:00 2001 From: Adam Guo Date: Thu, 27 Mar 2025 14:46:07 +0000 Subject: [PATCH 7/8] Add warning to event trigger --- pg_ivm--1.10--1.11.sql | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/pg_ivm--1.10--1.11.sql b/pg_ivm--1.10--1.11.sql index 4f99101..bff5179 100644 --- a/pg_ivm--1.10--1.11.sql +++ b/pg_ivm--1.10--1.11.sql @@ -25,17 +25,25 @@ $$ DECLARE old_search_path text; BEGIN - -- Empty search path so that get_immv_def returns a fully-qualified query. - SELECT setting INTO old_search_path FROM pg_catalog.pg_settings - WHERE name = 'search_path'; - SET search_path = ''; + -- Only need to refresh query strings if an object is renamed. + -- As a rough heuristic, check if this is an ALTER command. + IF tg_tag LIKE 'ALTER %' THEN + -- Empty search path so that get_immv_def returns a fully-qualified query. + SELECT setting INTO old_search_path FROM pg_catalog.pg_settings + WHERE name = 'search_path'; + SET search_path = ''; - UPDATE pgivm.pg_ivm_immv SET querystring = pgivm.get_immv_def(immvrelid); + UPDATE pgivm.pg_ivm_immv SET querystring = pgivm.get_immv_def(immvrelid); - -- Reset search path to the original value. - IF old_search_path != '' AND old_search_path != '""' THEN - EXECUTE format('SET search_path = %s', old_search_path); + -- Reset search path to the original value. + IF old_search_path != '' AND old_search_path != '""' THEN + EXECUTE format('SET search_path = %s', old_search_path); + END IF; END IF; +EXCEPTION + WHEN internal_error THEN + RAISE WARNING 'pg_ivm could not refresh the pg_ivm_immv query strings.' + USING HINT = 'Please recreate your IMMVs using pgivm.recreate_all_immvs().'; END $$; From 1901c99f2169670aac8a82d88c176e7db6ec8172 Mon Sep 17 00:00:00 2001 From: Adam Guo Date: Thu, 27 Mar 2025 18:15:22 +0000 Subject: [PATCH 8/8] Rollback GUC change in createas.c --- createas.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/createas.c b/createas.c index 026cce3..338650d 100644 --- a/createas.c +++ b/createas.c @@ -1712,6 +1712,7 @@ StoreImmvQuery(Oid viewOid, Query *viewQuery) { char *querytree = nodeToString((Node *) viewQuery); char *querystring; + int save_nestlevel; Datum values[Natts_pg_ivm_immv]; bool isNulls[Natts_pg_ivm_immv]; Relation matviewRel; @@ -1720,10 +1721,17 @@ StoreImmvQuery(Oid viewOid, Query *viewQuery) HeapTuple heapTuple; ObjectAddress address; + /* + * Restrict search_path so that pg_ivm_get_viewdef_internal returns a + * fully-qualified query. + */ + save_nestlevel = NewGUCNestLevel(); RestrictSearchPath(); matviewRel = table_open(viewOid, AccessShareLock); querystring = pg_ivm_get_viewdef_internal(viewQuery, matviewRel, true); table_close(matviewRel, NoLock); + /* Roll back the search_path change. */ + AtEOXact_GUC(false, save_nestlevel); memset(values, 0, sizeof(values)); memset(isNulls, false, sizeof(isNulls));