Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 13 additions & 127 deletions h3/sql/updates/h3--4.2.3--4.5.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -19,140 +19,26 @@
\echo Use "ALTER EXTENSION h3 UPDATE TO '4.5.0'" to load this file. \quit

-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
-- Keep the public bigint <-> signature upgrade-safe, refresh stored/indexed
-- distance results that may still contain the old sentinel, and wire in the
-- GiST KNN operator class support functions used below.
-- Keep the public bigint <-> signature upgrade-safe and wire in the GiST KNN
-- operator class support functions used below. User-defined dependent objects
-- must be maintained explicitly after the upgrade, not by this script.
-- ---------- ---------- ---------- ---------- ---------- ---------- ----------

CREATE OR REPLACE FUNCTION h3index_distance(h3index, h3index) RETURNS bigint
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON OPERATOR <-> (h3index, h3index) IS
'Returns the distance in grid cells between the two indices after refining the coarser input to its center child at the finer resolution. Returns the maximum bigint value when gridDistance fails (e.g. near pentagons).';

DO $$
DECLARE
dep_index RECORD;
dep_table RECORD;
dep_matview RECORD;
distance_op oid := '<->(h3index,h3index)'::regoperator;
distance_fn oid := 'h3index_distance(h3index,h3index)'::regprocedure;
original_replication_role text := pg_catalog.current_setting('session_replication_role');
BEGIN
/*
* Stored generated columns need their rows recomputed, but the extension
* upgrade must not fire arbitrary user UPDATE triggers while doing so.
*/
PERFORM pg_catalog.set_config('session_replication_role', 'replica', true);
BEGIN
FOR dep_table IN
WITH RECURSIVE distance_dependents AS (
SELECT 'pg_operator'::regclass::oid AS classid, distance_op AS objid
UNION
SELECT 'pg_proc'::regclass::oid AS classid, distance_fn AS objid
UNION
SELECT d.classid, d.objid
FROM pg_depend d
JOIN distance_dependents dd
ON d.refclassid = dd.classid
AND d.refobjid = dd.objid
WHERE d.deptype IN ('n', 'a', 'i')
)
SELECT DISTINCT
c.oid::regclass AS relid,
base.attname AS base_attname
FROM distance_dependents dd
JOIN pg_attrdef ad
ON ad.oid = dd.objid
JOIN pg_attribute a
ON a.attrelid = ad.adrelid
AND a.attnum = ad.adnum
AND a.attgenerated = 's'
JOIN pg_class c
ON c.oid = ad.adrelid
JOIN LATERAL (
SELECT a2.attname
FROM pg_attribute a2
WHERE a2.attrelid = c.oid
AND a2.attnum > 0
AND NOT a2.attisdropped
AND a2.attgenerated = ''
AND a2.attidentity <> 'a'
ORDER BY a2.attnum
LIMIT 1
) base ON TRUE
WHERE dd.classid = 'pg_attrdef'::regclass
LOOP
EXECUTE pg_catalog.format(
'UPDATE %s SET %I = %I',
dep_table.relid,
dep_table.base_attname,
dep_table.base_attname
);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
PERFORM pg_catalog.set_config(
'session_replication_role',
original_replication_role,
true
);
RAISE;
END;
PERFORM pg_catalog.set_config(
'session_replication_role',
original_replication_role,
true
);

FOR dep_index IN
WITH RECURSIVE distance_dependents AS (
SELECT 'pg_operator'::regclass::oid AS classid, distance_op AS objid
UNION
SELECT 'pg_proc'::regclass::oid AS classid, distance_fn AS objid
UNION
SELECT d.classid, d.objid
FROM pg_depend d
JOIN distance_dependents dd
ON d.refclassid = dd.classid
AND d.refobjid = dd.objid
WHERE d.deptype IN ('n', 'a', 'i')
)
SELECT c.oid::regclass AS relid
FROM distance_dependents dd
JOIN pg_class c
ON c.oid = dd.objid
WHERE dd.classid = 'pg_class'::regclass
AND c.relkind = 'i'
LOOP
EXECUTE pg_catalog.format('REINDEX INDEX %s', dep_index.relid);
END LOOP;

FOR dep_matview IN
WITH RECURSIVE distance_dependents AS (
SELECT 'pg_operator'::regclass::oid AS classid, distance_op AS objid
UNION
SELECT 'pg_proc'::regclass::oid AS classid, distance_fn AS objid
UNION
SELECT d.classid, d.objid
FROM pg_depend d
JOIN distance_dependents dd
ON d.refclassid = dd.classid
AND d.refobjid = dd.objid
WHERE d.deptype IN ('n', 'a', 'i')
)
SELECT c.oid::regclass AS relid
FROM distance_dependents dd
JOIN pg_rewrite r
ON r.oid = dd.objid
JOIN pg_class c
ON c.oid = r.ev_class
WHERE dd.classid = 'pg_rewrite'::regclass
AND c.relkind = 'm'
LOOP
EXECUTE pg_catalog.format('REFRESH MATERIALIZED VIEW %s', dep_matview.relid);
END LOOP;
END
$$;
/*
* Do not automatically UPDATE, REINDEX, or REFRESH user-defined objects that
* depend on h3index_distance() or <-> here. Those operations can evaluate
* user-controlled generated-column, expression-index, or materialized-view
* expressions with the privileges of the extension upgrade session.
*
* Administrators should arrange any required post-upgrade maintenance for
* affected objects explicitly, under an appropriate application/object-owner
* role, after reviewing the object definitions.
*/

-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
-- Btree comparator sign fix: existing btree indexes on h3index columns are
Expand Down
11 changes: 11 additions & 0 deletions h3/test/expected/extension.out
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ SELECT
h3_distance_user_wrapper(hex) AS dist
FROM h3_distance_expr_fail_userfn;
ALTER EXTENSION h3 UPDATE TO 'unreleased';
REINDEX INDEX h3_distance_expr_fail_idx;
REINDEX INDEX h3_distance_expr_fail_fn_idx;
REINDEX INDEX h3_distance_expr_fail_userfn_idx;
ALTER TABLE h3_distance_generated_fail DISABLE TRIGGER USER;
UPDATE h3_distance_generated_fail SET hex = hex;
ALTER TABLE h3_distance_generated_fail ENABLE TRIGGER USER;
UPDATE h3_distance_generated_fail_fn SET hex = hex;
UPDATE h3_distance_generated_fail_userfn SET hex = hex;
UPDATE h3_distance_generated_fail_userfn_identity SET hex = hex;
REFRESH MATERIALIZED VIEW h3_distance_matview_fail_fn;
REFRESH MATERIALIZED VIEW h3_distance_matview_fail_userfn;
SELECT (current_setting('server_version_num')::int >= 140000) = EXISTS (
SELECT 1
FROM pg_amproc ap
Expand Down
14 changes: 14 additions & 0 deletions h3/test/sql/extension.sql
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ FROM h3_distance_expr_fail_userfn;

ALTER EXTENSION h3 UPDATE TO 'unreleased';

-- Extension upgrade scripts must not evaluate user-controlled expressions.
-- Rebuild/refresh dependent user objects explicitly after the upgrade.
REINDEX INDEX h3_distance_expr_fail_idx;
REINDEX INDEX h3_distance_expr_fail_fn_idx;
REINDEX INDEX h3_distance_expr_fail_userfn_idx;
ALTER TABLE h3_distance_generated_fail DISABLE TRIGGER USER;
UPDATE h3_distance_generated_fail SET hex = hex;
ALTER TABLE h3_distance_generated_fail ENABLE TRIGGER USER;
UPDATE h3_distance_generated_fail_fn SET hex = hex;
UPDATE h3_distance_generated_fail_userfn SET hex = hex;
UPDATE h3_distance_generated_fail_userfn_identity SET hex = hex;
REFRESH MATERIALIZED VIEW h3_distance_matview_fail_fn;
REFRESH MATERIALIZED VIEW h3_distance_matview_fail_userfn;

SELECT (current_setting('server_version_num')::int >= 140000) = EXISTS (
SELECT 1
FROM pg_amproc ap
Expand Down
Loading