From trac at osgeo.org Mon Jun 1 03:25:23 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 01 Jun 2026 10:25:23 -0000 Subject: [PostGIS] #6078: Improve "raster_overviews" definition Message-ID: <049.6278d5361f978c5eec50a9542aca2cac@osgeo.org> #6078: Improve "raster_overviews" definition --------------------------+--------------------------- Reporter: Laurenz Albe | Owner: pramsey Type: enhancement | Status: new Priority: medium | Milestone: PostGIS 3.6.3 Component: postgis | Version: 3.6.x Keywords: | --------------------------+--------------------------- A customer is having problems with the query {{{ #!sql SELECT o_table_name, overview_factor, o_raster_column, o_table_schema FROM raster_overviews WHERE r_table_schema = 'some_schema' AND r_table_name = 'some_table' AND r_raster_column = 'some_column' ORDER BY overview_factor; }}} The execution plan is as follows: {{{ Sort (cost=17083.32..17083.33 rows=1 width=196) (actual time=9455.757..9455.762 rows=9 loops=1) Sort Key: ((TRIM(BOTH FROM split_part(pg_get_constraintdef(pg_constraint.oid), ','::text, 2)))::integer) Sort Method: quicksort Memory: 27kB Buffers: shared hit=1476736 -> Nested Loop (cost=9.28..17083.31 rows=1 width=196) (actual time=45.400..9455.729 rows=9 loops=1) Join Filter: (c.relnamespace = pg_constraint.connamespace) Buffers: shared hit=1476733 -> Nested Loop (cost=8.86..17081.96 rows=1 width=208) (actual time=1.561..314.613 rows=15113 loops=1) Join Filter: (c.relnamespace = n.oid) Rows Removed by Join Filter: 120840 Buffers: shared hit=146994 -> Nested Loop (cost=8.86..17080.62 rows=1 width=140) (actual time=1.554..268.991 rows=15113 loops=1) Buffers: shared hit=131881 -> Hash Join (cost=8.44..17072.13 rows=16 width=68) (actual time=0.317..160.670 rows=15115 loops=1) Hash Cond: (a.atttypid = t.oid) Buffers: shared hit=10941 -> Seq Scan on pg_attribute a (cost=0.00..15789.68 rows=485268 width=72) (actual time=0.007..125.174 rows=488960 loops=1) Filter: (NOT attisdropped) Buffers: shared hit=10937 -> Hash (cost=8.43..8.43 rows=1 width=4) (actual time=0.020..0.021 rows=1 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB Buffers: shared hit=4 -> Index Scan using pg_type_typname_nsp_index on pg_type t (cost=0.41..8.43 rows=1 width=4) (actual time=0.017..0.018 rows=1 loops=1) Index Cond: (typname = 'raster'::name) Buffers: shared hit=4 -> Index Scan using pg_class_oid_index on pg_class c (cost=0.42..0.53 rows=1 width=72) (actual time=0.007..0.007 rows=1 loops=15115) Index Cond: (oid = a.attrelid) Filter: ((NOT pg_is_other_temp_schema(relnamespace)) AND has_table_privilege(oid, 'SELECT'::text) AND ((relkind)::text = ANY ('{r,v,m,f}'::text[]))) Rows Removed by Filter: 0 Buffers: shared hit=120940 -> Seq Scan on pg_namespace n (cost=0.00..1.15 rows=15 width=68) (actual time=0.001..0.001 rows=9 loops=15113) Buffers: shared hit=15113 -> Index Scan using pg_constraint_conrelid_contypid_conname_index on pg_constraint (cost=0.42..1.33 rows=1 width=12) (actual time=0.604..0.605 rows=0 loops=15113) Index Cond: (conrelid = a.attrelid) Filter: ((pg_get_constraintdef(oid) ~~ '%_overview_constraint(%'::text) AND ((split_part(split_part(pg_get_constraintdef(oid), '''::name'::text, 1), ''''::text, 2))::name = 'some_schema'::name) AND ((split_part(split_part(pg_get_constraintdef(oid), '''::name'::text, 2), ''''::text, 2))::name = 'some_schema'::name) AND ((split_part(split_part(pg_get_constraintdef(oid), '''::name'::text, 3), ''''::text, 2))::name = 'some_column'::name)) Rows Removed by Filter: 12 Buffers: shared hit=1329703 Planning: Buffers: shared hit=387 Planning Time: 1.658 ms Execution Time: 9455.844 ms }}} The problematic part is {{{ -> Hash Join (... rows=16 ...) (actual ... rows=15115 ...) Hash Cond: (a.atttypid = t.oid) -> Seq Scan on pg_attribute a (... rows=485268 ...) (actual ... rows=488960 ...) Filter: (NOT attisdropped) -> Hash (... rows=1 ...) (actual ... rows=1 ...) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Index Scan using pg_type_typname_nsp_index on pg_type t (... rows=1 ...) (actual ... rows=1 ...) Index Cond: (typname = 'raster'::name) }}} The estimates on both {{{pg_attribute}}} and {{{pg_type}}} are correct, but the row count estimate on the join is horribly off. This causes PostgreSQL to choose a nested loop join, which is the cause of the bad performance. The underlying reason for the bad estimate is that PostgreSQL cannot tell at query planning time what the OID of the {{{raster}}} type is going to be, so it cannot use the statistics on {{{pg_attribute}}} that would tell it how many {{{raster}}} columns there are. I looked at the definition of {{{raster_overviews}}}, and the join with {{{pg_type}}} is unnecessary. Instead, you can use the {{{regtype}}} pseudo-type (that has been around since 2002) to directly query {{{pg_attribute}}}. So the following patch would simplify the view definition and would additionally give better estimates: {{{ #!diff diff --git a/raster/rt_pg/rtpostgis.sql.in b/raster/rt_pg/rtpostgis.sql.in index 566a23b86..b02018c4b 100644 --- a/raster/rt_pg/rtpostgis.sql.in +++ b/raster/rt_pg/rtpostgis.sql.in @@ -8448,13 +8448,11 @@ CREATE OR REPLACE VIEW raster_overviews AS FROM pg_class c, pg_attribute a, - pg_type t, pg_namespace n, (SELECT connamespace, conrelid, conkey, pg_get_constraintdef(oid) As consrc FROM pg_constraint) AS s - WHERE t.typname = 'raster'::name - AND a.attisdropped = false - AND a.atttypid = t.oid + WHERE a.attisdropped = false + AND a.atttypid = 'raster'::regtype AND a.attrelid = c.oid AND c.relnamespace = n.oid AND c.relkind = ANY(ARRAY['r'::char, 'v'::char, 'm'::char, 'f'::char]) }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 1 07:31:35 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 01 Jun 2026 14:31:35 -0000 Subject: [PostGIS] #6078: Improve "raster_overviews" definition In-Reply-To: <049.6278d5361f978c5eec50a9542aca2cac@osgeo.org> References: <049.6278d5361f978c5eec50a9542aca2cac@osgeo.org> Message-ID: <064.ef5225a19915c8d4945fa78fc6ee98cd@osgeo.org> #6078: Improve "raster_overviews" definition ---------------------------+--------------------------- Reporter: Laurenz Albe | Owner: pramsey Type: enhancement | Status: new Priority: medium | Milestone: PostGIS 3.6.3 Component: postgis | Version: 3.6.x Resolution: | Keywords: ---------------------------+--------------------------- Comment (by pramsey): I'm all in favour of smaller and faster. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Mon Jun 1 10:34:17 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 1 Jun 2026 10:34:17 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-494-g7761433a5 Message-ID: <20260601173417.D345E1B6B89@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 7761433a55ce7445282798f018d57819f44dc319 (commit) from 21949699858347065db080de31687841ce834ea0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 7761433a55ce7445282798f018d57819f44dc319 Author: Paul Ramsey Date: Mon Jun 1 10:19:06 2026 -0700 Improve "raster_overviews" efficiency, closes #6078, (from Laurenz Albe) diff --git a/raster/rt_pg/rtpostgis.sql.in b/raster/rt_pg/rtpostgis.sql.in index 566a23b86..5a1bfc085 100644 --- a/raster/rt_pg/rtpostgis.sql.in +++ b/raster/rt_pg/rtpostgis.sql.in @@ -8344,11 +8344,9 @@ CREATE OR REPLACE VIEW raster_columns AS FROM pg_class c, pg_attribute a, - pg_type t, pg_namespace n - WHERE t.typname = 'raster'::name - AND a.attisdropped = false - AND a.atttypid = t.oid + WHERE a.attisdropped = false + AND a.atttypid = 'raster'::regtype AND a.attrelid = c.oid AND c.relnamespace = n.oid AND c.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'm'::"char", 'f'::"char", 'p'::"char"] ) ----------------------------------------------------------------------- Summary of changes: raster/rt_pg/rtpostgis.sql.in | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Mon Jun 1 10:34:27 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 01 Jun 2026 17:34:27 -0000 Subject: [PostGIS] #6078: Improve "raster_overviews" definition In-Reply-To: <049.6278d5361f978c5eec50a9542aca2cac@osgeo.org> References: <049.6278d5361f978c5eec50a9542aca2cac@osgeo.org> Message-ID: <064.18ee488f7e3b22fba9b86ac7643b1903@osgeo.org> #6078: Improve "raster_overviews" definition ---------------------------+--------------------------- Reporter: Laurenz Albe | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.6.3 Component: postgis | Version: 3.6.x Resolution: fixed | Keywords: ---------------------------+--------------------------- Changes (by Paul Ramsey ): * resolution: => fixed * status: new => closed Comment: In [changeset:"7761433a55ce7445282798f018d57819f44dc319/git" 7761433a/git]: {{{#!CommitTicketReference repository="git" revision="7761433a55ce7445282798f018d57819f44dc319" Improve "raster_overviews" efficiency, closes #6078, (from Laurenz Albe) }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Tue Jun 2 00:40:05 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 02 Jun 2026 07:40:05 -0000 Subject: [PostGIS] #6078: Improve "raster_overviews" definition In-Reply-To: <049.6278d5361f978c5eec50a9542aca2cac@osgeo.org> References: <049.6278d5361f978c5eec50a9542aca2cac@osgeo.org> Message-ID: <064.4d289ffbca4a7040e027c6cede403803@osgeo.org> #6078: Improve "raster_overviews" definition ---------------------------+--------------------------- Reporter: Laurenz Albe | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.6.3 Component: postgis | Version: 3.6.x Resolution: fixed | Keywords: ---------------------------+--------------------------- Comment (by Laurenz Albe): Thank you for the quick reaction! -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 2 15:58:20 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 2 Jun 2026 15:58:20 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.3 updated. 3.3.10-6-g378c1bb3f Message-ID: <20260602225820.4D0EF1C1B89@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.3 has been updated via 378c1bb3f4626abc30b4ef4d8289ab613d1034b8 (commit) from 13118cab3d52b8fe39f84924c5b5e96ee8ee73e8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 378c1bb3f4626abc30b4ef4d8289ab613d1034b8 Author: Paul Ramsey Date: Tue Jun 2 15:52:50 2026 -0700 Prefix operators to avoid extension operator injection diff --git a/extras/tiger_geocoder/geocode/other_helper_functions.sql b/extras/tiger_geocoder/geocode/other_helper_functions.sql index c7303e7be..c8cf91cec 100644 --- a/extras/tiger_geocoder/geocode/other_helper_functions.sql +++ b/extras/tiger_geocoder/geocode/other_helper_functions.sql @@ -63,7 +63,7 @@ SELECT array_to_string(ARRAY( -- create unique index on faces for tfid seems to perform better -- SELECT 'CREATE UNIQUE INDEX uidx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('tfid') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -74,7 +74,7 @@ UNION ALL -- basic btree regular indexes SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('countyfp', 'tlid', 'tfidl', 'tfidr', 'tfid', 'zip', 'placefp', 'cousubfp') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -85,7 +85,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') AND (NOT UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || '_gist ON ' || c.table_schema || '.' || c.table_name || ' USING gist(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('the_geom', 'geom') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -96,7 +96,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_snd_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(soundex(' || c.column_name || '));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'place', 'city') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -109,7 +109,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_lower_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(lower(' || c.column_name || '));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'place', 'city') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -121,7 +121,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_least_address' || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(least_hn(fromhn, tohn));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name LIKE '%addr' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND table_name LIKE '%addr' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('fromhn') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -132,7 +132,7 @@ WHERE i.tablename IS NULL UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_l' || c.column_name || '_var_ops' || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(lower(' || c.column_name || ') varchar_pattern_ops);' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND (table_name LIKE '%featnames' or table_name LIKE '%place' or table_name LIKE '%zip_lookup_base' or table_name LIKE '%zip_state_loc') AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND (table_name LIKE '%featnames' or table_name LIKE '%place' or table_name LIKE '%zip_lookup_base' or table_name LIKE '%zip_state_loc') AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'city', 'place', 'fullname') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -154,11 +154,11 @@ WHERE i.tablename IS NULL **/ UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ' );' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name LIKE '%edges' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND table_name LIKE '%edges' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('zipl', 'zipr') ) AS c - ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) + ON (t.table_name OPERATOR(pg_catalog.=) c.table_name AND t.table_schema OPERATOR(pg_catalog.=) c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON - (i.tablename = c.table_name AND i.schemaname = c.table_schema + (i.tablename OPERATOR(pg_catalog.=) c.table_name AND i.schemaname OPERATOR(pg_catalog.=) c.table_schema AND indexdef LIKE '%btree%(' || c.column_name || '%)%') WHERE i.tablename IS NULL @@ -226,7 +226,7 @@ DROP TABLE dup; CREATE INDEX idx_' || t.table_schema || '_' || t.table_name || '_tlid ' || ' ON ' || t.table_schema || '.' || t.table_name || ' USING btree(tlid); ' As drop_sql_create_index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND (table_name LIKE '%featnames' ) AND table_schema IN('tiger','tiger_data')) As t + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND (table_name LIKE '%featnames' ) AND table_schema IN('tiger','tiger_data')) As t LEFT JOIN pg_catalog.pg_indexes i ON (i.tablename = t.table_name AND i.schemaname = t.table_schema AND indexdef LIKE '%btree%(%tlid%') diff --git a/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql b/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql index da6fc91a9..9f01969bc 100644 --- a/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql +++ b/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql @@ -8,35 +8,35 @@ $$ DECLARE var_temp text; BEGIN var_temp := tiger.SetSearchPathForInstall('tiger'); /** set set search path to have tiger in front **/ - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_gaz') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_gaz') THEN CREATE TABLE pagc_gaz (id serial NOT NULL primary key ,seq integer ,word text, stdword text, token integer,is_custom boolean NOT NULL default true); GRANT SELECT ON pagc_gaz TO public; ELSE -- Insist on invoking Postgres logic of owning table by extension. This prevent attacks like CVE-2022-2625. CREATE TABLE IF NOT EXISTS pagc_gaz (id serial NOT NULL primary key ,seq integer ,word text, stdword text, token integer,is_custom boolean NOT NULL default true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_lex') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_lex') THEN CREATE TABLE pagc_lex (id serial NOT NULL primary key,seq integer,word text,stdword text,token integer,is_custom boolean NOT NULL default true); GRANT SELECT ON pagc_lex TO public; ELSE -- Same as above. CREATE TABLE IF NOT EXISTS pagc_lex (id serial NOT NULL primary key,seq integer,word text,stdword text,token integer,is_custom boolean NOT NULL default true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_rules') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_rules') THEN CREATE TABLE pagc_rules (id serial NOT NULL primary key,rule text, is_custom boolean DEFAULT true); GRANT SELECT ON pagc_rules TO public; ELSE -- Same as above. CREATE TABLE IF NOT EXISTS pagc_rules (id serial NOT NULL primary key,rule text, is_custom boolean DEFAULT true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_gaz' AND data_type='text') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_gaz' AND data_type OPERATOR(pg_catalog.=) 'text') THEN -- its probably old table structure change type of lex and gaz columns ALTER TABLE tiger.pagc_lex ALTER COLUMN word TYPE text; ALTER TABLE tiger.pagc_lex ALTER COLUMN stdword TYPE text; ALTER TABLE tiger.pagc_gaz ALTER COLUMN word TYPE text; ALTER TABLE tiger.pagc_gaz ALTER COLUMN stdword TYPE text; END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_rules' AND column_name = 'is_custom' ) THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_rules' AND column_name OPERATOR(pg_catalog.=) 'is_custom' ) THEN -- its probably old table structure add column ALTER TABLE tiger.pagc_rules ADD COLUMN is_custom boolean NOT NULL DEFAULT false; END IF; @@ -8193,4 +8193,4 @@ UPDATE tiger.pagc_rules SET is_custom = false where id < 10000; -- after insert we need to set back to true so all -- user inputs are treated as custom ALTER TABLE tiger.pagc_rules ALTER COLUMN is_custom SET DEFAULT true; -SELECT pg_catalog.setval('pagc_rules_id_seq', 10000, true); \ No newline at end of file +SELECT pg_catalog.setval('pagc_rules_id_seq', 10000, true); ----------------------------------------------------------------------- Summary of changes: .../geocode/other_helper_functions.sql | 22 +++++++++++----------- .../tiger_geocoder/pagc_normalize/pagc_tables.sql | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Tue Jun 2 15:58:39 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 2 Jun 2026 15:58:39 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.4 updated. 3.4.6-6-gfa01ecedb Message-ID: <20260602225839.8F9A91C1B9C@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.4 has been updated via fa01ecedb2ba070b429246dac7226f79057a7c0d (commit) from 4761b8986edf899d1e7b61a85f6c8bbbfad8771f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit fa01ecedb2ba070b429246dac7226f79057a7c0d Author: Paul Ramsey Date: Tue Jun 2 14:00:56 2026 -0700 Prefix operators to avoid extension operator injection diff --git a/extras/tiger_geocoder/geocode/other_helper_functions.sql b/extras/tiger_geocoder/geocode/other_helper_functions.sql index c7303e7be..c8cf91cec 100644 --- a/extras/tiger_geocoder/geocode/other_helper_functions.sql +++ b/extras/tiger_geocoder/geocode/other_helper_functions.sql @@ -63,7 +63,7 @@ SELECT array_to_string(ARRAY( -- create unique index on faces for tfid seems to perform better -- SELECT 'CREATE UNIQUE INDEX uidx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('tfid') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -74,7 +74,7 @@ UNION ALL -- basic btree regular indexes SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('countyfp', 'tlid', 'tfidl', 'tfidr', 'tfid', 'zip', 'placefp', 'cousubfp') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -85,7 +85,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') AND (NOT UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || '_gist ON ' || c.table_schema || '.' || c.table_name || ' USING gist(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('the_geom', 'geom') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -96,7 +96,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_snd_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(soundex(' || c.column_name || '));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'place', 'city') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -109,7 +109,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_lower_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(lower(' || c.column_name || '));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'place', 'city') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -121,7 +121,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_least_address' || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(least_hn(fromhn, tohn));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name LIKE '%addr' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND table_name LIKE '%addr' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('fromhn') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -132,7 +132,7 @@ WHERE i.tablename IS NULL UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_l' || c.column_name || '_var_ops' || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(lower(' || c.column_name || ') varchar_pattern_ops);' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND (table_name LIKE '%featnames' or table_name LIKE '%place' or table_name LIKE '%zip_lookup_base' or table_name LIKE '%zip_state_loc') AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND (table_name LIKE '%featnames' or table_name LIKE '%place' or table_name LIKE '%zip_lookup_base' or table_name LIKE '%zip_state_loc') AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'city', 'place', 'fullname') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -154,11 +154,11 @@ WHERE i.tablename IS NULL **/ UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ' );' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name LIKE '%edges' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND table_name LIKE '%edges' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('zipl', 'zipr') ) AS c - ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) + ON (t.table_name OPERATOR(pg_catalog.=) c.table_name AND t.table_schema OPERATOR(pg_catalog.=) c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON - (i.tablename = c.table_name AND i.schemaname = c.table_schema + (i.tablename OPERATOR(pg_catalog.=) c.table_name AND i.schemaname OPERATOR(pg_catalog.=) c.table_schema AND indexdef LIKE '%btree%(' || c.column_name || '%)%') WHERE i.tablename IS NULL @@ -226,7 +226,7 @@ DROP TABLE dup; CREATE INDEX idx_' || t.table_schema || '_' || t.table_name || '_tlid ' || ' ON ' || t.table_schema || '.' || t.table_name || ' USING btree(tlid); ' As drop_sql_create_index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND (table_name LIKE '%featnames' ) AND table_schema IN('tiger','tiger_data')) As t + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND (table_name LIKE '%featnames' ) AND table_schema IN('tiger','tiger_data')) As t LEFT JOIN pg_catalog.pg_indexes i ON (i.tablename = t.table_name AND i.schemaname = t.table_schema AND indexdef LIKE '%btree%(%tlid%') diff --git a/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql b/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql index da6fc91a9..9f01969bc 100644 --- a/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql +++ b/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql @@ -8,35 +8,35 @@ $$ DECLARE var_temp text; BEGIN var_temp := tiger.SetSearchPathForInstall('tiger'); /** set set search path to have tiger in front **/ - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_gaz') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_gaz') THEN CREATE TABLE pagc_gaz (id serial NOT NULL primary key ,seq integer ,word text, stdword text, token integer,is_custom boolean NOT NULL default true); GRANT SELECT ON pagc_gaz TO public; ELSE -- Insist on invoking Postgres logic of owning table by extension. This prevent attacks like CVE-2022-2625. CREATE TABLE IF NOT EXISTS pagc_gaz (id serial NOT NULL primary key ,seq integer ,word text, stdword text, token integer,is_custom boolean NOT NULL default true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_lex') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_lex') THEN CREATE TABLE pagc_lex (id serial NOT NULL primary key,seq integer,word text,stdword text,token integer,is_custom boolean NOT NULL default true); GRANT SELECT ON pagc_lex TO public; ELSE -- Same as above. CREATE TABLE IF NOT EXISTS pagc_lex (id serial NOT NULL primary key,seq integer,word text,stdword text,token integer,is_custom boolean NOT NULL default true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_rules') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_rules') THEN CREATE TABLE pagc_rules (id serial NOT NULL primary key,rule text, is_custom boolean DEFAULT true); GRANT SELECT ON pagc_rules TO public; ELSE -- Same as above. CREATE TABLE IF NOT EXISTS pagc_rules (id serial NOT NULL primary key,rule text, is_custom boolean DEFAULT true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_gaz' AND data_type='text') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_gaz' AND data_type OPERATOR(pg_catalog.=) 'text') THEN -- its probably old table structure change type of lex and gaz columns ALTER TABLE tiger.pagc_lex ALTER COLUMN word TYPE text; ALTER TABLE tiger.pagc_lex ALTER COLUMN stdword TYPE text; ALTER TABLE tiger.pagc_gaz ALTER COLUMN word TYPE text; ALTER TABLE tiger.pagc_gaz ALTER COLUMN stdword TYPE text; END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_rules' AND column_name = 'is_custom' ) THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_rules' AND column_name OPERATOR(pg_catalog.=) 'is_custom' ) THEN -- its probably old table structure add column ALTER TABLE tiger.pagc_rules ADD COLUMN is_custom boolean NOT NULL DEFAULT false; END IF; @@ -8193,4 +8193,4 @@ UPDATE tiger.pagc_rules SET is_custom = false where id < 10000; -- after insert we need to set back to true so all -- user inputs are treated as custom ALTER TABLE tiger.pagc_rules ALTER COLUMN is_custom SET DEFAULT true; -SELECT pg_catalog.setval('pagc_rules_id_seq', 10000, true); \ No newline at end of file +SELECT pg_catalog.setval('pagc_rules_id_seq', 10000, true); ----------------------------------------------------------------------- Summary of changes: .../geocode/other_helper_functions.sql | 22 +++++++++++----------- .../tiger_geocoder/pagc_normalize/pagc_tables.sql | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Tue Jun 2 15:58:45 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 2 Jun 2026 15:58:45 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.5 updated. 3.5.6-6-g05d7932ad Message-ID: <20260602225845.BDD8C1C19C8@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.5 has been updated via 05d7932adf91edd05fc6e891d6b067f193379218 (commit) from f72686cca639ecb373cb82eaeebb3e9ef9022b84 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 05d7932adf91edd05fc6e891d6b067f193379218 Author: Paul Ramsey Date: Tue Jun 2 13:59:25 2026 -0700 Prefix operators to avoid extension operator injection diff --git a/extras/tiger_geocoder/geocode/other_helper_functions.sql b/extras/tiger_geocoder/geocode/other_helper_functions.sql index 41513bc1e..21dc92cda 100644 --- a/extras/tiger_geocoder/geocode/other_helper_functions.sql +++ b/extras/tiger_geocoder/geocode/other_helper_functions.sql @@ -63,7 +63,7 @@ SELECT array_to_string(ARRAY( -- create unique index on faces for tfid seems to perform better -- SELECT 'CREATE UNIQUE INDEX uidx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('tfid') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -74,7 +74,7 @@ UNION ALL -- basic btree regular indexes SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('countyfp', 'tlid', 'tfidl', 'tfidr', 'tfid', 'zip', 'placefp', 'cousubfp') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -85,7 +85,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') AND (NOT UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || '_gist ON ' || c.table_schema || '.' || c.table_name || ' USING gist(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('the_geom', 'geom') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -96,7 +96,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_snd_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(soundex(' || c.column_name || '));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'place', 'city') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -109,7 +109,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_lower_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(lower(' || c.column_name || '));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'place', 'city') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -121,7 +121,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_least_address' || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(least_hn(fromhn, tohn));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name LIKE '%addr' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND table_name LIKE '%addr' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('fromhn') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -132,7 +132,7 @@ WHERE i.tablename IS NULL UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_l' || c.column_name || '_var_ops' || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(lower(' || c.column_name || ') varchar_pattern_ops);' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND (table_name LIKE '%featnames' or table_name LIKE '%place' or table_name LIKE '%zip_lookup_base' or table_name LIKE '%zip_state_loc') AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND (table_name LIKE '%featnames' or table_name LIKE '%place' or table_name LIKE '%zip_lookup_base' or table_name LIKE '%zip_state_loc') AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'city', 'place', 'fullname') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -154,11 +154,11 @@ WHERE i.tablename IS NULL **/ UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ' );' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name LIKE '%edges' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND table_name LIKE '%edges' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('zipl', 'zipr') ) AS c - ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) + ON (t.table_name OPERATOR(pg_catalog.=) c.table_name AND t.table_schema OPERATOR(pg_catalog.=) c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON - (i.tablename = c.table_name AND i.schemaname = c.table_schema + (i.tablename OPERATOR(pg_catalog.=) c.table_name AND i.schemaname OPERATOR(pg_catalog.=) c.table_schema AND indexdef LIKE '%btree%(' || c.column_name || '%)%') WHERE i.tablename IS NULL @@ -226,7 +226,7 @@ DROP TABLE dup; CREATE INDEX idx_' || t.table_schema || '_' || t.table_name || '_tlid ' || ' ON ' || t.table_schema || '.' || t.table_name || ' USING btree(tlid); ' As drop_sql_create_index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND (table_name LIKE '%featnames' ) AND table_schema IN('tiger','tiger_data')) As t + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND (table_name LIKE '%featnames' ) AND table_schema IN('tiger','tiger_data')) As t LEFT JOIN pg_catalog.pg_indexes i ON (i.tablename = t.table_name AND i.schemaname = t.table_schema AND indexdef LIKE '%btree%(%tlid%') diff --git a/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql b/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql index da6fc91a9..9f01969bc 100644 --- a/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql +++ b/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql @@ -8,35 +8,35 @@ $$ DECLARE var_temp text; BEGIN var_temp := tiger.SetSearchPathForInstall('tiger'); /** set set search path to have tiger in front **/ - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_gaz') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_gaz') THEN CREATE TABLE pagc_gaz (id serial NOT NULL primary key ,seq integer ,word text, stdword text, token integer,is_custom boolean NOT NULL default true); GRANT SELECT ON pagc_gaz TO public; ELSE -- Insist on invoking Postgres logic of owning table by extension. This prevent attacks like CVE-2022-2625. CREATE TABLE IF NOT EXISTS pagc_gaz (id serial NOT NULL primary key ,seq integer ,word text, stdword text, token integer,is_custom boolean NOT NULL default true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_lex') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_lex') THEN CREATE TABLE pagc_lex (id serial NOT NULL primary key,seq integer,word text,stdword text,token integer,is_custom boolean NOT NULL default true); GRANT SELECT ON pagc_lex TO public; ELSE -- Same as above. CREATE TABLE IF NOT EXISTS pagc_lex (id serial NOT NULL primary key,seq integer,word text,stdword text,token integer,is_custom boolean NOT NULL default true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_rules') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_rules') THEN CREATE TABLE pagc_rules (id serial NOT NULL primary key,rule text, is_custom boolean DEFAULT true); GRANT SELECT ON pagc_rules TO public; ELSE -- Same as above. CREATE TABLE IF NOT EXISTS pagc_rules (id serial NOT NULL primary key,rule text, is_custom boolean DEFAULT true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_gaz' AND data_type='text') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_gaz' AND data_type OPERATOR(pg_catalog.=) 'text') THEN -- its probably old table structure change type of lex and gaz columns ALTER TABLE tiger.pagc_lex ALTER COLUMN word TYPE text; ALTER TABLE tiger.pagc_lex ALTER COLUMN stdword TYPE text; ALTER TABLE tiger.pagc_gaz ALTER COLUMN word TYPE text; ALTER TABLE tiger.pagc_gaz ALTER COLUMN stdword TYPE text; END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_rules' AND column_name = 'is_custom' ) THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_rules' AND column_name OPERATOR(pg_catalog.=) 'is_custom' ) THEN -- its probably old table structure add column ALTER TABLE tiger.pagc_rules ADD COLUMN is_custom boolean NOT NULL DEFAULT false; END IF; @@ -8193,4 +8193,4 @@ UPDATE tiger.pagc_rules SET is_custom = false where id < 10000; -- after insert we need to set back to true so all -- user inputs are treated as custom ALTER TABLE tiger.pagc_rules ALTER COLUMN is_custom SET DEFAULT true; -SELECT pg_catalog.setval('pagc_rules_id_seq', 10000, true); \ No newline at end of file +SELECT pg_catalog.setval('pagc_rules_id_seq', 10000, true); ----------------------------------------------------------------------- Summary of changes: .../geocode/other_helper_functions.sql | 22 +++++++++++----------- .../tiger_geocoder/pagc_normalize/pagc_tables.sql | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Tue Jun 2 15:59:12 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 2 Jun 2026 15:59:12 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.6 updated. 3.6.3-11-gbc9704020 Message-ID: <20260602225912.8957E1C184C@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.6 has been updated via bc9704020c519f3b2fccf4376bd2bf4f85236880 (commit) from 19df3b29a1c5578dcbb8ff15b4c206aada066c16 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit bc9704020c519f3b2fccf4376bd2bf4f85236880 Author: Paul Ramsey Date: Tue Jun 2 13:58:26 2026 -0700 Prefix operators to avoid extension operator injection diff --git a/extras/tiger_geocoder/geocode/other_helper_functions.sql b/extras/tiger_geocoder/geocode/other_helper_functions.sql index 41513bc1e..21dc92cda 100644 --- a/extras/tiger_geocoder/geocode/other_helper_functions.sql +++ b/extras/tiger_geocoder/geocode/other_helper_functions.sql @@ -63,7 +63,7 @@ SELECT array_to_string(ARRAY( -- create unique index on faces for tfid seems to perform better -- SELECT 'CREATE UNIQUE INDEX uidx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('tfid') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -74,7 +74,7 @@ UNION ALL -- basic btree regular indexes SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('countyfp', 'tlid', 'tfidl', 'tfidr', 'tfid', 'zip', 'placefp', 'cousubfp') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -85,7 +85,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') AND (NOT UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || '_gist ON ' || c.table_schema || '.' || c.table_name || ' USING gist(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('the_geom', 'geom') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -96,7 +96,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_snd_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(soundex(' || c.column_name || '));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'place', 'city') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -109,7 +109,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_lower_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(lower(' || c.column_name || '));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'place', 'city') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -121,7 +121,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_least_address' || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(least_hn(fromhn, tohn));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name LIKE '%addr' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND table_name LIKE '%addr' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('fromhn') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -132,7 +132,7 @@ WHERE i.tablename IS NULL UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_l' || c.column_name || '_var_ops' || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(lower(' || c.column_name || ') varchar_pattern_ops);' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND (table_name LIKE '%featnames' or table_name LIKE '%place' or table_name LIKE '%zip_lookup_base' or table_name LIKE '%zip_state_loc') AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND (table_name LIKE '%featnames' or table_name LIKE '%place' or table_name LIKE '%zip_lookup_base' or table_name LIKE '%zip_state_loc') AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'city', 'place', 'fullname') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -154,11 +154,11 @@ WHERE i.tablename IS NULL **/ UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ' );' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name LIKE '%edges' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND table_name LIKE '%edges' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('zipl', 'zipr') ) AS c - ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) + ON (t.table_name OPERATOR(pg_catalog.=) c.table_name AND t.table_schema OPERATOR(pg_catalog.=) c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON - (i.tablename = c.table_name AND i.schemaname = c.table_schema + (i.tablename OPERATOR(pg_catalog.=) c.table_name AND i.schemaname OPERATOR(pg_catalog.=) c.table_schema AND indexdef LIKE '%btree%(' || c.column_name || '%)%') WHERE i.tablename IS NULL @@ -226,7 +226,7 @@ DROP TABLE dup; CREATE INDEX idx_' || t.table_schema || '_' || t.table_name || '_tlid ' || ' ON ' || t.table_schema || '.' || t.table_name || ' USING btree(tlid); ' As drop_sql_create_index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND (table_name LIKE '%featnames' ) AND table_schema IN('tiger','tiger_data')) As t + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND (table_name LIKE '%featnames' ) AND table_schema IN('tiger','tiger_data')) As t LEFT JOIN pg_catalog.pg_indexes i ON (i.tablename = t.table_name AND i.schemaname = t.table_schema AND indexdef LIKE '%btree%(%tlid%') diff --git a/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql b/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql index da6fc91a9..9f01969bc 100644 --- a/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql +++ b/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql @@ -8,35 +8,35 @@ $$ DECLARE var_temp text; BEGIN var_temp := tiger.SetSearchPathForInstall('tiger'); /** set set search path to have tiger in front **/ - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_gaz') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_gaz') THEN CREATE TABLE pagc_gaz (id serial NOT NULL primary key ,seq integer ,word text, stdword text, token integer,is_custom boolean NOT NULL default true); GRANT SELECT ON pagc_gaz TO public; ELSE -- Insist on invoking Postgres logic of owning table by extension. This prevent attacks like CVE-2022-2625. CREATE TABLE IF NOT EXISTS pagc_gaz (id serial NOT NULL primary key ,seq integer ,word text, stdword text, token integer,is_custom boolean NOT NULL default true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_lex') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_lex') THEN CREATE TABLE pagc_lex (id serial NOT NULL primary key,seq integer,word text,stdword text,token integer,is_custom boolean NOT NULL default true); GRANT SELECT ON pagc_lex TO public; ELSE -- Same as above. CREATE TABLE IF NOT EXISTS pagc_lex (id serial NOT NULL primary key,seq integer,word text,stdword text,token integer,is_custom boolean NOT NULL default true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_rules') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_rules') THEN CREATE TABLE pagc_rules (id serial NOT NULL primary key,rule text, is_custom boolean DEFAULT true); GRANT SELECT ON pagc_rules TO public; ELSE -- Same as above. CREATE TABLE IF NOT EXISTS pagc_rules (id serial NOT NULL primary key,rule text, is_custom boolean DEFAULT true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_gaz' AND data_type='text') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_gaz' AND data_type OPERATOR(pg_catalog.=) 'text') THEN -- its probably old table structure change type of lex and gaz columns ALTER TABLE tiger.pagc_lex ALTER COLUMN word TYPE text; ALTER TABLE tiger.pagc_lex ALTER COLUMN stdword TYPE text; ALTER TABLE tiger.pagc_gaz ALTER COLUMN word TYPE text; ALTER TABLE tiger.pagc_gaz ALTER COLUMN stdword TYPE text; END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_rules' AND column_name = 'is_custom' ) THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_rules' AND column_name OPERATOR(pg_catalog.=) 'is_custom' ) THEN -- its probably old table structure add column ALTER TABLE tiger.pagc_rules ADD COLUMN is_custom boolean NOT NULL DEFAULT false; END IF; @@ -8193,4 +8193,4 @@ UPDATE tiger.pagc_rules SET is_custom = false where id < 10000; -- after insert we need to set back to true so all -- user inputs are treated as custom ALTER TABLE tiger.pagc_rules ALTER COLUMN is_custom SET DEFAULT true; -SELECT pg_catalog.setval('pagc_rules_id_seq', 10000, true); \ No newline at end of file +SELECT pg_catalog.setval('pagc_rules_id_seq', 10000, true); ----------------------------------------------------------------------- Summary of changes: .../geocode/other_helper_functions.sql | 22 +++++++++++----------- .../tiger_geocoder/pagc_normalize/pagc_tables.sql | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Tue Jun 2 16:13:33 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 2 Jun 2026 16:13:33 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.2 updated. 3.2.10-4-g94610531f Message-ID: <20260602231334.23C561C1A0D@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.2 has been updated via 94610531f03c30c733853704569ba1bd963151d8 (commit) from 32b6f6810ab57fa27bbe3e3f9d3bcb1938e29b4d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 94610531f03c30c733853704569ba1bd963151d8 Author: Paul Ramsey Date: Tue Jun 2 16:13:25 2026 -0700 Prefix operators to avoid extension operator injection diff --git a/extras/tiger_geocoder/geocode/other_helper_functions.sql b/extras/tiger_geocoder/geocode/other_helper_functions.sql index c7303e7be..c8cf91cec 100644 --- a/extras/tiger_geocoder/geocode/other_helper_functions.sql +++ b/extras/tiger_geocoder/geocode/other_helper_functions.sql @@ -63,7 +63,7 @@ SELECT array_to_string(ARRAY( -- create unique index on faces for tfid seems to perform better -- SELECT 'CREATE UNIQUE INDEX uidx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('tfid') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -74,7 +74,7 @@ UNION ALL -- basic btree regular indexes SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('countyfp', 'tlid', 'tfidl', 'tfidr', 'tfid', 'zip', 'placefp', 'cousubfp') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -85,7 +85,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') AND (NOT UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || '_gist ON ' || c.table_schema || '.' || c.table_name || ' USING gist(' || c.column_name || ');' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('the_geom', 'geom') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -96,7 +96,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_snd_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(soundex(' || c.column_name || '));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'place', 'city') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -109,7 +109,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_lower_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(lower(' || c.column_name || '));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE') As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE') As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'place', 'city') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -121,7 +121,7 @@ WHERE i.tablename IS NULL AND c.table_schema IN('tiger','tiger_data') UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_least_address' || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(least_hn(fromhn, tohn));' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name LIKE '%addr' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND table_name LIKE '%addr' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('fromhn') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -132,7 +132,7 @@ WHERE i.tablename IS NULL UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_l' || c.column_name || '_var_ops' || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(lower(' || c.column_name || ') varchar_pattern_ops);' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND (table_name LIKE '%featnames' or table_name LIKE '%place' or table_name LIKE '%zip_lookup_base' or table_name LIKE '%zip_state_loc') AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND (table_name LIKE '%featnames' or table_name LIKE '%place' or table_name LIKE '%zip_lookup_base' or table_name LIKE '%zip_state_loc') AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('name', 'city', 'place', 'fullname') ) AS c ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON @@ -154,11 +154,11 @@ WHERE i.tablename IS NULL **/ UNION ALL SELECT 'CREATE INDEX idx_' || c.table_schema || '_' || c.table_name || '_' || c.column_name || ' ON ' || c.table_schema || '.' || c.table_name || ' USING btree(' || c.column_name || ' );' As index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name LIKE '%edges' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND table_name LIKE '%edges' AND table_schema IN('tiger','tiger_data')) As t INNER JOIN (SELECT * FROM information_schema.columns WHERE column_name IN('zipl', 'zipr') ) AS c - ON (t.table_name = c.table_name AND t.table_schema = c.table_schema) + ON (t.table_name OPERATOR(pg_catalog.=) c.table_name AND t.table_schema OPERATOR(pg_catalog.=) c.table_schema) LEFT JOIN pg_catalog.pg_indexes i ON - (i.tablename = c.table_name AND i.schemaname = c.table_schema + (i.tablename OPERATOR(pg_catalog.=) c.table_name AND i.schemaname OPERATOR(pg_catalog.=) c.table_schema AND indexdef LIKE '%btree%(' || c.column_name || '%)%') WHERE i.tablename IS NULL @@ -226,7 +226,7 @@ DROP TABLE dup; CREATE INDEX idx_' || t.table_schema || '_' || t.table_name || '_tlid ' || ' ON ' || t.table_schema || '.' || t.table_name || ' USING btree(tlid); ' As drop_sql_create_index FROM (SELECT table_name, table_schema FROM - information_schema.tables WHERE table_type = 'BASE TABLE' AND (table_name LIKE '%featnames' ) AND table_schema IN('tiger','tiger_data')) As t + information_schema.tables WHERE table_type OPERATOR(pg_catalog.=) 'BASE TABLE' AND (table_name LIKE '%featnames' ) AND table_schema IN('tiger','tiger_data')) As t LEFT JOIN pg_catalog.pg_indexes i ON (i.tablename = t.table_name AND i.schemaname = t.table_schema AND indexdef LIKE '%btree%(%tlid%') diff --git a/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql b/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql index da6fc91a9..9f01969bc 100644 --- a/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql +++ b/extras/tiger_geocoder/pagc_normalize/pagc_tables.sql @@ -8,35 +8,35 @@ $$ DECLARE var_temp text; BEGIN var_temp := tiger.SetSearchPathForInstall('tiger'); /** set set search path to have tiger in front **/ - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_gaz') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_gaz') THEN CREATE TABLE pagc_gaz (id serial NOT NULL primary key ,seq integer ,word text, stdword text, token integer,is_custom boolean NOT NULL default true); GRANT SELECT ON pagc_gaz TO public; ELSE -- Insist on invoking Postgres logic of owning table by extension. This prevent attacks like CVE-2022-2625. CREATE TABLE IF NOT EXISTS pagc_gaz (id serial NOT NULL primary key ,seq integer ,word text, stdword text, token integer,is_custom boolean NOT NULL default true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_lex') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_lex') THEN CREATE TABLE pagc_lex (id serial NOT NULL primary key,seq integer,word text,stdword text,token integer,is_custom boolean NOT NULL default true); GRANT SELECT ON pagc_lex TO public; ELSE -- Same as above. CREATE TABLE IF NOT EXISTS pagc_lex (id serial NOT NULL primary key,seq integer,word text,stdword text,token integer,is_custom boolean NOT NULL default true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_rules') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_rules') THEN CREATE TABLE pagc_rules (id serial NOT NULL primary key,rule text, is_custom boolean DEFAULT true); GRANT SELECT ON pagc_rules TO public; ELSE -- Same as above. CREATE TABLE IF NOT EXISTS pagc_rules (id serial NOT NULL primary key,rule text, is_custom boolean DEFAULT true); END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_gaz' AND data_type='text') THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_gaz' AND data_type OPERATOR(pg_catalog.=) 'text') THEN -- its probably old table structure change type of lex and gaz columns ALTER TABLE tiger.pagc_lex ALTER COLUMN word TYPE text; ALTER TABLE tiger.pagc_lex ALTER COLUMN stdword TYPE text; ALTER TABLE tiger.pagc_gaz ALTER COLUMN word TYPE text; ALTER TABLE tiger.pagc_gaz ALTER COLUMN stdword TYPE text; END IF; - IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema = 'tiger' AND table_name = 'pagc_rules' AND column_name = 'is_custom' ) THEN + IF NOT EXISTS(SELECT table_name FROM information_schema.columns WHERE table_schema OPERATOR(pg_catalog.=) 'tiger' AND table_name OPERATOR(pg_catalog.=) 'pagc_rules' AND column_name OPERATOR(pg_catalog.=) 'is_custom' ) THEN -- its probably old table structure add column ALTER TABLE tiger.pagc_rules ADD COLUMN is_custom boolean NOT NULL DEFAULT false; END IF; @@ -8193,4 +8193,4 @@ UPDATE tiger.pagc_rules SET is_custom = false where id < 10000; -- after insert we need to set back to true so all -- user inputs are treated as custom ALTER TABLE tiger.pagc_rules ALTER COLUMN is_custom SET DEFAULT true; -SELECT pg_catalog.setval('pagc_rules_id_seq', 10000, true); \ No newline at end of file +SELECT pg_catalog.setval('pagc_rules_id_seq', 10000, true); ----------------------------------------------------------------------- Summary of changes: .../geocode/other_helper_functions.sql | 22 +++++++++++----------- .../tiger_geocoder/pagc_normalize/pagc_tables.sql | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 4 09:33:47 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 4 Jun 2026 09:33:47 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-495-gc9bdc50fb Message-ID: <20260604163348.43EF41A2EB4@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via c9bdc50fbdaac675ef784463df1849e27d447872 (commit) from 7761433a55ce7445282798f018d57819f44dc319 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c9bdc50fbdaac675ef784463df1849e27d447872 Author: Paul Ramsey Date: Thu Jun 4 09:32:40 2026 -0700 Change target target reskew calculation from an iterative process to a deterministic calculation. Closes #5854. References #5918. diff --git a/raster/rt_core/librtcore.h b/raster/rt_core/librtcore.h index 6847319cf..618d1292d 100644 --- a/raster/rt_core/librtcore.h +++ b/raster/rt_core/librtcore.h @@ -1544,21 +1544,17 @@ rt_errorstate rt_raster_get_perimeter( /* * Compute skewed extent that covers unskewed extent. * - * @param envelope : unskewed extent of type rt_envelope - * @param skew : pointer to 2-element array (x, y) of skew - * @param scale : pointer to 2-element array (x, y) of scale - * @param tolerance : value between 0 and 1 where the smaller the tolerance - * results in an extent approaching the "minimum" skewed extent. - * If value <= 0, tolerance = 0.1. If value > 1, tolerance = 1. + * @param extent : unskewed extent of type rt_envelope + * @param skew : pointer to 2-element array {skew_x, skew_y} + * @param scale : pointer to 2-element array {fabs(scale_x), fabs(scale_y)} * - * @return skewed raster who's extent covers unskewed extent, NULL on error + * @return skewed raster whose extent covers unskewed extent, NULL on error */ rt_raster rt_raster_compute_skewed_raster( rt_envelope extent, double *skew, - double *scale, - double tolerance + double *scale ); /** diff --git a/raster/rt_core/rt_raster.c b/raster/rt_core/rt_raster.c index 99578fe87..3ce611261 100644 --- a/raster/rt_core/rt_raster.c +++ b/raster/rt_core/rt_raster.c @@ -854,381 +854,96 @@ rt_raster_get_envelope( ******************************************************************************/ /* - * Compute skewed extent that covers unskewed extent. + * Compute skewed raster extent that covers the given unskewed extent. + * Uses a direct linear-algebra solution rather than an iterative approach. * - * @param envelope : unskewed extent of type rt_envelope - * @param skew : pointer to 2-element array (x, y) of skew - * @param scale : pointer to 2-element array (x, y) of scale - * @param tolerance : value between 0 and 1 where the smaller the tolerance - * results in an extent approaching the "minimum" skewed extent. - * If value <= 0, tolerance = 0.1. If value > 1, tolerance = 1. + * @param extent : unskewed extent of type rt_envelope + * @param skew : pointer to 2-element array {skew_x, skew_y} + * @param scale : pointer to 2-element array {fabs(scale_x), fabs(scale_y)} * - * @return skewed raster who's extent covers unskewed extent, NULL on error + * @return skewed raster whose extent covers unskewed extent, NULL on error */ rt_raster rt_raster_compute_skewed_raster( rt_envelope extent, double *skew, - double *scale, - double tolerance + double *scale ) { - uint32_t run = 0; - uint32_t max_run = 1; - double dbl_run = 0; - - int rtn; - int covers = 0; + double sx, syg, kx, ky, det; + double col_nums[4], row_nums[4]; + double col_min, col_max, row_min, row_max; + double K1, K2, eps; + double ulx, uly; + int width, height; rt_raster raster; - double _gt[6] = {0}; - double _igt[6] = {0}; - int _d[2] = {1, -1}; - int _dlast = 0; - int _dlastpos = 0; - double _w[2] = {0}; - double _r[2] = {0}; - double _xy[2] = {0}; int i; - int j; - int x; - int y; - LWGEOM *geom = NULL; - GEOSGeometry *sgeom = NULL; - GEOSGeometry *ngeom = NULL; - - if ( - (tolerance < 0.) || - FLT_EQ(tolerance, 0.) - ) { - tolerance = 0.1; - } - else if (tolerance > 1.) - tolerance = 1; - - dbl_run = tolerance; - while (dbl_run < 10) { - dbl_run *= 10.; - max_run *= 10; - } - - /* scale must be provided */ - if (scale == NULL) + if (scale == NULL || skew == NULL) return NULL; - for (i = 0; i < 2; i++) { - if (FLT_EQ(scale[i], 0.0)) - { - rterror("rt_raster_compute_skewed_raster: Scale cannot be zero"); - return 0; - } - if (i < 1) - _gt[1] = fabs(scale[i] * tolerance); - else - _gt[5] = fabs(scale[i] * tolerance); - } - /* conform scale-y to be negative */ - _gt[5] *= -1; - - /* skew not provided or skew is zero, return raster of correct dim and spatial attributes */ - if ((skew == NULL) || (FLT_EQ(skew[0], 0.0) && FLT_EQ(skew[1], 0.0))) - { - int _dim[2] = { - (int) fmax((fabs(extent.MaxX - extent.MinX) + (fabs(scale[0]) / 2.)) / fabs(scale[0]), 1), - (int) fmax((fabs(extent.MaxY - extent.MinY) + (fabs(scale[1]) / 2.)) / fabs(scale[1]), 1) - }; - - raster = rt_raster_new(_dim[0], _dim[1]); - if (raster == NULL) { - rterror("rt_raster_compute_skewed_raster: Could not create output raster"); - return NULL; - } - - rt_raster_set_offsets(raster, extent.MinX, extent.MaxY); - rt_raster_set_scale(raster, fabs(scale[0]), -1 * fabs(scale[1])); - rt_raster_set_skews(raster, skew[0], skew[1]); - - return raster; - } - - /* direction to shift upper-left corner */ - if (skew[0] > 0.) - _d[0] = -1; - if (skew[1] < 0.) - _d[1] = 1; - - /* geotransform */ - _gt[0] = extent.UpperLeftX; - _gt[2] = skew[0] * tolerance; - _gt[3] = extent.UpperLeftY; - _gt[4] = skew[1] * tolerance; - - RASTER_DEBUGF(4, "Initial geotransform: %f, %f, %f, %f, %f, %f", - _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5] - ); - RASTER_DEBUGF(4, "Delta: %d, %d", _d[0], _d[1]); - - /* simple raster */ - if ((raster = rt_raster_new(1, 1)) == NULL) { - rterror("rt_raster_compute_skewed_raster: Out of memory allocating extent raster"); - return NULL; - } - rt_raster_set_geotransform_matrix(raster, _gt); - - /* get inverse geotransform matrix */ - if (!GDALInvGeoTransform(_gt, _igt)) { - rterror("rt_raster_compute_skewed_raster: Could not compute inverse geotransform matrix"); - rt_raster_destroy(raster); - return NULL; - } - RASTER_DEBUGF(4, "Inverse geotransform: %f, %f, %f, %f, %f, %f", - _igt[0], _igt[1], _igt[2], _igt[3], _igt[4], _igt[5] - ); - - /* shift along axis */ - for (i = 0; i < 2; i++) { - covers = 0; - run = 0; - - RASTER_DEBUGF(3, "Shifting along %s axis", i < 1 ? "X" : "Y"); - - do { - - /* prevent possible infinite loop */ - if (run > max_run) { - rterror("rt_raster_compute_skewed_raster: Could not compute skewed extent due to check preventing infinite loop"); - rt_raster_destroy(raster); - return NULL; - } - - /* - check the four corners that they are covered along the specific axis - pixel column should be >= 0 - */ - for (j = 0; j < 4; j++) { - switch (j) { - /* upper-left */ - case 0: - _xy[0] = extent.MinX; - _xy[1] = extent.MaxY; - break; - /* lower-left */ - case 1: - _xy[0] = extent.MinX; - _xy[1] = extent.MinY; - break; - /* lower-right */ - case 2: - _xy[0] = extent.MaxX; - _xy[1] = extent.MinY; - break; - /* upper-right */ - case 3: - _xy[0] = extent.MaxX; - _xy[1] = extent.MaxY; - break; - } - - rtn = rt_raster_geopoint_to_cell( - raster, - _xy[0], _xy[1], - &(_r[0]), &(_r[1]), - _igt - ); - if (rtn != ES_NONE) { - rterror("rt_raster_compute_skewed_raster: Could not compute raster pixel for spatial coordinates"); - rt_raster_destroy(raster); - return NULL; - } - - RASTER_DEBUGF(4, "Point %d at cell %d x %d", j, (int) _r[0], (int) _r[1]); - - /* raster doesn't cover point */ - if ((int) _r[i] < 0) { - RASTER_DEBUGF(4, "Point outside of skewed extent: %d", j); - covers = 0; - - if (_dlastpos != j) { - _dlast = (int) _r[i]; - _dlastpos = j; - } - else if ((int) _r[i] < _dlast) { - RASTER_DEBUG(4, "Point going in wrong direction. Reversing direction"); - _d[i] *= -1; - _dlastpos = -1; - run = 0; - } - - break; - } - - covers++; - } - - if (!covers) { - x = 0; - y = 0; - if (i < 1) - x = _d[i] * fabs(_r[i]); - else - y = _d[i] * fabs(_r[i]); - - rtn = rt_raster_cell_to_geopoint( - raster, - x, y, - &(_w[0]), &(_w[1]), - _gt - ); - if (rtn != ES_NONE) { - rterror("rt_raster_compute_skewed_raster: Could not compute spatial coordinates for raster pixel"); - rt_raster_destroy(raster); - return NULL; - } - - /* adjust ul */ - if (i < 1) - _gt[0] = _w[i]; - else - _gt[3] = _w[i]; - rt_raster_set_geotransform_matrix(raster, _gt); - RASTER_DEBUGF(4, "Shifted geotransform: %f, %f, %f, %f, %f, %f", - _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5] - ); - - /* get inverse geotransform matrix */ - if (!GDALInvGeoTransform(_gt, _igt)) { - rterror("rt_raster_compute_skewed_raster: Could not compute inverse geotransform matrix"); - rt_raster_destroy(raster); - return NULL; - } - RASTER_DEBUGF(4, "Inverse geotransform: %f, %f, %f, %f, %f, %f", - _igt[0], _igt[1], _igt[2], _igt[3], _igt[4], _igt[5] - ); - } - - run++; - } - while (!covers); - } - - /* covers test */ - rtn = rt_raster_geopoint_to_cell( - raster, - extent.MaxX, extent.MinY, - &(_r[0]), &(_r[1]), - _igt - ); - if (rtn != ES_NONE) { - rterror("rt_raster_compute_skewed_raster: Could not compute raster pixel for spatial coordinates"); - rt_raster_destroy(raster); + if (FLT_EQ(scale[0], 0.0) || FLT_EQ(scale[1], 0.0)) { + rterror("rt_raster_compute_skewed_raster: Scale cannot be zero"); return NULL; } - RASTER_DEBUGF(4, "geopoint %f x %f at cell %d x %d", extent.MaxX, extent.MinY, (int) _r[0], (int) _r[1]); + sx = fabs(scale[0]); + syg = -fabs(scale[1]); /* gt[5]: negative for north-up */ + kx = skew[0]; + ky = skew[1]; + det = sx * syg - kx * ky; - raster->width = _r[0]; - raster->height = _r[1]; - - /* initialize GEOS */ - initGEOS(rtinfo, lwgeom_geos_error); - - /* create reference LWPOLY */ - { - LWPOLY *npoly = rt_util_envelope_to_lwpoly(extent); - if (npoly == NULL) { - rterror("rt_raster_compute_skewed_raster: Could not build extent's geometry for covers test"); - rt_raster_destroy(raster); - return NULL; - } - - ngeom = (GEOSGeometry *) LWGEOM2GEOS(lwpoly_as_lwgeom(npoly), 0); - lwpoly_free(npoly); + if (FLT_EQ(det, 0.0)) { + rterror("rt_raster_compute_skewed_raster: Degenerate geotransform (determinant is zero)"); + return NULL; } - do { - covers = 0; - - /* construct sgeom from raster */ - if ((rt_raster_get_convex_hull(raster, &geom) != ES_NONE) || geom == NULL) { - rterror("rt_raster_compute_skewed_raster: Could not build skewed extent's geometry for covers test"); - GEOSGeom_destroy(ngeom); - rt_raster_destroy(raster); - return NULL; - } - - sgeom = (GEOSGeometry *) LWGEOM2GEOS(geom, 0); - lwgeom_free(geom); - - covers = GEOSRelatePattern(sgeom, ngeom, "******FF*"); - GEOSGeom_destroy(sgeom); - - if (covers == 2) { - rterror("rt_raster_compute_skewed_raster: Could not run covers test"); - GEOSGeom_destroy(ngeom); - rt_raster_destroy(raster); - return NULL; - } - - if (!covers) - { - raster->width++; - raster->height++; - } - } - while (!covers); - - RASTER_DEBUGF(4, "Skewed extent does cover normal extent with dimensions %d x %d", raster->width, raster->height); - - raster->width = (int) ((((double) raster->width) * fabs(_gt[1]) + fabs(scale[0] / 2.)) / fabs(scale[0])); - raster->height = (int) ((((double) raster->height) * fabs(_gt[5]) + fabs(scale[1] / 2.)) / fabs(scale[1])); - _gt[1] = fabs(scale[0]); - _gt[5] = -1 * fabs(scale[1]); - _gt[2] = skew[0]; - _gt[4] = skew[1]; - rt_raster_set_geotransform_matrix(raster, _gt); - - /* minimize width/height */ - for (i = 0; i < 2; i++) { - covers = 1; - do { - if (i < 1) - raster->width--; - else - raster->height--; - - /* construct sgeom from raster */ - if ((rt_raster_get_convex_hull(raster, &geom) != ES_NONE) || geom == NULL) { - rterror("rt_raster_compute_skewed_raster: Could not build skewed extent's geometry for minimizing dimensions"); - GEOSGeom_destroy(ngeom); - rt_raster_destroy(raster); - return NULL; - } - - sgeom = (GEOSGeometry *) LWGEOM2GEOS(geom, 0); - lwgeom_free(geom); - - covers = GEOSRelatePattern(sgeom, ngeom, "******FF*"); - GEOSGeom_destroy(sgeom); - - if (covers == 2) { - rterror("rt_raster_compute_skewed_raster: Could not run covers test for minimizing dimensions"); - GEOSGeom_destroy(ngeom); - rt_raster_destroy(raster); - return NULL; - } - } while (covers); - - if (i < 1) - raster->width++; - else - raster->height++; + /* col_num(x,y) = syg*x - kx*y, row_num(x,y) = -ky*x + sx*y */ + col_nums[0] = syg * extent.MinX - kx * extent.MaxY; + col_nums[1] = syg * extent.MaxX - kx * extent.MaxY; + col_nums[2] = syg * extent.MaxX - kx * extent.MinY; + col_nums[3] = syg * extent.MinX - kx * extent.MinY; + row_nums[0] = -ky * extent.MinX + sx * extent.MaxY; + row_nums[1] = -ky * extent.MaxX + sx * extent.MaxY; + row_nums[2] = -ky * extent.MaxX + sx * extent.MinY; + row_nums[3] = -ky * extent.MinX + sx * extent.MinY; + col_min = col_max = col_nums[0]; + row_min = row_max = row_nums[0]; + for (i = 1; i < 4; i++) { + if (col_nums[i] < col_min) col_min = col_nums[i]; + if (col_nums[i] > col_max) col_max = col_nums[i]; + if (row_nums[i] < row_min) row_min = row_nums[i]; + if (row_nums[i] > row_max) row_max = row_nums[i]; } - GEOSGeom_destroy(ngeom); + K1 = (det < 0.0) ? col_max : col_min; + K2 = (det < 0.0) ? row_max : row_min; + + /* Tiny safety margin so FP rounding can't place boundary corners just outside */ + eps = (fabs(K1) + fabs(K2) + fabs(det)) * DBL_EPSILON * 16.0; + if (det < 0.0) { K1 += eps; K2 += eps; } + else { K1 -= eps; K2 -= eps; } + + /* Solve: syg*ulx - kx*uly = K1, -ky*ulx + sx*uly = K2 */ + ulx = (sx * K1 + kx * K2) / det; + uly = (ky * K1 + syg * K2) / det; + + width = (int)floor((col_max - col_min) / fabs(det)) + 1; + height = (int)floor((row_max - row_min) / fabs(det)) + 1; + + raster = rt_raster_new(width, height); + if (raster == NULL) { + rterror("rt_raster_compute_skewed_raster: Could not create output raster"); + return NULL; + } + rt_raster_set_offsets(raster, ulx, uly); + rt_raster_set_scale(raster, fabs(scale[0]), -fabs(scale[1])); + rt_raster_set_skews(raster, skew[0], skew[1]); return raster; } + /** * Return TRUE if the raster is empty. i.e. is NULL, width = 0 or height = 0 * @@ -2749,8 +2464,7 @@ rt_raster_gdal_rasterize( skewedrast = rt_raster_compute_skewed_raster( extent, _skew, - _scale, - 0.01 + _scale ); if (skewedrast == NULL) { rterror("rt_raster_gdal_rasterize: Could not compute skewed raster"); diff --git a/raster/rt_core/rt_warp.c b/raster/rt_core/rt_warp.c index 59110feec..f5854fd0f 100644 --- a/raster/rt_core/rt_warp.c +++ b/raster/rt_core/rt_warp.c @@ -145,34 +145,9 @@ _rti_warp_arg_destroy(_rti_warp_arg arg) { } /** - * Return a warped raster using GDAL Warp API - * - * @param raster : raster to transform - * @param src_srs : the raster's coordinate system in OGC WKT - * @param dst_srs : the warped raster's coordinate system in OGC WKT - * @param scale_x : the x size of pixels of the warped raster's pixels in - * units of dst_srs - * @param scale_y : the y size of pixels of the warped raster's pixels in - * units of dst_srs - * @param width : the number of columns of the warped raster. note that - * width/height CANNOT be used with scale_x/scale_y - * @param height : the number of rows of the warped raster. note that - * width/height CANNOT be used with scale_x/scale_y - * @param ul_xw : the X value of upper-left corner of the warped raster in - * units of dst_srs - * @param ul_yw : the Y value of upper-left corner of the warped raster in - * units of dst_srs - * @param grid_xw : the X value of point on a grid to align warped raster - * to in units of dst_srs - * @param grid_yw : the Y value of point on a grid to align warped raster - * to in units of dst_srs - * @param skew_x : the X skew of the warped raster in units of dst_srs - * @param skew_y : the Y skew of the warped raster in units of dst_srs - * @param resample_alg : the resampling algorithm - * @param max_err : maximum error measured in input pixels permitted - * (0.0 for exact calculations) - * - * @return the warped raster or NULL + * Return a warped raster using GDAL Warp API. + * When non-zero skew values are requested, the output extent is computed + * via rt_raster_compute_skewed_raster(). */ rt_raster rt_raster_gdal_warp( rt_raster raster, @@ -207,103 +182,64 @@ rt_raster rt_raster_gdal_warp( int i = 0; int numBands = 0; - /* flag indicating that the spatial info is being substituted */ int subspatial = 0; - RASTER_DEBUG(3, "starting"); + RASTER_DEBUG(3, "rt_raster_gdal_warp: starting"); assert(NULL != raster); - /* internal variables */ arg = _rti_warp_arg_init(); if (arg == NULL) { rterror("rt_raster_gdal_warp: Could not initialize internal variables"); return NULL; } - /* - max_err must be gte zero - - the value 0.125 is the default used in gdalwarp.cpp on line 283 - */ if (max_err < 0.) max_err = 0.125; - RASTER_DEBUGF(4, "max_err = %f", max_err); /* handle srs */ if (src_srs != NULL) { - /* reprojection taking place */ if (dst_srs != NULL && strcmp(src_srs, dst_srs) != 0) { - RASTER_DEBUG(4, "Warp operation does include a reprojection"); + RASTER_DEBUG(4, "rt_raster_gdal_warp: Warp includes reprojection"); arg->src.srs = rt_util_gdal_convert_sr(src_srs, 0); arg->dst.srs = rt_util_gdal_convert_sr(dst_srs, 0); - if (arg->src.srs == NULL || arg->dst.srs == NULL) { rterror("rt_raster_gdal_warp: Could not convert srs values to GDAL accepted format"); _rti_warp_arg_destroy(arg); return NULL; } } - /* no reprojection, a stub just for clarity */ - else { - RASTER_DEBUG(4, "Warp operation does NOT include reprojection"); - } } else if (dst_srs != NULL) { - /* dst_srs provided but not src_srs */ rterror("rt_raster_gdal_warp: SRS required for input raster if SRS provided for warped raster"); _rti_warp_arg_destroy(arg); return NULL; } - /* load raster into a GDAL MEM dataset */ + /* load raster into GDAL MEM dataset */ arg->src.ds = rt_raster_to_gdal_mem(raster, arg->src.srs, NULL, NULL, 0, &(arg->src.drv), &(arg->src.destroy_drv)); if (NULL == arg->src.ds) { rterror("rt_raster_gdal_warp: Could not convert raster to GDAL MEM format"); _rti_warp_arg_destroy(arg); return NULL; } - RASTER_DEBUG(3, "raster loaded into GDAL MEM dataset"); - /* special case when src_srs and dst_srs is NULL and raster's geotransform matrix is default */ + /* special case: default geotransform raster with no SRS */ if ( src_srs == NULL && dst_srs == NULL && rt_raster_get_srid(raster) == SRID_UNKNOWN ) { double gt[6]; - -#if POSTGIS_DEBUG_LEVEL > 3 - GDALGetGeoTransform(arg->src.ds, gt); - RASTER_DEBUGF(3, "GDAL MEM geotransform: %f, %f, %f, %f, %f, %f", - gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]); -#endif - - /* default geotransform */ rt_raster_get_geotransform_matrix(raster, gt); - RASTER_DEBUGF(3, "raster geotransform: %f, %f, %f, %f, %f, %f", - gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]); - - /* substitute spatial info (lack of) with a real one EPSG:32731 (WGS84/UTM zone 31s) */ if (FLT_EQ(gt[0], 0.0) && FLT_EQ(gt[3], 0.0) && FLT_EQ(gt[1], 1.0) && FLT_EQ(gt[5], -1.0) && FLT_EQ(gt[2], 0.0) && FLT_EQ(gt[4], 0.0)) { double ngt[6] = {166021.4431, 0.1, 0, 10000000.0000, 0, -0.1}; - rtwarn("Raster has default geotransform. Adjusting metadata for use of GDAL Warp API"); - subspatial = 1; - GDALSetGeoTransform(arg->src.ds, ngt); GDALFlushCache(arg->src.ds); - - /* EPSG:32731 */ arg->src.srs = rt_util_gdal_convert_sr("EPSG:32731", 0); arg->dst.srs = rt_util_gdal_convert_sr("EPSG:32731", 0); - -#if POSTGIS_DEBUG_LEVEL > 3 - GDALGetGeoTransform(arg->src.ds, gt); - RASTER_DEBUGF(3, "GDAL MEM geotransform: %f, %f, %f, %f, %f, %f", - gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]); -#endif } } @@ -312,7 +248,7 @@ rt_raster rt_raster_gdal_warp( arg->transform.option.len = 2; arg->transform.option.item = rtalloc(sizeof(char *) * (arg->transform.option.len + 1)); if (NULL == arg->transform.option.item) { - rterror("rt_raster_gdal_warp: Could not allocation memory for transform options"); + rterror("rt_raster_gdal_warp: Could not allocate memory for transform options"); _rti_warp_arg_destroy(arg); return NULL; } @@ -322,15 +258,14 @@ rt_raster rt_raster_gdal_warp( const char *srs = i ? arg->dst.srs : arg->src.srs; const char *lbl = i ? "DST_SRS=" : "SRC_SRS="; size_t sz = sizeof(char) * (strlen(lbl) + 1); - if ( srs ) sz += strlen(srs); + if (srs) sz += strlen(srs); arg->transform.option.item[i] = (char *) rtalloc(sz); if (NULL == arg->transform.option.item[i]) { - rterror("rt_raster_gdal_warp: Could not allocation memory for transform options"); + rterror("rt_raster_gdal_warp: Could not allocate memory for transform options"); _rti_warp_arg_destroy(arg); return NULL; } sprintf(arg->transform.option.item[i], "%s%s", lbl, srs ? srs : ""); - RASTER_DEBUGF(4, "arg->transform.option.item[%d] = %s", i, arg->transform.option.item[i]); } } else @@ -339,7 +274,7 @@ rt_raster rt_raster_gdal_warp( /* transformation object for building dst dataset */ arg->transform.arg.transform = GDALCreateGenImgProjTransformer2(arg->src.ds, NULL, arg->transform.option.item); if (NULL == arg->transform.arg.transform) { - rterror("rt_raster_gdal_warp: Could not create GDAL transformation object for output dataset creation"); + rterror("rt_raster_gdal_warp: Could not create GDAL transformation object"); _rti_warp_arg_destroy(arg); return NULL; } @@ -349,70 +284,49 @@ rt_raster rt_raster_gdal_warp( arg->src.ds, GDALGenImgProjTransform, arg->transform.arg.transform, _gt, &(_dim[0]), &(_dim[1]), dst_extent, 0); if (cplerr != CE_None) { - rterror("rt_raster_gdal_warp: Could not get GDAL suggested warp output for output dataset creation"); + rterror("rt_raster_gdal_warp: Could not get GDAL suggested warp output"); _rti_warp_arg_destroy(arg); return NULL; } GDALDestroyGenImgProjTransformer(arg->transform.arg.transform); arg->transform.arg.transform = NULL; - /* - don't use suggested dimensions as use of suggested scales - on suggested extent will result in suggested dimensions - */ _dim[0] = 0; _dim[1] = 0; - RASTER_DEBUGF(3, "Suggested geotransform: %f, %f, %f, %f, %f, %f", - _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]); - - /* store extent in easier-to-use object */ extent.MinX = dst_extent[0]; extent.MinY = dst_extent[1]; extent.MaxX = dst_extent[2]; extent.MaxY = dst_extent[3]; - extent.UpperLeftX = dst_extent[0]; extent.UpperLeftY = dst_extent[3]; - RASTER_DEBUGF(3, "Suggested extent: %f, %f, %f, %f", - extent.MinX, extent.MinY, extent.MaxX, extent.MaxY); - /* scale and width/height are mutually exclusive */ if ( ((NULL != scale_x) || (NULL != scale_y)) && ((NULL != width) || (NULL != height)) ) { - rterror("rt_raster_gdal_warp: Scale X/Y and width/height are mutually exclusive. Only provide one"); + rterror("rt_raster_gdal_warp: Scale X/Y and width/height are mutually exclusive"); _rti_warp_arg_destroy(arg); return NULL; } - /* user-defined width */ if (NULL != width) { _dim[0] = abs(*width); _scale[0] = fabs((extent.MaxX - extent.MinX) / ((double) _dim[0])); } - /* user-defined height */ if (NULL != height) { _dim[1] = abs(*height); _scale[1] = fabs((extent.MaxY - extent.MinY) / ((double) _dim[1])); } - /* user-defined scale */ if ( ((NULL != scale_x) && (FLT_NEQ(*scale_x, 0.0))) && ((NULL != scale_y) && (FLT_NEQ(*scale_y, 0.0))) ) { _scale[0] = fabs(*scale_x); _scale[1] = fabs(*scale_y); - - /* special override since we changed the original GT scales */ if (subspatial) { - /* - _scale[0] *= 10; - _scale[1] *= 10; - */ _scale[0] /= 10; _scale[1] /= 10; } @@ -421,83 +335,59 @@ rt_raster rt_raster_gdal_warp( ((NULL != scale_x) && (NULL == scale_y)) || ((NULL == scale_x) && (NULL != scale_y)) ) { - rterror("rt_raster_gdal_warp: Both X and Y scale values must be provided for scale"); + rterror("rt_raster_gdal_warp: Both X and Y scale values must be provided"); _rti_warp_arg_destroy(arg); return NULL; } - /* scale not defined, use suggested */ - if (FLT_EQ(_scale[0], 0.0) && FLT_EQ(_scale[1], 0.0)) - { + /* scale not defined: use suggested */ + if (FLT_EQ(_scale[0], 0.0) && FLT_EQ(_scale[1], 0.0)) { _scale[0] = fabs(_gt[1]); _scale[1] = fabs(_gt[5]); } - RASTER_DEBUGF(4, "Using scale: %f x %f", _scale[0], -1 * _scale[1]); + RASTER_DEBUGF(4, "rt_raster_gdal_warp: Using scale: %f x %f", _scale[0], -1 * _scale[1]); - /* user-defined skew */ + /* skew */ if (NULL != skew_x) { _skew[0] = *skew_x; - - /* - negative scale-x affects skew - for now, force skew to be in left-right, top-down orientation - */ - if ( - NULL != scale_x && - *scale_x < 0. - ) { + if (NULL != scale_x && *scale_x < 0.) _skew[0] *= -1; - } } if (NULL != skew_y) { _skew[1] = *skew_y; - - /* - positive scale-y affects skew - for now, force skew to be in left-right, top-down orientation - */ - if ( - NULL != scale_y && - *scale_y > 0. - ) { + if (NULL != scale_y && *scale_y > 0) _skew[1] *= -1; - } } - RASTER_DEBUGF(4, "Using skew: %f x %f", _skew[0], _skew[1]); + RASTER_DEBUGF(4, "rt_raster_gdal_warp: Using skew: %f x %f", _skew[0], _skew[1]); - /* reprocess extent if skewed */ - if (FLT_NEQ(_skew[0], 0.0) || FLT_NEQ(_skew[1], 0.0)) - { + /* Compute the output grid parameters when skew is requested. */ + if (FLT_NEQ(_skew[0], 0.0) || FLT_NEQ(_skew[1], 0.0)) { rt_raster skewedrast; - RASTER_DEBUG(3, "Computing skewed extent's envelope"); + RASTER_DEBUG(3, "rt_raster_gdal_warp: Computing skewed extent"); - skewedrast = rt_raster_compute_skewed_raster( - extent, - _skew, - _scale, - 0.01 - ); + skewedrast = rt_raster_compute_skewed_raster(extent, _skew, _scale); if (skewedrast == NULL) { - rterror("rt_raster_gdal_warp: Could not compute skewed raster"); + rterror("rt_raster_gdal_warp: Could not compute skewed extent"); _rti_warp_arg_destroy(arg); return NULL; } - if (_dim[0] == 0) - _dim[0] = skewedrast->width; - if (_dim[1] == 0) - _dim[1] = skewedrast->height; + if (_dim[0] == 0) _dim[0] = rt_raster_get_width(skewedrast); + if (_dim[1] == 0) _dim[1] = rt_raster_get_height(skewedrast); - extent.UpperLeftX = skewedrast->ipX; - extent.UpperLeftY = skewedrast->ipY; + extent.UpperLeftX = rt_raster_get_x_offset(skewedrast); + extent.UpperLeftY = rt_raster_get_y_offset(skewedrast); + + RASTER_DEBUGF(3, "rt_raster_gdal_warp: Skewed extent: UL=(%f,%f) dim=%dx%d", + extent.UpperLeftX, extent.UpperLeftY, _dim[0], _dim[1]); rt_raster_destroy(skewedrast); } - /* dimensions not defined, compute */ + /* dimensions not defined, compute from extent */ if (!_dim[0]) _dim[0] = (int) fmax((fabs(extent.MaxX - extent.MinX) + (_scale[0] / 2.)) / _scale[0], 1); if (!_dim[1]) @@ -517,21 +407,12 @@ rt_raster rt_raster_gdal_warp( rt_raster_set_skews(rast, _skew[0], _skew[1]); rt_raster_get_geotransform_matrix(rast, _gt); - RASTER_DEBUGF(3, "Temp raster's geotransform: %f, %f, %f, %f, %f, %f", + RASTER_DEBUGF(3, "rt_raster_gdal_warp: Temp raster geotransform: %f,%f,%f,%f,%f,%f", _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]); - RASTER_DEBUGF(3, "Temp raster's dimensions (width x height): %d x %d", - _dim[0], _dim[1]); /* user-defined upper-left corner */ - if ( - NULL != ul_xw && - NULL != ul_yw - ) { + if (NULL != ul_xw && NULL != ul_yw) { ul_user = 1; - - RASTER_DEBUGF(4, "Using user-specified upper-left corner: %f, %f", *ul_xw, *ul_yw); - - /* set upper-left corner */ rt_raster_set_offsets(rast, *ul_xw, *ul_yw); extent.UpperLeftX = *ul_xw; extent.UpperLeftY = *ul_yw; @@ -599,7 +480,6 @@ rt_raster rt_raster_gdal_warp( NULL ) != ES_NONE) { rterror("rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel"); - rt_raster_destroy(rast); _rti_warp_arg_destroy(arg); return NULL; @@ -646,7 +526,6 @@ rt_raster rt_raster_gdal_warp( NULL ) != ES_NONE) { rterror("rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel"); - rt_raster_destroy(rast); _rti_warp_arg_destroy(arg); return NULL; @@ -662,68 +541,35 @@ rt_raster rt_raster_gdal_warp( while (0); } - /* - after this point, rt_envelope extent is no longer used - */ - - /* get key attributes from rast */ + /* get key attributes */ _dim[0] = rast->width; _dim[1] = rast->height; rt_raster_get_geotransform_matrix(rast, _gt); - /* scale-x is negative or scale-y is positive */ - if (( - (NULL != scale_x) && (*scale_x < 0.) - ) || ( - (NULL != scale_y) && (*scale_y > 0) - )) { + /* handle negative scale-x or positive scale-y (same as original) */ + if ((NULL != scale_x && *scale_x < 0.) || (NULL != scale_y && *scale_y > 0)) { double _w[2] = {0}; - - /* negative scale-x */ - if ( - (NULL != scale_x) && - (*scale_x < 0.) - ) { - if (rt_raster_cell_to_geopoint( - rast, - rast->width, 0, - &(_w[0]), &(_w[1]), - NULL - ) != ES_NONE) { + if (NULL != scale_x && *scale_x < 0.) { + if (rt_raster_cell_to_geopoint(rast, rast->width, 0, &(_w[0]), &(_w[1]), NULL) != ES_NONE) { rterror("rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel"); rt_raster_destroy(rast); _rti_warp_arg_destroy(arg); return NULL; } - _gt[0] = _w[0]; _gt[1] = *scale_x; - - /* check for skew */ if (NULL != skew_x && FLT_NEQ(*skew_x, 0.0)) _gt[2] = *skew_x; } - /* positive scale-y */ - if ( - (NULL != scale_y) && - (*scale_y > 0) - ) { - if (rt_raster_cell_to_geopoint( - rast, - 0, rast->height, - &(_w[0]), &(_w[1]), - NULL - ) != ES_NONE) { + if (NULL != scale_y && *scale_y > 0) { + if (rt_raster_cell_to_geopoint(rast, 0, rast->height, &(_w[0]), &(_w[1]), NULL) != ES_NONE) { rterror("rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel"); rt_raster_destroy(rast); _rti_warp_arg_destroy(arg); return NULL; } - _gt[3] = _w[1]; _gt[5] = *scale_y; - - /* check for skew */ if (NULL != skew_y && FLT_NEQ(*skew_y, 0.0)) _gt[4] = *skew_y; } @@ -732,12 +578,11 @@ rt_raster rt_raster_gdal_warp( rt_raster_destroy(rast); rast = NULL; - RASTER_DEBUGF(3, "Applied geotransform: %f, %f, %f, %f, %f, %f", + RASTER_DEBUGF(3, "rt_raster_gdal_warp: Final geotransform: %f,%f,%f,%f,%f,%f", _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]); - RASTER_DEBUGF(3, "Raster dimensions (width x height): %d x %d", - _dim[0], _dim[1]); + RASTER_DEBUGF(3, "rt_raster_gdal_warp: Raster dimensions: %d x %d", _dim[0], _dim[1]); - if ( _dim[0] == 0 || _dim[1] == 0 ) { + if (_dim[0] == 0 || _dim[1] == 0) { rterror("rt_raster_gdal_warp: The width (%d) or height (%d) of the warped raster is zero", _dim[0], _dim[1]); _rti_warp_arg_destroy(arg); return NULL; @@ -745,7 +590,6 @@ rt_raster rt_raster_gdal_warp( /* load VRT driver */ if (!rt_util_gdal_driver_registered("VRT")) { - RASTER_DEBUG(3, "Registering VRT driver"); GDALRegister_VRT(); arg->dst.destroy_drv = 1; } @@ -772,7 +616,6 @@ rt_raster rt_raster_gdal_warp( _rti_warp_arg_destroy(arg); return NULL; } - RASTER_DEBUGF(3, "Applied SRS: %s", GDALGetProjectionRef(arg->dst.ds)); } /* set dst geotransform */ @@ -783,7 +626,7 @@ rt_raster rt_raster_gdal_warp( return NULL; } - /* add bands to dst dataset */ + /* add bands */ numBands = rt_raster_get_num_bands(raster); for (i = 0; i < numBands; i++) { rtband = rt_raster_get_band(raster, i); @@ -805,8 +648,6 @@ rt_raster rt_raster_gdal_warp( return NULL; } - /* get band to write data to */ - band = NULL; band = GDALGetRasterBand(arg->dst.ds, i + 1); if (NULL == band) { rterror("rt_raster_gdal_warp: Could not get GDAL band for additional processing"); @@ -814,12 +655,10 @@ rt_raster rt_raster_gdal_warp( return NULL; } - /* set nodata */ if (rt_band_get_hasnodata_flag(rtband) != FALSE) { rt_band_get_nodata(rtband, &nodata); if (GDALSetRasterNoDataValue(band, nodata) != CE_None) rtwarn("rt_raster_gdal_warp: Could not set nodata value for band %d", i); - RASTER_DEBUGF(3, "nodata value set to %f", GDALGetRasterNoDataValue(band, NULL)); } } @@ -835,7 +674,6 @@ rt_raster rt_raster_gdal_warp( } arg->transform.func = GDALGenImgProjTransform; - /* use approximate transformation object */ if (max_err > 0.0) { arg->transform.arg.transform = arg->transform.arg.approx = GDALCreateApproxTransformer( GDALGenImgProjTransform, @@ -846,7 +684,6 @@ rt_raster rt_raster_gdal_warp( _rti_warp_arg_destroy(arg); return NULL; } - arg->transform.func = GDALApproxTransform; } @@ -858,37 +695,25 @@ rt_raster rt_raster_gdal_warp( return NULL; } - /* set options */ arg->wopts->eResampleAlg = resample_alg; arg->wopts->hSrcDS = arg->src.ds; arg->wopts->hDstDS = arg->dst.ds; arg->wopts->pfnTransformer = arg->transform.func; arg->wopts->pTransformerArg = arg->transform.arg.transform; arg->wopts->papszWarpOptions = (char **) CPLMalloc(sizeof(char *) * 2); - arg->wopts->papszWarpOptions[0] = (char *) CPLMalloc(sizeof(char) * (strlen("INIT_DEST=NO_DATA") + 1)); strcpy(arg->wopts->papszWarpOptions[0], "INIT_DEST=NO_DATA"); arg->wopts->papszWarpOptions[1] = NULL; - /* set band mapping */ + /* band mapping */ arg->wopts->nBandCount = numBands; arg->wopts->panSrcBands = (int *) CPLMalloc(sizeof(int) * arg->wopts->nBandCount); arg->wopts->panDstBands = (int *) CPLMalloc(sizeof(int) * arg->wopts->nBandCount); for (i = 0; i < arg->wopts->nBandCount; i++) arg->wopts->panDstBands[i] = arg->wopts->panSrcBands[i] = i + 1; - /* - * https://trac.osgeo.org/postgis/ticket/5881 - * In order to call GDALWarp with BAND_INIT=NO_DATA we need to ensure - * that the src and dst rasters have nodata values and they are - * matched up nicely. This block used by tested with the hasnodata - * check on all src raster bands, but now we just do it every time - * because that makes sense (any warped raster is likely to have - * empty corners on output, and those corners need to be filled with - * some kind of NODATA value). - */ + /* nodata mapping */ { - RASTER_DEBUG(3, "Setting nodata mapping"); arg->wopts->padfSrcNoDataReal = (double *) CPLMalloc(numBands * sizeof(double)); arg->wopts->padfDstNoDataReal = (double *) CPLMalloc(numBands * sizeof(double)); arg->wopts->padfSrcNoDataImag = (double *) CPLMalloc(numBands * sizeof(double)); @@ -910,68 +735,43 @@ rt_raster rt_raster_gdal_warp( _rti_warp_arg_destroy(arg); return NULL; } - - if (!rt_band_get_hasnodata_flag(band)) { - /* - based on line 1004 of gdalwarp.cpp - the problem is that there is a chance that this number is a legitimate value - */ + if (!rt_band_get_hasnodata_flag(band)) arg->wopts->padfSrcNoDataReal[i] = -123456.789; - } - else { + else rt_band_get_nodata(band, &(arg->wopts->padfSrcNoDataReal[i])); - } - arg->wopts->padfDstNoDataReal[i] = arg->wopts->padfSrcNoDataReal[i]; arg->wopts->padfDstNoDataImag[i] = arg->wopts->padfSrcNoDataImag[i] = 0.0; - RASTER_DEBUGF(4, "Mapped nodata value for band %d: %f (%f) => %f (%f)", - i, - arg->wopts->padfSrcNoDataReal[i], arg->wopts->padfSrcNoDataImag[i], - arg->wopts->padfDstNoDataReal[i], arg->wopts->padfDstNoDataImag[i] - ); } } - /* warp raster */ - RASTER_DEBUG(3, "Warping raster"); + /* warp */ cplerr = GDALInitializeWarpedVRT(arg->dst.ds, arg->wopts); if (cplerr != CE_None) { rterror("rt_raster_gdal_warp: Could not warp raster"); _rti_warp_arg_destroy(arg); return NULL; } - /* - GDALSetDescription(arg->dst.ds, "/tmp/warped.vrt"); - */ GDALFlushCache(arg->dst.ds); - RASTER_DEBUG(3, "Raster warped"); - /* convert gdal dataset to raster */ - RASTER_DEBUG(3, "Converting GDAL dataset to raster"); + /* convert to raster */ rast = rt_raster_from_gdal_dataset(arg->dst.ds); - _rti_warp_arg_destroy(arg); if (NULL == rast) { - rterror("rt_raster_gdal_warp: Could not warp raster"); + rterror("rt_raster_gdal_warp: Could not convert warped dataset to raster"); return NULL; } - /* substitute spatial, reset back to default */ + /* reset spatial info for default-geotransform rasters */ if (subspatial) { double gt[6] = {0, 1, 0, 0, 0, -1}; - /* See http://trac.osgeo.org/postgis/ticket/2911 */ - /* We should probably also tweak rotation here */ - /* NOTE: the times 10 is because it was divided by 10 in a section above, - * I'm not sure the above division was needed */ gt[1] = _scale[0] * 10; gt[5] = -1 * _scale[1] * 10; - rt_raster_set_geotransform_matrix(rast, gt); rt_raster_set_srid(rast, SRID_UNKNOWN); } - RASTER_DEBUG(3, "done"); + RASTER_DEBUG(3, "rt_raster_gdal_warp: done"); return rast; } diff --git a/raster/test/cunit/cu_raster_misc.c b/raster/test/cunit/cu_raster_misc.c index 90888a9aa..048749193 100644 --- a/raster/test/cunit/cu_raster_misc.c +++ b/raster/test/cunit/cu_raster_misc.c @@ -191,17 +191,14 @@ static void test_raster_compute_skewed_raster(void) { rast = rt_raster_compute_skewed_raster( extent, skew, - scale, - 0 + scale ); CU_ASSERT(rast != NULL); - /* Check disabled: See https://trac.osgeo.org/postgis/ticket/4379 - * CU_ASSERT_EQUAL(rt_raster_get_width(rast), 2); - */ + CU_ASSERT_EQUAL(rt_raster_get_width(rast), 3); CU_ASSERT_EQUAL(rt_raster_get_height(rast), 3); - CU_ASSERT_DOUBLE_EQUAL(rt_raster_get_x_offset(rast), -0.5, DBL_EPSILON); - CU_ASSERT_DOUBLE_EQUAL(rt_raster_get_y_offset(rast), 0, DBL_EPSILON); + CU_ASSERT_DOUBLE_EQUAL(rt_raster_get_x_offset(rast), -8.0/17.0, 1e-8); + CU_ASSERT_DOUBLE_EQUAL(rt_raster_get_y_offset(rast), -2.0/17.0, 1e-8); cu_free_raster(rast); } diff --git a/raster/test/regress/rt_asraster_expected b/raster/test/regress/rt_asraster_expected index 1e8fef17d..50110cee8 100644 --- a/raster/test/regress/rt_asraster_expected +++ b/raster/test/regress/rt_asraster_expected @@ -46,10 +46,10 @@ NOTICE: The rasters have different scales on the X axis 3.0|||||||||||||||| 3.1|993310|100|100|1|1406.537|-869.114|0.000|0.000|-175453.086|114987.661|8BUI|0.000|t|255.000|255.000| 3.2|993310|100|100|1|1406.537|-869.114|0.000|0.000|-175453.086|114987.661|8BUI|0.000|t|255.000|255.000| -3.3|993310|100|100|1|1406.537|-869.114|1.000|0.000|-175565.609|114987.661|8BUI|0.000|t|255.000|255.000| -3.4|993310|100|100|1|1406.537|-869.114|0.000|1.000|-175453.086|114987.661|8BUI|0.000|t|255.000|255.000| -3.5|993310|101|101|1|1406.537|-869.114|10.000|-5.000|-176465.793|115491.747|8BUI|0.000|t|255.000|255.000| -3.6|993310|100|101|1|1406.537|-869.114|-5.000|10.000|-175453.086|114987.661|8BUI|0.000|t|255.000|255.000| +3.3|993310|101|101|1|1406.537|-869.114|1.000|0.000|-175553.086|114987.661|8BUI|0.000|t|255.000|255.000| +3.4|993310|100|101|1|1406.537|-869.114|0.000|1.000|-175453.086|114987.661|8BUI|0.000|t|255.000|255.000| +3.5|993310|101|101|1|1406.537|-869.114|10.000|-5.000|-176458.881|115491.236|8BUI|0.000|t|255.000|255.000| +3.6|993310|101|102|1|1406.537|-869.114|-5.000|10.000|-175453.086|114987.661|8BUI|0.000|t|255.000|255.000| 4.0|||||||||||||||| 4.1|992163|150|117|1|1000.000|-1000.000|0.000|0.000|-1898000.000|-412000.000|8BUI|0.000|t|1.000|1.000|t 4.10|993310|142|88|1|1000.000|-1000.000|0.000|0.000|-176100.000|115100.000|16BUI|0.000|t|13.000|13.000|f diff --git a/raster/test/regress/rt_gdalwarp_expected b/raster/test/regress/rt_gdalwarp_expected index 649f8d98e..d6bc47c1f 100644 --- a/raster/test/regress/rt_gdalwarp_expected +++ b/raster/test/regress/rt_gdalwarp_expected @@ -14,7 +14,7 @@ NOTICE: Values must be provided for both X and Y when specifying the scale. Re 0.13|992163|11|11|1|1000.000|-1000.000|0.000|0.000|-500100.000|600950.000|t|t|t 0.14|992163|201|201|1|50.000|50.000|0.000|0.000|-500040.000|589957.000|t|t|t 0.15|992163|84|84|1|121.000|121.000|0.000|0.000|-500093.000|589875.000|t|t|t -0.18|992163|10|10|1|1000.000|-1000.000|3.000|3.000|-500030.000|600000.000|t|t|t +0.18|992163|11|11|1|1000.000|-1000.000|3.000|3.000|-500030.000|599999.910|t|t|t 0.25|0|5|5|1|2.000|-2.000|0.000|0.000|0.000|0.000|t|t|t 0.26|0|2|2|1|5.000|-5.000|0.000|0.000|0.000|0.000|t|t|t 0.27|0|100|100|1|0.100|-0.100|0.000|0.000|0.000|0.000|t|t|t @@ -31,14 +31,14 @@ NOTICE: Values must be provided for both X and Y when specifying the scale. Re 1.13|992163|84|84|1|121.000|121.000|0.000|0.000|-500093.000|589875.000|t|t|t 1.14|992163|201|201|1|50.000|50.000|0.000|0.000|-500040.000|589957.000|t|t|t 1.15|992163|201|201|1|50.000|50.000|0.000|0.000|-500040.000|589957.000|t|t|t -1.16|992163|10|10|1|1000.000|-1000.000|3.000|3.000|-500030.000|600000.000|t|t|t -1.17|992163|10|10|1|1000.000|-1000.000|3.000|3.000|-500030.000|600000.000|t|t|t -1.18|992163|10|10|1|1000.000|-1000.000|1.000|3.000|-500010.000|600000.000|t|t|t -1.19|992163|20|20|1|500.000|500.000|3.000|3.000|-500065.000|590065.000|t|t|t +1.16|992163|11|11|1|1000.000|-1000.000|3.000|3.000|-500030.000|599999.910|t|t|t +1.17|992163|11|11|1|1000.000|-1000.000|3.000|3.000|-500030.000|599999.910|t|t|t +1.18|992163|11|11|1|1000.000|-1000.000|1.000|3.000|-500010.000|599999.970|t|t|t +1.19|992163|21|21|1|500.000|500.000|3.000|3.000|-500060.362|589560.362|t|t|t 1.2|992163|20|20|1|500.000|500.000|0.000|0.000|-500000.000|590000.000|t|t|t -1.20|992163|21|21|1|500.000|500.000|0.000|6.000|-500048.000|590038.000|t|t|t -1.21|992163|207|101|1|50.000|-100.000|3.000|0.000|-500319.000|600056.000|t|t|t -1.22|992163|207|101|1|50.000|-100.000|3.000|0.000|-500319.000|600056.000|t|t|t +1.20|992163|22|22|1|500.000|500.000|0.000|6.000|-500048.000|589538.000|t|t|t +1.21|992163|208|102|1|50.000|-100.000|3.000|0.000|-500319.000|600056.000|t|t|t +1.22|992163|208|102|1|50.000|-100.000|3.000|0.000|-500319.000|600056.000|t|t|t 1.23|992163|150|150|1|66.667|-66.667|0.000|0.000|-500000.000|600000.000|t|t|t 1.24|992163|5|5|1|2064.200|-2291.200|0.000|0.000|-500321.000|601456.000|t|t|t 1.25||||||||||||| @@ -62,11 +62,11 @@ NOTICE: Values must be provided for both X and Y when specifying the scale. Re 3.7|992163|67|80|1|150.000|125.000|0.000|0.000|-500000.000|590000.000|t|t|t 3.8|992163|67|80|1|150.000|125.000|0.000|0.000|-500000.000|590000.000|t|t|t 4.1|992163|10|10|1|1000.000|-1000.000|0.000|0.000|-500000.000|600000.000|t|t|t -4.2|992163|10|10|1|1000.000|-1000.000|1.000|1.000|-500010.000|600000.000|t|t|t -4.3|992163|10|10|1|1000.000|-1000.000|0.500|0.000|-500010.000|600000.000|t|t|t -4.4|992163|10|10|1|1000.000|-1000.000|10.000|10.000|-500100.000|600000.000|t|t|t -4.5|992163|10|10|1|1000.000|-1000.000|10.000|10.000|-500100.000|600000.000|t|t|t -4.6|992163|10|10|1|1000.000|-1000.000|10.000|10.000|-500100.000|600000.000|t|t|t +4.2|992163|11|11|1|1000.000|-1000.000|1.000|1.000|-500010.000|599999.990|t|t|t +4.3|992163|11|11|1|1000.000|-1000.000|0.500|0.000|-500005.000|600000.000|t|t|t +4.4|992163|11|11|1|1000.000|-1000.000|10.000|10.000|-500099.990|599999.000|t|t|t +4.5|992163|11|11|1|1000.000|-1000.000|10.000|10.000|-500099.990|599999.000|t|t|t +4.6|992163|11|11|1|1000.000|-1000.000|10.000|10.000|-500099.990|599999.000|t|t|t 5.1|992163|10|10|1|1000.000|-1000.000|0.000|0.000|-500000.000|600000.000|t|t|t 5.10|992163|11|11|1|1000.000|-1000.000|0.000|0.000|-500005.000|600001.000|t|t|t 5.11|992163|11|11|1|1000.000|-1000.000|0.000|0.000|-500991.000|600991.000|t|t|t diff --git a/raster/test/regress/tickets.sql b/raster/test/regress/tickets.sql index a22717160..7a58d86e8 100644 --- a/raster/test/regress/tickets.sql +++ b/raster/test/regress/tickets.sql @@ -18,8 +18,8 @@ SELECT '#2532.2', NULL::geometry @ null::raster; -- added OFFSET 0 to force PostgreSQL 12+ to materialize the cte WITH data AS ( SELECT '#2911' l, ST_Metadata(ST_Rescale( ST_AddBand( - ST_MakeEmptyRaster(10, 10, 0, 0, 1, -1, 0, 0, 0), - 1, '8BUI', 0, 0 + ST_MakeEmptyRaster(10, 10, 0, 0, 1, -1, 0, 0, 0), + 1, '8BUI', 0, 0 ), 2.0, -2.0 @@ -37,38 +37,38 @@ DROP TABLE IF EXISTS test_raster_scale_big; DROP TABLE IF EXISTS test_raster_scale_small; CREATE TABLE test_raster_scale_regular ( - rid integer, - rast raster + rid integer, + rast raster ); CREATE TABLE test_raster_scale_big ( - rid integer, - rast raster + rid integer, + rast raster ); CREATE TABLE test_raster_scale_small ( - rid integer, - rast raster + rid integer, + rast raster ); CREATE OR REPLACE FUNCTION make_test_raster( - table_suffix text, + table_suffix text, rid integer, - scale_x double precision, - scale_y double precision DEFAULT 1.0 + scale_x double precision, + scale_y double precision DEFAULT 1.0 ) RETURNS void AS $$ DECLARE rast raster; - width integer := 2; - height integer := 2; - ul_x double precision := 0; - ul_y double precision := 0; - skew_x double precision := 0; - skew_y double precision := 0; - initvalue double precision := 1; - nodataval double precision := 0; + width integer := 2; + height integer := 2; + ul_x double precision := 0; + ul_y double precision := 0; + skew_x double precision := 0; + skew_y double precision := 0; + initvalue double precision := 1; + nodataval double precision := 0; BEGIN rast := ST_MakeEmptyRaster(width, height, ul_x, ul_y, scale_x, scale_y, skew_x, skew_y, 0); rast := ST_AddBand(rast, 1, '8BUI', initvalue, nodataval); @@ -83,7 +83,7 @@ SELECT make_test_raster('regular', 1, 1.0000001); SELECT make_test_raster('regular', 2, 0.9999999); SELECT AddRasterConstraints('test_raster_scale_regular'::name, 'rast'::name, 'scale_x', 'scale_y'); SELECT r_table_name, r_raster_column, scale_x, scale_y FROM raster_columns - WHERE r_raster_column = 'rast' AND r_table_name = 'test_raster_scale_regular'; + WHERE r_raster_column = 'rast' AND r_table_name = 'test_raster_scale_regular'; -- Issues enforce_scaley_rast constraint violation SELECT make_test_raster('regular', 3, 1.001, 0.9999999); @@ -91,7 +91,7 @@ SELECT make_test_raster('regular', 3, 1.001, 0.9999999); SELECT make_test_raster('big', 0, -1234567890123456789.0); SELECT AddRasterConstraints('test_raster_scale_big'::name, 'rast'::name, 'scale_x', 'scale_y'); SELECT r_table_name, r_raster_column, scale_x, scale_y FROM raster_columns - WHERE r_raster_column = 'rast' AND r_table_name = 'test_raster_scale_big'; + WHERE r_raster_column = 'rast' AND r_table_name = 'test_raster_scale_big'; -- Issues enforce_scalex_rast constraint violation SELECT make_test_raster('big', 1, -12345678901234567890.0); @@ -101,7 +101,7 @@ SELECT make_test_raster('small', 1, 0.000011); SELECT make_test_raster('small', 2, 0.00000999); SELECT AddRasterConstraints('test_raster_scale_small'::name, 'rast'::name, 'scale_x', 'scale_y'); SELECT r_table_name, r_raster_column, scale_x, scale_y FROM raster_columns - WHERE r_raster_column = 'rast' AND r_table_name = 'test_raster_scale_small'; + WHERE r_raster_column = 'rast' AND r_table_name = 'test_raster_scale_small'; -- Issues enforce_scaley_rast constraint violation SELECT make_test_raster('small', 3, 0.00001, 1.00001); @@ -153,10 +153,12 @@ FROM (VALUES ('A0006', 300), ('A0006', 302)) t(a,b); SELECT '#4770.b', ST_Union(NULL::raster) OVER (PARTITION BY a ORDER BY b) FROM (VALUES ('A0006', 300), - ('A0006', 302)) t(a, b); + ('A0006', 302)) t(a, b); SELECT '#4724.a', ST_SummaryStatsAgg(NULL::raster, NULL::int4, NULL::bool) OVER (ORDER BY q) FROM generate_series(1,2) AS e(q); SELECT '#4724.b', ST_SummaryStatsAgg(NULL::raster, NULL::int4, NULL::bool) FROM generate_series(1,2) AS e(q); + +SELECT '#5854',Round(ST_Rotation(ST_Reskew(ST_AddBand(ST_MakeEmptyRaster(100, 430, 0, 0, 0.001, -0.001, 0, 0, 4269), '8BUI'::text, 1, 0), 0.0015))::numeric,3); diff --git a/raster/test/regress/tickets_expected b/raster/test/regress/tickets_expected index 46e1297be..1087ddadc 100644 --- a/raster/test/regress/tickets_expected +++ b/raster/test/regress/tickets_expected @@ -77,3 +77,4 @@ NOTICE: Adding maximum extent constraint #4724.a|(0,,,,,) #4724.a|(0,,,,,) #4724.b|(0,,,,,) +#5854|-0.983 ----------------------------------------------------------------------- Summary of changes: raster/rt_core/librtcore.h | 14 +- raster/rt_core/rt_raster.c | 404 +++++-------------------------- raster/rt_core/rt_warp.c | 312 +++++------------------- raster/test/cunit/cu_raster_misc.c | 11 +- raster/test/regress/rt_asraster_expected | 8 +- raster/test/regress/rt_gdalwarp_expected | 26 +- raster/test/regress/tickets.sql | 48 ++-- raster/test/regress/tickets_expected | 1 + 8 files changed, 167 insertions(+), 657 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 4 09:33:55 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 16:33:55 -0000 Subject: [PostGIS] #5854: ST_Reskew Performance In-Reply-To: <049.9e30402f2c6e18ae5d16e4ed42881ae6@osgeo.org> References: <049.9e30402f2c6e18ae5d16e4ed42881ae6@osgeo.org> Message-ID: <064.0fcfc923c487262e4c1583c6a1ce1581@osgeo.org> #5854: ST_Reskew Performance -----------------------+--------------------------- Reporter: pramsey | Owner: pramsey Type: defect | Status: closed Priority: critical | Milestone: PostGIS 3.5.5 Component: postgis | Version: 3.5.x Resolution: fixed | Keywords: -----------------------+--------------------------- Changes (by Paul Ramsey ): * resolution: => fixed * status: new => closed Comment: In [changeset:"c9bdc50fbdaac675ef784463df1849e27d447872/git" c9bdc50f/git]: {{{#!CommitTicketReference repository="git" revision="c9bdc50fbdaac675ef784463df1849e27d447872" Change target target reskew calculation from an iterative process to a deterministic calculation. Closes #5854. References #5918. }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 09:33:56 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 16:33:56 -0000 Subject: [PostGIS] #5918: ST_Reskew crashes on ARM machines when processing rasters with infinite values In-Reply-To: <047.df59dfba8b18c6fc202037a98165fda2@osgeo.org> References: <047.df59dfba8b18c6fc202037a98165fda2@osgeo.org> Message-ID: <062.1d8b8fc1e6f49e355a741d16200ae4f5@osgeo.org> #5918: ST_Reskew crashes on ARM machines when processing rasters with infinite values ----------------------+--------------------------- Reporter: dmyzl | Owner: pramsey Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.5.5 Component: postgis | Version: 3.5.x Resolution: | Keywords: ST_Reskew ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"c9bdc50fbdaac675ef784463df1849e27d447872/git" c9bdc50f/git]: {{{#!CommitTicketReference repository="git" revision="c9bdc50fbdaac675ef784463df1849e27d447872" Change target target reskew calculation from an iterative process to a deterministic calculation. Closes #5854. References #5918. }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 09:34:13 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 16:34:13 -0000 Subject: [PostGIS] #5918: ST_Reskew crashes on ARM machines when processing rasters with infinite values In-Reply-To: <047.df59dfba8b18c6fc202037a98165fda2@osgeo.org> References: <047.df59dfba8b18c6fc202037a98165fda2@osgeo.org> Message-ID: <062.40d5fec195e210235b42897eaf8a246a@osgeo.org> #5918: ST_Reskew crashes on ARM machines when processing rasters with infinite values -------------------------+--------------------------- Reporter: dmyzl | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.5.5 Component: postgis | Version: 3.5.x Resolution: worksforme | Keywords: ST_Reskew -------------------------+--------------------------- Changes (by pramsey): * resolution: => worksforme * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 10:17:01 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 17:17:01 -0000 Subject: [PostGIS] #5593: Fails to build with imagemagic 6.9.12.98 In-Reply-To: <050.d70c51fcb8f375a80f52b2069c0d9bcc@osgeo.org> References: <050.d70c51fcb8f375a80f52b2069c0d9bcc@osgeo.org> Message-ID: <065.3a394a0b9363ff4ff81bb4e58fe8f73b@osgeo.org> #5593: Fails to build with imagemagic 6.9.12.98 -----------------------------+--------------------------- Reporter: Bas Couwenberg | Owner: komzpa Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.4.1 Component: build | Version: 3.4.x Resolution: fixed | Keywords: -----------------------------+--------------------------- Changes (by pramsey): * resolution: => fixed * status: new => closed Comment: This was closed by komzpa at 95e8afa878e77ed4e735fff2367f113a81c19aa9, with with a ticket number typo in the log. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 10:20:19 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 17:20:19 -0000 Subject: [PostGIS] #6049: postgis_tiger_geocoder should not create tiger_data In-Reply-To: <046.f601aa66528bf783f46b4d604662dd76@osgeo.org> References: <046.f601aa66528bf783f46b4d604662dd76@osgeo.org> Message-ID: <061.874fb96c8cace3dcf0fe33538b75169f@osgeo.org> #6049: postgis_tiger_geocoder should not create tiger_data -----------------------------+---------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.2.10 Component: tiger geocoder | Version: 3.5.x Resolution: fixed | Keywords: -----------------------------+---------------------------- Changes (by pramsey): * resolution: => fixed * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 4 12:18:13 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 4 Jun 2026 12:18:13 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-496-gf09adbed3 Message-ID: <20260604191814.2F9841A45DB@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via f09adbed379aad9ed9374cd19ca7ec3b6c2c0b49 (commit) from c9bdc50fbdaac675ef784463df1849e27d447872 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit f09adbed379aad9ed9374cd19ca7ec3b6c2c0b49 Author: Paul Ramsey Date: Thu Jun 4 12:17:19 2026 -0700 Use nodata mask rather than a SQL filter in ST_Polygon Avoids polygonizing nodata areas with ST_Polygon, matches old behaviour pre-3.x (2018). Closes #6010 diff --git a/raster/rt_core/rt_geometry.c b/raster/rt_core/rt_geometry.c index 2c126f4b8..70d815c69 100644 --- a/raster/rt_core/rt_geometry.c +++ b/raster/rt_core/rt_geometry.c @@ -979,7 +979,6 @@ rt_raster_gdal_polygonize( int *pnElements ) { CPLErr cplerr = CE_None; - char *pszQuery; long j; OGRSFDriverH ogr_drv = NULL; GDALDriverH gdal_drv = NULL; @@ -1140,9 +1139,14 @@ rt_raster_gdal_polygonize( /* * Why: We pass the shared interrupt-aware progress callback so GDAL can * unwind promptly when PostgreSQL requests cancellation (#4222). + * Use the band's nodata mask so large/infinite nodata values are excluded + * before polygonizing, bypassing the broken %f string-format filter (#6010). */ + GDALRasterBandH mask_band = iBandHasNodataValue + ? GDALGetMaskBand(gdal_band) + : NULL; cplerr = GDALFPolygonize( - gdal_band, NULL, hLayer, iPixVal, NULL, rt_util_gdal_progress_func, (void *)"GDALFPolygonize"); + gdal_band, mask_band, hLayer, iPixVal, NULL, rt_util_gdal_progress_func, (void *)"GDALFPolygonize"); if (cplerr != CE_None) { rterror("rt_raster_gdal_polygonize: Could not polygonize GDAL band"); @@ -1156,25 +1160,6 @@ rt_raster_gdal_polygonize( return NULL; } - /** - * Optimization: Apply a OGR SQL filter to the layer to select the - * features different from NODATA value. - * - * Thanks to David Zwarg. - **/ - if (iBandHasNodataValue) { - size_t sz = 50 * sizeof (char); - pszQuery = (char *) rtalloc(sz); - snprintf(pszQuery, sz, "PixelValue != %f", dBandNoData ); - OGRErr e = OGR_L_SetAttributeFilter(hLayer, pszQuery); - if (e != OGRERR_NONE) { - rtwarn("Error filtering NODATA values for band. All values will be treated as data values"); - } - } - else { - pszQuery = NULL; - } - /********************************************************************* * Transform OGR layers to WKB polygons * XXX jorgearevalo: GDALPolygonize does not set the coordinate system @@ -1193,8 +1178,6 @@ rt_raster_gdal_polygonize( if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv); OGR_Fld_Destroy(hFldDfn); OGR_DS_DeleteLayer(memdatasource, 0); - if (NULL != pszQuery) - rtdealloc(pszQuery); OGRReleaseDataSource(memdatasource); return NULL; @@ -1225,8 +1208,6 @@ rt_raster_gdal_polygonize( if (destroy_gdal_drv) GDALDestroyDriver(gdal_drv); OGR_Fld_Destroy(hFldDfn); OGR_DS_DeleteLayer(memdatasource, 0); - if (NULL != pszQuery) - rtdealloc(pszQuery); OGRReleaseDataSource(memdatasource); return NULL; @@ -1291,7 +1272,6 @@ rt_raster_gdal_polygonize( RASTER_DEBUG(3, "destroying OGR MEM vector"); OGR_Fld_Destroy(hFldDfn); OGR_DS_DeleteLayer(memdatasource, 0); - if (NULL != pszQuery) rtdealloc(pszQuery); OGRReleaseDataSource(memdatasource); return pols; diff --git a/raster/test/cunit/cu_gdal.c b/raster/test/cunit/cu_gdal.c index 18b1b6314..67fdaf55c 100644 --- a/raster/test/cunit/cu_gdal.c +++ b/raster/test/cunit/cu_gdal.c @@ -190,7 +190,8 @@ static void test_gdal_polygonize(void) { nPols = 0; gv = rt_raster_gdal_polygonize(rt, 0, TRUE, &nPols); - CU_ASSERT_DOUBLE_EQUAL(nPols, 4, FLT_EPSILON); + /* nodata=1.8 pixels are excluded: only 0.0 (x2 regions) and 2.8 remain */ + CU_ASSERT_DOUBLE_EQUAL(nPols, 3, FLT_EPSILON); total_area = 0; total_val = 0; for (i = 0; i < nPols; i++) { total_val += gv[i].val; @@ -199,8 +200,8 @@ static void test_gdal_polygonize(void) { lwgeom_free((LWGEOM *) gv[i].geom); } printf("total area, total_val, polys = %f, %f, %i\n", total_area, total_val, nPols); - CU_ASSERT_DOUBLE_EQUAL(total_val, 4.6, FLT_EPSILON); - CU_ASSERT_DOUBLE_EQUAL(total_area, 81, FLT_EPSILON); + CU_ASSERT_DOUBLE_EQUAL(total_val, 2.8, FLT_EPSILON); + CU_ASSERT_DOUBLE_EQUAL(total_area, 65, FLT_EPSILON); rtdealloc(gv); @@ -214,7 +215,8 @@ static void test_gdal_polygonize(void) { nPols = 0; gv = rt_raster_gdal_polygonize(rt, 0, TRUE, &nPols); - CU_ASSERT_DOUBLE_EQUAL(nPols, 4, FLT_EPSILON); + /* nodata=2.8 pixels are excluded: only 0.0 (x2 regions) and 1.8 remain */ + CU_ASSERT_DOUBLE_EQUAL(nPols, 3, FLT_EPSILON); total_area = 0; total_val = 0; for (i = 0; i < nPols; i++) { total_val += gv[i].val; @@ -224,8 +226,8 @@ static void test_gdal_polygonize(void) { } printf("total area, total_val, polys = %f, %f, %i\n", total_area, total_val, nPols); - CU_ASSERT_DOUBLE_EQUAL(total_val, 4.6, FLT_EPSILON); - CU_ASSERT_DOUBLE_EQUAL(total_area, 81, FLT_EPSILON); + CU_ASSERT_DOUBLE_EQUAL(total_val, 1.8, FLT_EPSILON); + CU_ASSERT_DOUBLE_EQUAL(total_area, 69, FLT_EPSILON); rtdealloc(gv); cu_free_raster(rt); diff --git a/raster/test/regress/rt_polygon.sql b/raster/test/regress/rt_polygon.sql index 111f089fa..ea1e3461d 100644 --- a/raster/test/regress/rt_polygon.sql +++ b/raster/test/regress/rt_polygon.sql @@ -151,3 +151,17 @@ FROM ( DROP FUNCTION temp_geos_version(); DROP TABLE IF EXISTS raster_polygon; + +-- #6010: nodata=FLT_MAX (32BF): only the 8 valid pixels should polygonize, not the nodata center pixel +SELECT count(*) = 1 FROM ST_DumpAsPolygons( + ST_SetValue( + ST_AddBand(ST_MakeEmptyRaster(3, 3, 0, 0, 1, -1, 0, 0, 0), + 1, '32BF'::text, -9.0, 3.4028234663852886e+38), + 1, 2, 2, 3.4028234663852886e+38)); + +-- #6010: nodata=DBL_MAX (64BF): only the 8 valid pixels should polygonize, not the nodata center pixel +SELECT count(*) = 1 FROM ST_DumpAsPolygons( + ST_SetValue( + ST_AddBand(ST_MakeEmptyRaster(3, 3, 0, 0, 1, -1, 0, 0, 0), + 1, '64BF'::text, -9.0, 1.7976931348623157e+308), + 1, 2, 2, 1.7976931348623157e+308)); diff --git a/raster/test/regress/rt_polygon_expected b/raster/test/regress/rt_polygon_expected index 3d2628a5e..22ec3b719 100644 --- a/raster/test/regress/rt_polygon_expected +++ b/raster/test/regress/rt_polygon_expected @@ -5,3 +5,5 @@ t t t t +t +t ----------------------------------------------------------------------- Summary of changes: raster/rt_core/rt_geometry.c | 32 ++++++-------------------------- raster/test/cunit/cu_gdal.c | 14 ++++++++------ raster/test/regress/rt_polygon.sql | 14 ++++++++++++++ raster/test/regress/rt_polygon_expected | 2 ++ 4 files changed, 30 insertions(+), 32 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 4 12:18:16 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 19:18:16 -0000 Subject: [PostGIS] #6010: ST_SetBandNoDataValue can't handle infinite no data In-Reply-To: <053.e75a882ed0a76b9cbe60661a303659f4@osgeo.org> References: <053.e75a882ed0a76b9cbe60661a303659f4@osgeo.org> Message-ID: <068.c641d7d9e8c8a9eff8539ba54149e144@osgeo.org> #6010: ST_SetBandNoDataValue can't handle infinite no data -------------------------+------------------------------------------------- Reporter: | Owner: robe GISuser5432 | Type: defect | Status: closed Priority: low | Milestone: PostGIS 3.2.10 Component: raster | Version: 3.6.x Resolution: fixed | Keywords: ST_Polygon (raster) ; Raster; | PostGIS_Raster; -------------------------+------------------------------------------------- Changes (by Paul Ramsey ): * resolution: => fixed * status: new => closed Comment: In [changeset:"f09adbed379aad9ed9374cd19ca7ec3b6c2c0b49/git" f09adbed/git]: {{{#!CommitTicketReference repository="git" revision="f09adbed379aad9ed9374cd19ca7ec3b6c2c0b49" Use nodata mask rather than a SQL filter in ST_Polygon Avoids polygonizing nodata areas with ST_Polygon, matches old behaviour pre-3.x (2018). Closes #6010 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 4 13:45:30 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 4 Jun 2026 13:45:30 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-497-g7318e9522 Message-ID: <20260604204531.004101A4AF8@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 7318e95222b33f24eb606e958eb48fcfef06411f (commit) from f09adbed379aad9ed9374cd19ca7ec3b6c2c0b49 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 7318e95222b33f24eb606e958eb48fcfef06411f Author: Paul Ramsey Date: Thu Jun 4 13:45:12 2026 -0700 Avoid Inf looping and memory use in ST_Split When fed with very large coordinates, ST_Split could be fooled into an Inf loop, this fixes that case, closes #5916 diff --git a/liblwgeom/lwgeom_geos_split.c b/liblwgeom/lwgeom_geos_split.c index a69b3d502..15ca6ff5c 100644 --- a/liblwgeom/lwgeom_geos_split.c +++ b/liblwgeom/lwgeom_geos_split.c @@ -282,9 +282,12 @@ lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in, LWDEBUGF(3, "Projected point:(%.15g %.15g), seg:%d, p1:(%.15g %.15g), p2:(%.15g %.15g)", pt_projected.x, pt_projected.y, seg, p1.x, p1.y, p2.x, p2.y); - /* When closest point == an endpoint, this is a boundary intersection */ - if ( ( (seg == nsegs-1) && P4D_SAME_STRICT(&pt_projected, &p2) ) || - ( (seg == 0) && P4D_SAME_STRICT(&pt_projected, &p1) ) ) + /* When closest point == an endpoint, this is a boundary intersection. + * Compare only X and Y since pt_projected.x/y were forced to pt.x/y above, + * and Z/M may be NaN when line coordinates are very large (causing Inf/Inf + * in closest_point_on_segment). See #5916. */ + if ( ( (seg == nsegs-1) && (pt_projected.x == p2.x) && (pt_projected.y == p2.y) ) || + ( (seg == 0) && (pt_projected.x == p1.x) && (pt_projected.y == p1.y) ) ) { return 1; } diff --git a/regress/core/split.sql b/regress/core/split.sql index a1087e171..3b82a6708 100644 --- a/regress/core/split.sql +++ b/regress/core/split.sql @@ -114,4 +114,8 @@ SELECT '#5635a', ST_Split('LINESTRING Z (1 2 NaN,3 4 10,5 6 NaN)'::geometry -- https://trac.osgeo.org/postgis/ticket/5635 (split by nan blade) SELECT '#5635b', ST_Split('LINESTRING Z (1 2 1,3 4 10,5 6 3)'::geometry ,'MULTIPOINT(1 NaN,2 1,2 4, 4 5)'::geometry); +-- https://trac.osgeo.org/postgis/ticket/5916 (split hangs on huge-but-finite coordinates) +SELECT '#5916', ST_NumGeometries(ST_Split( + ST_GeomFromText('LINESTRING(123456789 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999, 0 1)'), + ST_GeomFromText('MULTIPOINT(0 1, 0 0, 2 3)'))); -- TODO: split line by collapsed line diff --git a/regress/core/split_expected b/regress/core/split_expected index 62ec3cfeb..9e5be98a0 100644 --- a/regress/core/split_expected +++ b/regress/core/split_expected @@ -31,3 +31,4 @@ ERROR: Splitter line has linear intersection with input 87|SRID=4326;GEOMETRYCOLLECTION(LINESTRING EMPTY) ERROR: Input Geometry contains invalid coordinates ERROR: Blade Geometry contains invalid coordinates +#5916|1 ----------------------------------------------------------------------- Summary of changes: liblwgeom/lwgeom_geos_split.c | 9 ++++++--- regress/core/split.sql | 4 ++++ regress/core/split_expected | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 4 13:45:33 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 20:45:33 -0000 Subject: [PostGIS] #5916: ST_Split consumes excessive memory when input contains infinity values In-Reply-To: <047.d96a0100e8d34bc08ed7faaea76e286f@osgeo.org> References: <047.d96a0100e8d34bc08ed7faaea76e286f@osgeo.org> Message-ID: <062.ccd78c4ec3e7bd98172f915d78e859ca@osgeo.org> #5916: ST_Split consumes excessive memory when input contains infinity values ----------------------+--------------------------- Reporter: dmyzl | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.5.5 Component: postgis | Version: 3.5.x Resolution: fixed | Keywords: ST_Split ----------------------+--------------------------- Changes (by Paul Ramsey ): * resolution: => fixed * status: new => closed Comment: In [changeset:"7318e95222b33f24eb606e958eb48fcfef06411f/git" 7318e95/git]: {{{#!CommitTicketReference repository="git" revision="7318e95222b33f24eb606e958eb48fcfef06411f" Avoid Inf looping and memory use in ST_Split When fed with very large coordinates, ST_Split could be fooled into an Inf loop, this fixes that case, closes #5916 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 13:51:01 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 20:51:01 -0000 Subject: [PostGIS] Batch modify: #5903, #5317, #5408, #5487, #5655, #5786, ... In-Reply-To: <134.fccdbc024940e43defaa9492d6a67ba2@osgeo.org> References: <134.fccdbc024940e43defaa9492d6a67ba2@osgeo.org> Message-ID: <142.5138b17900913606722354b393a2d106@osgeo.org> Batch modification to #5903, #5317, #5408, #5487, #5655, #5786, #5797, #5840, #5859, #5864, #5886, #5904, #5914, #5930, #5931, #5932, #5933, #5958, #5772 by pramsey: milestone to PostGIS 3.5.6 -- Tickets URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 13:53:50 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 20:53:50 -0000 Subject: [PostGIS] Batch modify: #6075, #6072 In-Reply-To: <049.6ab1f03a22c23edf94b9e2b179bd9af3@osgeo.org> References: <049.6ab1f03a22c23edf94b9e2b179bd9af3@osgeo.org> Message-ID: <042.b69a4c77f8f403aa0923f2eaaea899ea@osgeo.org> Batch modification to #6075, #6072 by pramsey: milestone to None Comment: Ticket retargeted after milestone closed -- Tickets URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 13:58:17 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 20:58:17 -0000 Subject: [PostGIS] Batch modify: #5903, #5317, #5408, #5487, #5655, #5786, ... In-Reply-To: <139.7889972b843b83aab91f9bedd9088253@osgeo.org> References: <139.7889972b843b83aab91f9bedd9088253@osgeo.org> Message-ID: <147.4f332720cfe9653f012572e8ee069749@osgeo.org> Batch modification to #5903, #5317, #5408, #5487, #5655, #5786, #5797, #5840, #5859, #5864, #5886, #5904, #5914, #5930, #5931, #5932, #5933, #5958, #6063, #5772 by pramsey: milestone to PostGIS 3.5.7 -- Tickets URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:00:22 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:00:22 -0000 Subject: [PostGIS] #6038: Using public.geometry_columns causes 'could not open relation with OID 188954716' after drop geometry tables In-Reply-To: <050.410b70db9c436ac53a1e23f89f1c69ff@osgeo.org> References: <050.410b70db9c436ac53a1e23f89f1c69ff@osgeo.org> Message-ID: <065.2d7cee428cee3421bf7c1a6cd9c6a6fc@osgeo.org> #6038: Using public.geometry_columns causes 'could not open relation with OID 188954716' after drop geometry tables --------------------------------+--------------------------- Reporter: Lars Aksel Opsahl | Owner: strk Type: defect | Status: new Priority: blocker | Milestone: PostGIS 3.6.4 Component: topology | Version: master Resolution: | Keywords: --------------------------------+--------------------------- Changes (by pramsey): * milestone: => PostGIS 3.6.4 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:00:45 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:00:45 -0000 Subject: [PostGIS] #5309: ST_ClusterKMeans not working on PostGIS 3.23 In-Reply-To: <046.a083d2bb974560198459a52c54e030b4@osgeo.org> References: <046.a083d2bb974560198459a52c54e030b4@osgeo.org> Message-ID: <061.7e2088f131979bdb701d0b1d8803c5c7@osgeo.org> #5309: ST_ClusterKMeans not working on PostGIS 3.23 ----------------------+--------------------- Reporter: jbtw | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: Component: postgis | Version: 3.2.x Resolution: invalid | Keywords: ----------------------+--------------------- Changes (by pramsey): * resolution: => invalid * status: reopened => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:02:26 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:02:26 -0000 Subject: [PostGIS] #5228: ST_MakeEmptyCoverage creates a bad tiling In-Reply-To: <053.09b9b54624fa1c29354dec315cf199e1@osgeo.org> References: <053.09b9b54624fa1c29354dec315cf199e1@osgeo.org> Message-ID: <068.3ae177da012cd59180c93a047a9d1d4b@osgeo.org> #5228: ST_MakeEmptyCoverage creates a bad tiling ---------------------------+-------------------- Reporter: Arthur Bazin | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: Component: raster | Version: 3.2.x Resolution: worksforme | Keywords: ---------------------------+-------------------- Changes (by pramsey): * resolution: => worksforme * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:02:44 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:02:44 -0000 Subject: [PostGIS] #5273: GetNodeEdges should error out when given unexisting node In-Reply-To: <046.3f16d691b36cb0c8bb6b53eb17211421@osgeo.org> References: <046.3f16d691b36cb0c8bb6b53eb17211421@osgeo.org> Message-ID: <061.4046ccdafa38019486a743c5e02f9918@osgeo.org> #5273: GetNodeEdges should error out when given unexisting node -----------------------+-------------------- Reporter: strk | Owner: strk Type: defect | Status: closed Priority: medium | Milestone: Component: topology | Version: Resolution: invalid | Keywords: -----------------------+-------------------- Changes (by pramsey): * resolution: => invalid * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:03:22 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:03:22 -0000 Subject: [PostGIS] #4947: ST_Transform gives wrong projection result In-Reply-To: <050.8b47232f1a6f1c5bae0e05a0417c614b@osgeo.org> References: <050.8b47232f1a6f1c5bae0e05a0417c614b@osgeo.org> Message-ID: <065.b46dae6911f3817d55b4ef07df5b18ef@osgeo.org> #4947: ST_Transform gives wrong projection result -----------------------+--------------------- Reporter: prusswan | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: Component: postgis | Version: 3.1.x Resolution: invalid | Keywords: -----------------------+--------------------- Changes (by pramsey): * resolution: => invalid * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:03:50 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:03:50 -0000 Subject: [PostGIS] #5356: Make the postgis docker images available from cr.postgis.net In-Reply-To: <046.d487f8827062ae1f8c55fdb1d68e86cf@osgeo.org> References: <046.d487f8827062ae1f8c55fdb1d68e86cf@osgeo.org> Message-ID: <061.b6f04697a72e6710d4bad22d8513c5ad@osgeo.org> #5356: Make the postgis docker images available from cr.postgis.net --------------------------+-------------------------------------- Reporter: strk | Owner: robe Type: enhancement | Status: new Priority: medium | Milestone: Website Management, Bots Component: management | Version: master Resolution: | Keywords: --------------------------+-------------------------------------- Changes (by pramsey): * milestone: => Website Management, Bots * version: => master -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:04:05 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:04:05 -0000 Subject: [PostGIS] #5393: Error in postgis_valid_typmod In-Reply-To: <050.ce67f01a4a462f4a619980b688d93e46@osgeo.org> References: <050.ce67f01a4a462f4a619980b688d93e46@osgeo.org> Message-ID: <065.86239b816aac4b1a699f19a480a7c787@osgeo.org> #5393: Error in postgis_valid_typmod -----------------------+--------------------- Reporter: ezimanyi | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: Component: postgis | Version: 3.3.x Resolution: invalid | Keywords: -----------------------+--------------------- Changes (by pramsey): * resolution: => invalid * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:04:45 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:04:45 -0000 Subject: [PostGIS] #5398: ST_RemoveRepeatedPoints behaves unexpectedly on 3D input In-Reply-To: <051.7796835575d9be18e4c60abbcaa05de2@osgeo.org> References: <051.7796835575d9be18e4c60abbcaa05de2@osgeo.org> Message-ID: <066.370d82c572a9c61e636bbc2aa5c206fb@osgeo.org> #5398: ST_RemoveRepeatedPoints behaves unexpectedly on 3D input -------------------------+------------------------------------------------- Reporter: pimvdhelm | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: Component: postgis | Version: 3.3.x Resolution: invalid | Keywords: 3D, tolerance, | ST_RemoveRepeatedPoints -------------------------+------------------------------------------------- Changes (by pramsey): * resolution: => invalid * status: new => closed Comment: 2.5 D coordinates ignore Z except for representation. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:05:02 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:05:02 -0000 Subject: [PostGIS] #5672: Function ST_3DIntersects does not work for MULTILINESTRING and LINESTRING. In-Reply-To: <049.260a521a98afdeb01f4205d033d8a56c@osgeo.org> References: <049.260a521a98afdeb01f4205d033d8a56c@osgeo.org> Message-ID: <064.2b648457ac9f0f7a03e3d7bcda2f8d97@osgeo.org> #5672: Function ST_3DIntersects does not work for MULTILINESTRING and LINESTRING. ----------------------+--------------------- Reporter: Wenjing | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: Component: postgis | Version: 3.4.x Resolution: fixed | Keywords: ----------------------+--------------------- Changes (by pramsey): * resolution: => fixed * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:05:33 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:05:33 -0000 Subject: [PostGIS] #5673: Case studies link broken on postgis.net In-Reply-To: <046.8ac6c70aa601c8586389f6b249b12c3d@osgeo.org> References: <046.8ac6c70aa601c8586389f6b249b12c3d@osgeo.org> Message-ID: <061.2162a5a86a6915e87328122bc40701c4@osgeo.org> #5673: Case studies link broken on postgis.net ----------------------+-------------------------------------- Reporter: strk | Owner: robe Type: defect | Status: new Priority: medium | Milestone: Website Management, Bots Component: website | Version: master Resolution: | Keywords: casestudy, usecases ----------------------+-------------------------------------- Changes (by pramsey): * milestone: => Website Management, Bots * version: => master -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:06:09 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:06:09 -0000 Subject: [PostGIS] #5807: Joined table ST_Transform runs on each filter evaluation instead of just once per input row In-Reply-To: <049.300f7bf1efc2f0e07722ac43db44baba@osgeo.org> References: <049.300f7bf1efc2f0e07722ac43db44baba@osgeo.org> Message-ID: <064.d4c4d1ea711923e559e0811623099e1c@osgeo.org> #5807: Joined table ST_Transform runs on each filter evaluation instead of just once per input row ----------------------+--------------------------- Reporter: lnicola | Owner: pramsey Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.5.7 Component: postgis | Version: 3.5.x Resolution: | Keywords: ----------------------+--------------------------- Changes (by pramsey): * milestone: => PostGIS 3.5.7 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:07:29 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:07:29 -0000 Subject: [PostGIS] #5836: Different result with same table and same query in various PostGIS versions In-Reply-To: <052.e4afb0ead84052253cfb969e49ce0483@osgeo.org> References: <052.e4afb0ead84052253cfb969e49ce0483@osgeo.org> Message-ID: <067.158309da30d386fa1886daa9a6b7b1e7@osgeo.org> #5836: Different result with same table and same query in various PostGIS versions -------------------------+--------------------- Reporter: zhangyijun | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: Component: postgis | Version: 3.5.x Resolution: wontfix | Keywords: -------------------------+--------------------- Changes (by pramsey): * resolution: => wontfix * status: new => closed Comment: If the tile output is wrong, that's something to do something about. The size of outputs is not something I consider a regression. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:07:59 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:07:59 -0000 Subject: [PostGIS] #5865: A util metthod to repair topology when invalid cases found In-Reply-To: <050.53ab2485531453318f27faa983d92c28@osgeo.org> References: <050.53ab2485531453318f27faa983d92c28@osgeo.org> Message-ID: <065.adde4b64a8af3cd142cf6497a1be53a0@osgeo.org> #5865: A util metthod to repair topology when invalid cases found --------------------------------+--------------------------- Reporter: Lars Aksel Opsahl | Owner: strk Type: enhancement | Status: new Priority: medium | Milestone: PostGIS 3.7.0 Component: topology | Version: master Resolution: | Keywords: --------------------------------+--------------------------- Changes (by pramsey): * milestone: => PostGIS 3.7.0 * version: => master -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:08:20 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:08:20 -0000 Subject: [PostGIS] #5873: Postgres Topology and logical partitioning In-Reply-To: <050.157178fc0627faa49f358682e3c49c28@osgeo.org> References: <050.157178fc0627faa49f358682e3c49c28@osgeo.org> Message-ID: <065.06679d0e2252f5686f4bcb3e2cc206c1@osgeo.org> #5873: Postgres Topology and logical partitioning --------------------------------+--------------------------- Reporter: Lars Aksel Opsahl | Owner: strk Type: enhancement | Status: new Priority: medium | Milestone: PostGIS 3.7.0 Component: topology | Version: master Resolution: | Keywords: --------------------------------+--------------------------- Changes (by pramsey): * milestone: => PostGIS 3.7.0 * version: => master -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:09:03 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:09:03 -0000 Subject: [PostGIS] #5895: Distance Calculation Issue with `ST_DistanceSphere` In-Reply-To: <057.cc508822a8e6a9eaa70a2081ad54626f@osgeo.org> References: <057.cc508822a8e6a9eaa70a2081ad54626f@osgeo.org> Message-ID: <072.70e29621594896be81fe311101760ae4@osgeo.org> #5895: Distance Calculation Issue with `ST_DistanceSphere` ------------------------------+--------------------------- Reporter: giovannicimolin | Owner: pramsey Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.4.6 Component: postgis | Version: 3.4.x Resolution: | Keywords: ------------------------------+--------------------------- Changes (by pramsey): * milestone: => PostGIS 3.4.6 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:09:24 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:09:24 -0000 Subject: [PostGIS] #5990: Adding 2 lines to Postgis topology takes 2 hours in a production line we have In-Reply-To: <050.5fc19b458abc55e80bbb7820f01dafcd@osgeo.org> References: <050.5fc19b458abc55e80bbb7820f01dafcd@osgeo.org> Message-ID: <065.56b6d4fcf45e4a9257837252c23bdf7d@osgeo.org> #5990: Adding 2 lines to Postgis topology takes 2 hours in a production line we have --------------------------------+--------------------------- Reporter: Lars Aksel Opsahl | Owner: strk Type: defect | Status: reopened Priority: medium | Milestone: PostGIS 3.7.0 Component: topology | Version: 3.0.x Resolution: | Keywords: performance --------------------------------+--------------------------- Changes (by pramsey): * milestone: => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:09:54 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:09:54 -0000 Subject: [PostGIS] #6022: Add documentation on simplification performed by ST_AsMVTGeom In-Reply-To: <049.8d06e190fc385292e7a351ca01334593@osgeo.org> References: <049.8d06e190fc385292e7a351ca01334593@osgeo.org> Message-ID: <064.0c510e7fa960faa2c84a57263254f082@osgeo.org> #6022: Add documentation on simplification performed by ST_AsMVTGeom ----------------------------+--------------------------- Reporter: robintw | Owner: robe Type: enhancement | Status: new Priority: medium | Milestone: PostGIS 3.7.0 Component: documentation | Version: 3.5.x Resolution: | Keywords: ----------------------------+--------------------------- Changes (by pramsey): * milestone: => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:10:11 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:10:11 -0000 Subject: [PostGIS] #6034: Missing node when adding overlapping line In-Reply-To: <050.00fe4cf3809caf26d3d25a602c774226@osgeo.org> References: <050.00fe4cf3809caf26d3d25a602c774226@osgeo.org> Message-ID: <065.87b45f67b7e13b85e1cb4d76f3de5ae2@osgeo.org> #6034: Missing node when adding overlapping line --------------------------------+--------------------------- Reporter: Lars Aksel Opsahl | Owner: strk Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.7.0 Component: topology | Version: 3.6.x Resolution: | Keywords: --------------------------------+--------------------------- Changes (by pramsey): * milestone: => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:10:24 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:10:24 -0000 Subject: [PostGIS] #6075: Extend ST_GetFaceGeometry with a optional srid parameter for geom In-Reply-To: <050.576af3d8862a6003859386a81241cf59@osgeo.org> References: <050.576af3d8862a6003859386a81241cf59@osgeo.org> Message-ID: <065.ffd954a52d768c4424b423a87af96ad0@osgeo.org> #6075: Extend ST_GetFaceGeometry with a optional srid parameter for geom --------------------------------+--------------------------- Reporter: Lars Aksel Opsahl | Owner: strk Type: enhancement | Status: new Priority: medium | Milestone: PostGIS 3.7.0 Component: topology | Version: 3.6.x Resolution: | Keywords: --------------------------------+--------------------------- Changes (by pramsey): * milestone: => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:10:58 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:10:58 -0000 Subject: [PostGIS] #6035: shp2pgsql-gui Update In-Reply-To: <053.a11c22d3a984531304293d17b0d2eb5c@osgeo.org> References: <053.a11c22d3a984531304293d17b0d2eb5c@osgeo.org> Message-ID: <068.14d60086143088fb1fd9988f8b0798a6@osgeo.org> #6035: shp2pgsql-gui Update ------------------------------+-------------------- Reporter: Lo?c Bartoletti | Owner: robe Type: enhancement | Status: closed Priority: low | Milestone: Component: utils/shp2pgsql | Version: Resolution: wontfix | Keywords: gtk ------------------------------+-------------------- Changes (by pramsey): * resolution: => wontfix * status: new => closed Comment: I don't think we get enough usage from it, should probably remove and deprecate... -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 4 14:11:22 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 04 Jun 2026 21:11:22 -0000 Subject: [PostGIS] #6072: loader scripts for os type 'sh' do not create schema tiger_data In-Reply-To: <052.e62fa89168934007c19e959c1918be99@osgeo.org> References: <052.e62fa89168934007c19e959c1918be99@osgeo.org> Message-ID: <067.7c2195edec3143f08bb07c44c96de455@osgeo.org> #6072: loader scripts for os type 'sh' do not create schema tiger_data -----------------------------+--------------------------- Reporter: epolkerman | Owner: robe Type: defect | Status: new Priority: low | Milestone: PostGIS 3.6.4 Component: tiger geocoder | Version: 3.6.x Resolution: | Keywords: -----------------------------+--------------------------- Changes (by pramsey): * milestone: => PostGIS 3.6.4 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Fri Jun 5 09:32:22 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 05 Jun 2026 16:32:22 -0000 Subject: [PostGIS] #6045: PostGIS 3.2 no rule to make docs-localized In-Reply-To: <046.d5b2a034a127f9902be4eddaa9a003fb@osgeo.org> References: <046.d5b2a034a127f9902be4eddaa9a003fb@osgeo.org> Message-ID: <061.b4d162998971c0f33dd7f5cc4fa5c956@osgeo.org> #6045: PostGIS 3.2 no rule to make docs-localized ----------------------+---------------------------- Reporter: robe | Owner: strk Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.2.10 Component: build | Version: 3.2.x Resolution: wontfix | Keywords: ----------------------+---------------------------- Changes (by pramsey): * resolution: => wontfix * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sat Jun 6 21:40:14 2026 From: git at osgeo.org (git at osgeo.org) Date: Sat, 6 Jun 2026 21:40:14 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-498-g1af7ed1d6 Message-ID: <20260607044015.05C851C2B20@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 1af7ed1d6babb822ff3991e772ef4cd7fb22ade9 (commit) from 7318e95222b33f24eb606e958eb48fcfef06411f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1af7ed1d6babb822ff3991e772ef4cd7fb22ade9 Author: Regina Obe Date: Sun Jun 7 00:39:19 2026 -0400 Prep work for 3.7.0beta1 release - Update NEWS to add min requirements - Show What's new section in 3.7 docs - Update migrations for recently released stables diff --git a/NEWS b/NEWS index 48dcf7ea2..fb07650e6 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,9 @@ -PostGIS 3.7.0dev -xxxx/xx/xx +PostGIS 3.7.0beta1 +2026/06/xx -This version requires GEOS 3.10 or higher +This version requires GEOS 3.10 or higher. PostgreSQL 14-19beta1 required. Proj 6.1+ required. +To take advantage of all features postgis extension features, GEOS 3.15+ is needed. +To take advantage of all postgis_sfcgal extension features SFCGAL 2.2+ is needed. * Breaking Changes * diff --git a/doc/xsl-config.xml b/doc/xsl-config.xml index fb7904494..686de356e 100644 --- a/doc/xsl-config.xml +++ b/doc/xsl-config.xml @@ -21,6 +21,7 @@ + 3.7 3.6 3.6 3.5 diff --git a/extensions/upgradeable_versions.mk b/extensions/upgradeable_versions.mk index 13476d575..f8709f789 100644 --- a/extensions/upgradeable_versions.mk +++ b/extensions/upgradeable_versions.mk @@ -97,6 +97,7 @@ UPGRADEABLE_VERSIONS = \ 3.2.7 \ 3.2.8 \ 3.2.9 \ + 3.2.10 \ 3.3.0 \ 3.3.1 \ 3.3.2 \ @@ -107,18 +108,23 @@ UPGRADEABLE_VERSIONS = \ 3.3.7 \ 3.3.8 \ 3.3.9 \ + 3.3.10 \ 3.4.0 \ 3.4.1 \ 3.4.2 \ 3.4.3 \ 3.4.4 \ 3.4.5 \ + 3.4.6 \ 3.5.0 \ 3.5.1 \ 3.5.2 \ 3.5.3 \ 3.5.4 \ + 3.5.5 \ + 3.5.6 \ 3.6.0 \ 3.6.1 \ 3.6.2 \ - 3.6.3dev + 3.6.3 \ + 3.6.4 ----------------------------------------------------------------------- Summary of changes: NEWS | 8 +++++--- doc/xsl-config.xml | 1 + extensions/upgradeable_versions.mk | 8 +++++++- 3 files changed, 13 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sat Jun 6 22:39:34 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 07 Jun 2026 05:39:34 -0000 Subject: [PostGIS] #6079: Remove support for GEOS < 3.10 Message-ID: <046.1ee3eb60a1909f23f10dbaa3ab1f4c0c@osgeo.org> #6079: Remove support for GEOS < 3.10 ---------------------+--------------------------- Reporter: robe | Owner: strk Type: defect | Status: assigned Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.6.x Keywords: | ---------------------+--------------------------- I couldn't find a ticket for this so creating it https://gitea.osgeo.org/postgis/postgis/commit/8d6df5b8ef368723a125c62494a31b820b2454 I also think this may need more work. As it looks like we just prevent building against but haven't removed the ifdefs we had to guard against < 3.9. https://lists.osgeo.org/pipermail/postgis-devel/2026-January/030713.html -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sat Jun 6 22:41:44 2026 From: git at osgeo.org (git at osgeo.org) Date: Sat, 6 Jun 2026 22:41:44 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-499-g8b7cbaa81 Message-ID: <20260607054145.2EF2F1C2E98@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 8b7cbaa81af3561d34c0393fbc0e2d56d97be4ef (commit) from 1af7ed1d6babb822ff3991e772ef4cd7fb22ade9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 8b7cbaa81af3561d34c0393fbc0e2d56d97be4ef Author: Regina Obe Date: Sun Jun 7 01:41:24 2026 -0400 Add in breaking changes NEWS, removal of GEOS < 3.10 diff --git a/NEWS b/NEWS index fb07650e6..aaf9f2c05 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,7 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.2+ is needed https://github.com/postgis/address_standardizer (Paul Ramsey) - #6052, [tiger_geocoder] Extension removed and moved to https://git.osgeo.org/postgis/postgis_tiger_geocoder (Regina Obe) + - #6079, Remove support for GEOS < 3.10 (Sandro Santilli) * New Features * ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + 1 file changed, 1 insertion(+) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 7 05:00:30 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 07 Jun 2026 12:00:30 -0000 Subject: [PostGIS] #6079: Remove support for GEOS < 3.10 In-Reply-To: <046.1ee3eb60a1909f23f10dbaa3ab1f4c0c@osgeo.org> References: <046.1ee3eb60a1909f23f10dbaa3ab1f4c0c@osgeo.org> Message-ID: <061.f2c2a0161050f69187cf92cb0f495790@osgeo.org> #6079: Remove support for GEOS < 3.10 ----------------------+--------------------------- Reporter: robe | Owner: strk Type: defect | Status: assigned Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.6.x Resolution: | Keywords: ----------------------+--------------------------- Comment (by strk): The NEWS file needs to report this as a breaking change too, in case it wasn't done already -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Mon Jun 8 01:07:12 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 8 Jun 2026 01:07:12 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-501-g65e081184 Message-ID: <20260608080713.14C131310E6@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 65e0811847b3a6572ce496bd219ba69dc62e364f (commit) via 7826c60d05d8875df8d1b2152eb5a7baadc94d9f (commit) from 8b7cbaa81af3561d34c0393fbc0e2d56d97be4ef (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 65e0811847b3a6572ce496bd219ba69dc62e364f Merge: 8b7cbaa81 7826c60d0 Author: Darafei Praliaskouski Date: Mon Jun 8 12:06:48 2026 +0400 Merge branch 'codex/postgis-skill-scope' commit 7826c60d05d8875df8d1b2152eb5a7baadc94d9f Author: Darafei Praliaskouski Date: Mon May 4 08:54:27 2026 +0400 docs: keep PostGIS skill scope specific diff --git a/doc/SKILL.md b/doc/SKILL.md deleted file mode 100644 index 5d2504c44..000000000 --- a/doc/SKILL.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -name: postgis-skill -description: PostGIS-focused SQL tips, tricks and gotchas. Use when in need of dealing with geospatial data in Postgres. ---- - -## Documentation - - - Make sure every create statement or CTE has descriptive comment `--` in front of it. - - Write enough comments so you can deduce what was a requirement in the future and not walk in circles. - - Every feature needs to have comprehensive up-to-date documentation near it. - -## Style - - - PostGIS functions follow their spelling from the manual (`st_segmentize` -> `ST_Segmentize`). - - SQL is lowercase unless instructed otherwise. - - Values in databases and layers should be absolute as much as possible: store "birthday" or "construction date" instead of "age". - - Do not mix tabs and spaces in code. - - Add empty lines between logical blocks. - - Format the code nicely and consistently. - - Call geometry column `geom`; geography column `geog`. - -## Indexing - - - Create brin for all columns when creating large table that will be used for ad-hoc queries. - - If you have cache table that has a primary key, it makes sense to add values into `including` on same index for faster lookup. - -## Debugging - - - Make sure that error messages towards developer are better than just "500 Internal server error". - - Don't stub stuff out with insane fallbacks (like lat/lon=0) - instead make the rest of the code work around data absence and inform user. - - SQL files should to be idempotent: drop table if exists + create table as; add some comments to make people grasp queries faster. - - Create both "up' and "down/rollback" migration when creating new migrations for ease of iteration. - - Check `select postgis_full_version();` to see if all upgrades happened successfully. - - Don't run one SQL file from other SQL file - this quickly becomes a mess with relative file paths. - -## Raster - - - Do not work with GDAL on the filesystem. Import things into database and deal with data there. - -## SQL gotchas - - - `sum(case when A then 1 else 0 end)` is just `count() filter (where A)` - - `row_number() ... = 1` can likely be redone as `order by + limit 1` (possibly with `distinct on` or `lateral`) - - `exists(select 1 from ...)` is just `exists(select from ...)` - - `tags ->> 'key' = 'value'` is just `tags @> '{"key": "value"}` - works faster for indexes - - you can't just create ordered table and then rely on it to be ordered on scan without `order by` - -## PostGIS gotchas - - - Do not use geometry typmod unless requested (things like `geometry(multilinestring, 4326)`) - use plain `geometry` or `geography` instead. This removes clutter of `ST_Multi` and errors via `ST_SetSRID`. - - `ST_UnaryUnion(ST_Collect(geom))` is just `ST_Union(geom)` - - `ST_Buffer(geom, 0)` should be `ST_MakeValid(geom)` - - `select min(ST_Distance(..))` should be `select ST_Distance() ... order by a <-> b limit 1` to enable knn gist - - `order by ST_Distance(c.geog, t.geog)` should be `order by c.geog <-> t.geog` - - `ST_UnaryUnion` is a sign you're doing something wrong - - `ST_MakeValid` is a sign you're doing something wrong on the previous step - - be extra attintive when calling `ST_SetSRID`: check the actual projection of input data, check if it can be set correctly during input (`ST_GeomFromGeoJSON`, `EWKT`-style `SRID=4326;POINT(...`, `EWKB` allow that). Check if `ST_Transform` is needed instead. - - when looking for relation between point and polygon, prefer `ST_Intersects` to other topology predicates - - when generating complex geometry by walking raster or grid, may make sense to `ST_Simplify(geom, 0)` - - to generate neighbourhoods of predictable size, use `ST_ClusterKMeans` with k=2 and `max_radius` set to your distance. - - use `ST_AsEWKB` for binary representation instead of `ST_AsWKB` to keep SRID. - - Choosing projection: - SRID=4326 (2D longlat) when input or output is longitude and latitude and coordinate value is to be shown to user. - SRID=3857 (2D Spherical Mercator) when output will be shown on web map, ST_AsMVT, or 2D KNN requests of short distance are to be executed. - SRID=4978 (3D XYZ) when performing internal computations, line-of-sight, clustering and averaging across antimeridian. Beware: only use 3D-aware operations, ST_Force3DZ on 2D CRS data before calling ST_Transform to it. - - Instead of using `ST_Hexagon` / `ST_HexagonGrid` use `h3` extension. - - When you know the data is going to be dumped in binary form, gzipped and moved around, consider using `ST_QuantizeCoordinates` if precision is known. diff --git a/skills/postgis/SKILL.md b/skills/postgis/SKILL.md new file mode 100644 index 000000000..7ee79755e --- /dev/null +++ b/skills/postgis/SKILL.md @@ -0,0 +1,38 @@ +--- +name: postgis +description: PostGIS-specific SQL tips and gotchas. Use when working with geometry, geography, raster, projections, spatial indexes, or geospatial processing in PostgreSQL through PostGIS. +--- + +## Naming + + - Spell PostGIS functions as they appear in the manual (`st_segmentize` -> `ST_Segmentize`). + - Call geometry columns `geom`; call geography columns `geog`. + +## Checks + + - Check `select postgis_full_version();` to confirm the installed PostGIS, GEOS, PROJ, GDAL, and SFCGAL versions when debugging extension behavior. + +## Raster + + - Do not work with GDAL on the filesystem. Import things into database and deal with data there. + +## Gotchas + + - Do not use geometry typmod unless requested (things like `geometry(multilinestring, 4326)`) - use plain `geometry` or `geography` instead. This removes clutter of `ST_Multi` and errors via `ST_SetSRID`. + - `ST_UnaryUnion(ST_Collect(geom))` is just `ST_Union(geom)`. + - `ST_Buffer(geom, 0)` should be `ST_MakeValid(geom)` when invalid geometry must be repaired, but first prefer fixing the source of invalid geometry upstream. + - `select min(ST_Distance(..))` should be `select ST_Distance() ... order by a <-> b limit 1` to enable knn gist. + - `order by ST_Distance(c.geog, t.geog)` should be `order by c.geog <-> t.geog`. + - `ST_UnaryUnion` is a sign you're doing something wrong. + - Needing `ST_MakeValid` is a sign you're doing something wrong on the previous step. + - Be extra attentive when calling `ST_SetSRID`: first check the actual projection of input data. Prefer setting the SRID during input when the source format supports it, for example with `ST_GeomFromGeoJSON`, EWKT like `SRID=4326;POINT(1 2)`, or EWKB; use `ST_Transform` instead if reprojection is needed. + - When looking for relation between point and polygon, prefer `ST_Intersects` to other topology predicates. + - When generating complex geometry by walking raster or grid, it may make sense to `ST_Simplify(geom, 0)`. + - To generate neighbourhoods of predictable size, use `ST_ClusterKMeans` with `k = 2` and `max_radius` set to your distance. + - Use `ST_AsEWKB` for binary representation instead of `ST_AsWKB` to keep SRID. + - Choosing projection: + SRID=4326 (2D longlat) when input or output is longitude and latitude and coordinate value is to be shown to user. + SRID=3857 (2D Spherical Mercator) when output will be shown on web map, ST_AsMVT, or 2D KNN requests of short distance are to be executed. + SRID=4978 (3D XYZ) when performing internal computations, line-of-sight, clustering and averaging across antimeridian. Beware: only use 3D-aware operations, ST_Force3DZ on 2D CRS data before calling ST_Transform to it. + - Instead of using `ST_Hexagon` / `ST_HexagonGrid`, use the `h3` extension. + - When you know the data is going to be dumped in binary form, gzipped and moved around, consider using `ST_QuantizeCoordinates` if precision is known. diff --git a/skills/sql-programming/SKILL.md b/skills/sql-programming/SKILL.md new file mode 100644 index 000000000..ef035204e --- /dev/null +++ b/skills/sql-programming/SKILL.md @@ -0,0 +1,39 @@ +--- +name: sql-programming +description: General SQL programming, formatting, debugging, and query-shaping tips. Use for SQL work that is not specifically about PostGIS spatial data. +--- + +## Documentation + + - Make sure every create statement or CTE has a descriptive comment `--` in front of it. + - Write enough comments so you can deduce what was a requirement in the future and not walk in circles. + - Every feature needs to have comprehensive up-to-date documentation near it. + +## Style + + - SQL is lowercase unless instructed otherwise. + - Values in databases and layers should be absolute as much as possible: store "birthday" or "construction date" instead of "age". + - Do not mix tabs and spaces in code. + - Add empty lines between logical blocks. + - Format the code nicely and consistently. + +## Indexing + + - Consider BRIN indexes for very large naturally ordered tables that will be used for ad-hoc range queries. + - If you have a cache table that has a primary key, it can make sense to add frequently read values into `including` on the same index for faster lookup. + +## Debugging + + - Make sure error messages towards developers are better than just "500 Internal Server Error". + - Don't stub stuff out with insane fallbacks like `lat = 0` and `lon = 0`; instead make the rest of the code work around data absence and inform the user. + - SQL files should be idempotent: drop table if exists + create table as; add comments to make queries faster to grasp. + - Create both "up" and "down/rollback" migrations when the project expects reversible migrations. + - Don't run one SQL file from another SQL file - this quickly becomes a mess with relative file paths. + +## SQL Gotchas + + - `sum(case when A then 1 else 0 end)` is just `count() filter (where A)`. + - `row_number() ... = 1` can likely be redone as `order by + limit 1` (possibly with `distinct on` or `lateral`). + - `exists(select 1 from ...)` is just `exists(select from ...)`. + - `tags ->> 'key' = 'value'` is just `tags @> '{"key": "value"}'` - works faster with indexes. + - You can't create an ordered table and then rely on it to be ordered on scan without `order by`. ----------------------------------------------------------------------- Summary of changes: doc/SKILL.md | 67 ----------------------------------------- skills/postgis/SKILL.md | 38 +++++++++++++++++++++++ skills/sql-programming/SKILL.md | 39 ++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 67 deletions(-) delete mode 100644 doc/SKILL.md create mode 100644 skills/postgis/SKILL.md create mode 100644 skills/sql-programming/SKILL.md hooks/post-receive -- PostGIS From trac at osgeo.org Mon Jun 8 07:19:53 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 08 Jun 2026 14:19:53 -0000 Subject: [PostGIS] #6079: Remove support for GEOS < 3.10 In-Reply-To: <046.1ee3eb60a1909f23f10dbaa3ab1f4c0c@osgeo.org> References: <046.1ee3eb60a1909f23f10dbaa3ab1f4c0c@osgeo.org> Message-ID: <061.c5ce925000f691ba2a0ee101cc7e8f3e@osgeo.org> #6079: Remove support for GEOS < 3.10 ----------------------+--------------------------- Reporter: robe | Owner: strk Type: defect | Status: assigned Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.6.x Resolution: | Keywords: ----------------------+--------------------------- Comment (by strk): Regina thanks for adding the missing NEWS entry but is there any conditional you saw that isn't needed anymore ? All I can find is for versions that are between 3.10 and higher, nothing that guards against < 3.9 {{{ $ git grep 'if .*POSTGIS_GEOS_VERSION' configure.ac:if test "$POSTGIS_GEOS_VERSION" -ge "$GEOS_MIN_VERSION_NUMERIC"; then configure.ac:if test "$POSTGIS_GEOS_VERSION" -lt 31200; then doc/developer.md: #if POSTGIS_GEOS_VERSION < 31300 liblwgeom/liblwgeom.h.in:#if POSTGIS_GEOS_VERSION >= 31100 liblwgeom/lwgeom_geos.c:#if POSTGIS_GEOS_VERSION < 31100 liblwgeom/lwgeom_geos.c:#if POSTGIS_GEOS_VERSION >= 31200 liblwgeom/lwgeom_geos.c:#if POSTGIS_GEOS_VERSION >= 31100 liblwgeom/lwgeom_geos.h:#if POSTGIS_GEOS_VERSION < 31300 liblwgeom/lwgeom_geos_cluster.c:#if POSTGIS_GEOS_VERSION >= 31300 postgis/lwgeom_geos.c:#if POSTGIS_GEOS_VERSION < 31100 postgis/lwgeom_geos.c:#if POSTGIS_GEOS_VERSION < 31100 postgis/lwgeom_geos.c:#if POSTGIS_GEOS_VERSION < 31100 postgis/lwgeom_geos_predicates.c:#if POSTGIS_GEOS_VERSION >= 31300 postgis/lwgeom_geos_predicates.c:#if POSTGIS_GEOS_VERSION >= 31300 postgis/lwgeom_geos_predicates.c:#if POSTGIS_GEOS_VERSION >= 31300 postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION < 31300 postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION >= 31200 postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION >= 31400 postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION >= 31400 postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION >= 31400 postgis/lwgeom_window.c:#endif /* POSTGIS_GEOS_VERSION >= 31200 */ postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION < 31200 postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION < 31200 postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION < 31400 postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION < 31500 postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION < 31500 postgis/lwgeom_window.c:#if POSTGIS_GEOS_VERSION < 31500 postgis/postgis.sql.in:#if POSTGIS_GEOS_VERSION >= 31100 raster/rt_core/librtcore.h:#if POSTGIS_GEOS_VERSION >= 31400 raster/rt_core/rt_spatial_relationship.c:#if POSTGIS_GEOS_VERSION >= 31400 raster/rt_core/rt_spatial_relationship.c:#endif /* POSTGIS_GEOS_VERSION >= 31400 */ raster/rt_pg/rtpg_spatial_relationship.c:#if POSTGIS_GEOS_VERSION < 31400 raster/rt_pg/rtpg_spatial_relationship.c:#endif /* POSTGIS_GEOS_VERSION < 31400 */ }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Mon Jun 8 07:45:26 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 8 Jun 2026 07:45:26 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-504-g18d5a182e Message-ID: <20260608144527.3E5D019891B@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 18d5a182ec414673f583da21ac1d9975f19e967d (commit) via 75870db9056ff0a905df53181e7a42448386d328 (commit) via 8d491659bd0ed42baedcf96ff3c741611ffa43c4 (commit) from 65e0811847b3a6572ce496bd219ba69dc62e364f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 18d5a182ec414673f583da21ac1d9975f19e967d Author: Lo?c Bartoletti Date: Mon Jun 8 12:51:30 2026 +0200 build: add FreeBSD docbook-ns xsl path to configure search list diff --git a/configure.ac b/configure.ac index fbc92932b..4de164b61 100644 --- a/configure.ac +++ b/configure.ac @@ -322,6 +322,7 @@ if test "x$XSLBASE" = "x"; then /usr/share/sgml/docbook/stylesheet/xsl/nwalsh /opt/local/share/xsl/docbook-xsl /usr/local/opt/docbook-xsl/docbook-xsl + /usr/local/share/xsl/docbook-ns /usr/local/share/xsl/docbook-xsl /usr/share/xsl/docbook-xsl " commit 75870db9056ff0a905df53181e7a42448386d328 Author: Lo?c Bartoletti Date: Mon Jun 8 12:42:08 2026 +0200 fix(loader): initialize pgfieldlens and pgfieldtypmods to NULL in ShpDumperCreate diff --git a/loader/pgsql2shp-core.c b/loader/pgsql2shp-core.c index 0d6e43486..47d2daf11 100644 --- a/loader/pgsql2shp-core.c +++ b/loader/pgsql2shp-core.c @@ -1177,6 +1177,8 @@ ShpDumperCreate(SHPDUMPERCONFIG *config) state->dbffieldnames = NULL; state->dbffieldtypes = NULL; state->pgfieldnames = NULL; + state->pgfieldlens = NULL; + state->pgfieldtypmods = NULL; state->message[0] = '\0'; colmap_init(&state->column_map); commit 8d491659bd0ed42baedcf96ff3c741611ffa43c4 Author: Lo?c Bartoletti Date: Fri Jun 5 08:07:16 2026 +0200 ci: replace cirrus-ci by github actions diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index bf74e73ba..000000000 --- a/.cirrus.yml +++ /dev/null @@ -1,158 +0,0 @@ -task: - # only_if: $CIRRUS_BRANCH =~ 'pull/.*' - name: FreeBSD - alias: test-freebsd - env: - CIRRUS_CLONE_DEPTH: 1 - CCACHE_DIR: "/tmp/ccache_dir" - NCPU: 2 - MAKEJOBS: "-j${NCPU}" - CC: "ccache clang" - CXX: "ccache clang++" - CCACHE_MAXSIZE: 1 - CCACHE_COMPRESS: 1 - CCACHE_STATIC_PREFIX: "/usr/local" - CCACHE_NOSTATS: 1 - CCACHE_TEMPDIR: "/tmp" - BASEFS: "${CIRRUS_WORKING_DIR}/test_bulk" - freebsd_cache: - folder: ${CCACHE_DIR} - pkg_bootstrap_script: - - | - sed -i.bak -e 's,pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly,pkg+http://pkg.FreeBSD.org/\${ABI}/latest,' /etc/pkg/FreeBSD.conf - ASSUME_ALWAYS_YES=yes pkg bootstrap -f - pkg_cache: - folder: /var/cache/pkg - populate_script: - pkg fetch -udy autoconf automake bison cunit docbook gdal geos gmake iconv json-c libtool libxml2 libxslt pkgconf postgresql17-contrib postgresql17-server proj protobuf-c sfcgal - install_pkgs_script: - - | - env IGNORE_OSVERSION=yes pkg update -f - env IGNORE_OSVERSION=yes pkg install -y autoconf automake bison cunit docbook gdal geos gmake iconv json-c libtool libxml2 libxslt pkgconf postgresql17-contrib postgresql17-server proj protobuf-c sfcgal - projsync --system-directory --source-id us_noaa - projsync --system-directory --source-id ch_swisstopo - ccache_setup_script: - - | - env IGNORE_OSVERSION=yes pkg install -y ccache-static - ccache --max-size=${CCACHE_MAXSIZE} - patch_script: - - | - find . -name "*.pl" | xargs sed -i -r 's|/usr/bin/perl|/usr/bin/env perl|' - build_script: - - | - ./autogen.sh - ./configure PKG_CONFIG=/usr/local/bin/pkgconf CFLAGS="-isystem /usr/local/include -Wall -fno-omit-frame-pointer -Werror" LDFLAGS="-L/usr/local/lib" --with-libiconv-prefix=/usr/local --without-gui --with-topology --without-raster --with-sfcgal=/usr/local/bin/sfcgal-config --with-protobuf - service postgresql oneinitdb - service postgresql onestart - su postgres -c "createuser -s `whoami`" - gmake ${MAKEJOBS} || { service postgresql onestop; exit 1; } - gmake ${MAKEJOBS} install || { service postgresql onestop; exit 1; } - ccache -s - test_script: - - | - show_regression_diffs() { - local tmpdir="${PGIS_REG_TMPDIR:-/tmp/pgis_reg}" - local found=0 - for f in "${tmpdir}"/*_diff; do - [ -f "${f}" ] || continue - if [ "${found}" -eq 0 ]; then - echo "---- BEGIN REGRESSION DIFFS (${tmpdir}) ----" - fi - found=1 - echo "---- ${f} ----" - cat "${f}" - done - if [ "${found}" -eq 0 ]; then - echo "No regression diff files found in ${tmpdir}" - else - echo "---- END REGRESSION DIFFS ----" - fi - } - gmake ${MAKEJOBS} check RUNTESTFLAGS="-v --extension --dumprestore" || { - show_regression_diffs - service postgresql onestop - exit 1 - } - service postgresql onestop - freebsd_instance: - cpu: ${NCPU} - memory: 8G - matrix: - - name: 14.3-RELEASE - freebsd_instance: - image_family: freebsd-14-3 - -task: - name: macOS - alias: test-macos - macos_instance: - image: ghcr.io/cirruslabs/macos-runner:sonoma - - env: - CC: "ccache clang" - CXX: "ccache clang++" - CCACHE_DIR: "$HOME/.ccache" - CCACHE_MAXSIZE: 1 - PG: "17" - HOMEBREW_PREFIX: "/opt/homebrew" - PATH: "${HOMEBREW_PREFIX}/opt/postgresql@${PG}/bin:${HOMEBREW_PREFIX}/bin:${HOMEBREW_PREFIX}/sbin:${HOMEBREW_PREFIX}/opt/ccache/libexec:$PATH" - - setup_script: - - | - brew update - brew install ccache autoconf automake libtool pkg-config gdal geos icu4c json-c libpq libxml2 proj protobuf-c sfcgal cunit docbook docbook-xsl postgresql@${PG} gettext - brew link --force gettext - ccache --max-size=$CCACHE_MAXSIZE - sudo ln -sfn ${HOMEBREW_PREFIX}/opt/postgresql@${PG}/bin/postgres /usr/local/bin/postgres - - test_script: - - | - show_regression_diffs() { - local tmpdir="${PGIS_REG_TMPDIR:-/tmp/pgis_reg}" - local found=0 - for f in "${tmpdir}"/*_diff; do - [ -f "${f}" ] || continue - if [ "${found}" -eq 0 ]; then - echo "---- BEGIN REGRESSION DIFFS (${tmpdir}) ----" - fi - found=1 - echo "---- ${f} ----" - cat "${f}" - done - if [ "${found}" -eq 0 ]; then - echo "No regression diff files found in ${tmpdir}" - else - echo "---- END REGRESSION DIFFS ----" - fi - } - - export PGCONFIG="${HOMEBREW_PREFIX}/opt/postgresql@${PG}/bin/pg_config" - export CFLAGS="-I${HOMEBREW_PREFIX}/opt/gettext/include \ - -I${HOMEBREW_PREFIX}/opt/postgresql@${PG}/include \ - -I${HOMEBREW_PREFIX}/include -Wno-nullability-completeness" - export LDFLAGS="-L${HOMEBREW_PREFIX}/opt/gettext/lib \ - -L${HOMEBREW_PREFIX}/opt/postgresql@${PG}/lib" - export CXXFLAGS="-std=c++17" - - ./autogen.sh - ./configure --without-gui \ - --without-interrupt-tests \ - --with-topology \ - --without-raster \ - --with-sfcgal \ - --with-protobuf \ - --with-pgconfig=${PGCONFIG} - - brew services start postgresql@${PG} - make -j$(sysctl -n hw.logicalcpu) || { brew services stop postgresql@${PG}; exit 1; } - make -j$(sysctl -n hw.logicalcpu) check || { - show_regression_diffs - brew services stop postgresql@${PG} - exit 1 - } - brew services stop postgresql@${PG} - - macos_cache: - folders: ${CCACHE_DIR} - - upload_caches: macos diff --git a/.github/workflows/ci-freebsd.yml b/.github/workflows/ci-freebsd.yml new file mode 100644 index 000000000..93f7360fe --- /dev/null +++ b/.github/workflows/ci-freebsd.yml @@ -0,0 +1,119 @@ +# GitHub Actions ? FreeBSD CI +# Replaces .cirrus.yml + +name: "CI (FreeBSD)" + +on: + push: + branches-ignore: + - 'master' + pull_request: ~ + +jobs: + + freebsd: + name: "FreeBSD ${{ matrix.version }}" + runs-on: ubuntu-latest + env: + CCACHE_DIR: "${{ github.workspace }}/.ccache" + CCACHE_MAXSIZE: "1G" + strategy: + fail-fast: false + matrix: + version: + - "14.3" + steps: + - uses: actions/checkout at 11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Cache ccache + uses: actions/cache at 27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ${{ env.CCACHE_DIR }} + key: freebsd-${{ matrix.version }}-ccache-${{ github.sha }} + restore-keys: | + freebsd-${{ matrix.version }}-ccache- + + - name: Build and test on FreeBSD + uses: vmactions/freebsd-vm at a6de9343ef5747433d9c25784c90e84998b9d69a # v1.4.6 + with: + release: ${{ matrix.version }} + usesh: true + sync: rsync + copyback: true + prepare: | + sed -i.bak \ + -e 's,pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly,pkg+http://pkg.FreeBSD.org/\${ABI}/latest,' \ + /etc/pkg/FreeBSD.conf + ASSUME_ALWAYS_YES=yes pkg bootstrap -f + env IGNORE_OSVERSION=yes pkg update -f + env IGNORE_OSVERSION=yes pkg install -y \ + autoconf automake bison ccache-static cunit docbook \ + gdal geos gmake iconv json-c libtool libxml2 libxslt \ + pkgconf postgresql17-contrib postgresql17-server \ + proj protobuf-c sfcgal + projsync --system-directory --source-id us_noaa + projsync --system-directory --source-id ch_swisstopo + run: | + set -e + + export CC="ccache clang" + export CXX="ccache clang++" + export CCACHE_DIR="${{ github.workspace }}/.ccache" + export CCACHE_MAXSIZE="1G" + export CCACHE_COMPRESS=1 + export CCACHE_STATIC_PREFIX="/usr/local" + export CCACHE_NOSTATS=1 + export CCACHE_TEMPDIR="/tmp" + export MAKEJOBS="-j2" + + ccache --max-size="${CCACHE_MAXSIZE}" + + find . -name "*.pl" | xargs sed -i '' 's|/usr/bin/perl|/usr/bin/env perl|' + + ./autogen.sh + ./configure \ + PKG_CONFIG=/usr/local/bin/pkgconf \ + CFLAGS="-isystem /usr/local/include -Wall -fno-omit-frame-pointer -Werror" \ + LDFLAGS="-L/usr/local/lib" \ + --with-libiconv-prefix=/usr/local \ + --without-gui \ + --with-topology \ + --without-raster \ + --with-sfcgal=/usr/local/bin/sfcgal-config \ + --with-protobuf + + service postgresql oneinitdb + service postgresql onestart + su postgres -c "createuser -s $(whoami)" + + gmake ${MAKEJOBS} || { service postgresql onestop; exit 1; } + gmake ${MAKEJOBS} install || { service postgresql onestop; exit 1; } + ccache -s + + show_regression_diffs() { + local tmpdir="${PGIS_REG_TMPDIR:-/tmp/pgis_reg}" + local found=0 + for f in "${tmpdir}"/*_diff; do + [ -f "${f}" ] || continue + if [ "${found}" -eq 0 ]; then + echo "---- BEGIN REGRESSION DIFFS (${tmpdir}) ----" + fi + found=1 + echo "---- ${f} ----" + cat "${f}" + done + if [ "${found}" -eq 0 ]; then + echo "No regression diff files found in ${tmpdir}" + else + echo "---- END REGRESSION DIFFS ----" + fi + } + + gmake ${MAKEJOBS} check RUNTESTFLAGS="-v --extension --dumprestore" || { + show_regression_diffs + service postgresql onestop + exit 1 + } + service postgresql onestop diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml new file mode 100644 index 000000000..27c3cd565 --- /dev/null +++ b/.github/workflows/ci-macos.yml @@ -0,0 +1,98 @@ +# GitHub Actions ? macOS CI +# Replaces .cirrus.yml + +name: "CI (macOS)" + +on: + push: + branches-ignore: + - 'master' + pull_request: ~ + +jobs: + + macos: + name: "macOS" + runs-on: macos-latest + env: + PG: "17" + HOMEBREW_PREFIX: "/opt/homebrew" + CCACHE_DIR: "${{ github.workspace }}/.ccache" + CCACHE_MAXSIZE: "1G" + steps: + - uses: actions/checkout at 11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Cache ccache + uses: actions/cache at 27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ${{ env.CCACHE_DIR }} + key: macos-ccache-${{ github.sha }} + restore-keys: | + macos-ccache- + + - name: Install dependencies + run: | + brew update + brew install \ + autoconf automake libtool pkg-config \ + ccache \ + gdal geos icu4c json-c libpq libxml2 \ + proj protobuf-c sfcgal cunit \ + docbook docbook-xsl \ + postgresql@${PG} gettext + brew link --force gettext + ccache --max-size="${CCACHE_MAXSIZE}" + sudo ln -sfn "${HOMEBREW_PREFIX}/opt/postgresql@${PG}/bin/postgres" /usr/local/bin/postgres + + - name: Build and test + env: + CC: "ccache clang" + CXX: "ccache clang++" + run: | + export PATH="${HOMEBREW_PREFIX}/opt/postgresql@${PG}/bin:${HOMEBREW_PREFIX}/bin:${HOMEBREW_PREFIX}/sbin:${HOMEBREW_PREFIX}/opt/ccache/libexec:${PATH}" + export PGCONFIG="${HOMEBREW_PREFIX}/opt/postgresql@${PG}/bin/pg_config" + export CFLAGS="-I${HOMEBREW_PREFIX}/opt/gettext/include -I${HOMEBREW_PREFIX}/opt/postgresql@${PG}/include -I${HOMEBREW_PREFIX}/include -Wno-nullability-completeness" + export LDFLAGS="-L${HOMEBREW_PREFIX}/opt/gettext/lib -L${HOMEBREW_PREFIX}/opt/postgresql@${PG}/lib" + export CXXFLAGS="-std=c++17" + + show_regression_diffs() { + local tmpdir="${PGIS_REG_TMPDIR:-/tmp/pgis_reg}" + local found=0 + for f in "${tmpdir}"/*_diff; do + [ -f "${f}" ] || continue + if [ "${found}" -eq 0 ]; then + echo "---- BEGIN REGRESSION DIFFS (${tmpdir}) ----" + fi + found=1 + echo "---- ${f} ----" + cat "${f}" + done + if [ "${found}" -eq 0 ]; then + echo "No regression diff files found in ${tmpdir}" + else + echo "---- END REGRESSION DIFFS ----" + fi + } + + ./autogen.sh + ./configure \ + --without-gui \ + --without-interrupt-tests \ + --with-topology \ + --without-raster \ + --with-sfcgal \ + --with-protobuf \ + --with-pgconfig="${PGCONFIG}" + + brew services start "postgresql@${PG}" + + make -j$(sysctl -n hw.logicalcpu) || { brew services stop "postgresql@${PG}"; exit 1; } + sudo make install || { brew services stop "postgresql@${PG}"; exit 1; } + make -j$(sysctl -n hw.logicalcpu) check RUNTESTFLAGS="-v --extension --dumprestore" || { + show_regression_diffs + brew services stop "postgresql@${PG}" + exit 1 + } + brew services stop "postgresql@${PG}" diff --git a/make_dist.sh b/make_dist.sh index 601e62ac0..bda4c2ce4 100755 --- a/make_dist.sh +++ b/make_dist.sh @@ -63,7 +63,6 @@ rm -fv "$outdir"/make_dist.sh "$outdir"/HOWTO_RELEASE echo "Removing ci files" rm -rfv \ "$outdir"/ci \ - "$outdir"/.cirrus.yml \ "$outdir"/.clang-format \ "$outdir"/.dron*.yml \ "$outdir"/.github \ diff --git a/utils/ci-trac-line.sh b/utils/ci-trac-line.sh index 744d74324..d0abef4f4 100755 --- a/utils/ci-trac-line.sh +++ b/utils/ci-trac-line.sh @@ -17,7 +17,8 @@ cat < This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 0c06ae1dc5dbb4877ef90c79122ca88f6425b465 (commit) from 18d5a182ec414673f583da21ac1d9975f19e967d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 0c06ae1dc5dbb4877ef90c79122ca88f6425b465 Author: Lo?c Bartoletti Date: Mon Jun 8 15:30:47 2026 +0200 test(sfcgal): replace flaky alpha-shape 2-component test with integer input diff --git a/sfcgal/regress/alphashape_components.sql b/sfcgal/regress/alphashape_components.sql index 38e896ffd..6baff0256 100644 --- a/sfcgal/regress/alphashape_components.sql +++ b/sfcgal/regress/alphashape_components.sql @@ -1,4 +1,23 @@ +-- CG_OptimalAlphaShape with nb_components=2, allow_holes=false +-- Two rectangular-frame clusters with integer coordinates. +-- Integer-only input avoids floating-point borderline cases and produces +-- identical results regardless of compiler or CGAL minor version. SELECT 'CG_Optimalalphashape_2components', - ST_AsText(CG_OptimalAlphaShape('MULTIPOINT((10.1 0.2),(8.1 0.1),(6.0 0.0),(4.2 0.3),(2.5 1.0),(1.2 2.3),(0.4 4.0),(0.1 6.1),(0.3 8.2),(1.1 10.1),(2.6 11.2),(4.1 11.9),(6.2 12.1),(8.3 11.8),(10.2 11.1),(9.1 9.9),(7.6 9.8),(6.1 9.9),(4.8 9.2),(3.8 8.0),(3.6 6.2),(3.7 4.1),(4.6 2.9),(6.0 2.3),(7.8 2.2),(9.2 2.4),(40.3 0.4),(40.1 3.1),(39.8 6.2),(40.4 9.0),(40.2 12.3),(40.5 15.2),(41.9 15.6),(43.1 15.3),(54.3 15.2),(55.8 15.0),(55.6 12.1),(55.9 9.2),(55.5 6.0),(55.7 3.3),(55.4 0.5),(52.6 0.1),(49.8 -0.2),(46.9 2.8),(44.2 0.2),(42.1 0.3),(43.0 3.8),(43.3 7.1),(43.1 10.4),(52.9 10.6),(52.7 7.3),(52.8 4.1))', allow_holes => false, nb_components => 2)); + ST_AsText(CG_OptimalAlphaShape('MULTIPOINT( + (0 0),(1 0),(2 0),(3 0),(4 0),(5 0), + (0 1),(5 1), + (0 2),(5 2), + (0 3),(1 3),(2 3),(3 3),(4 3),(5 3), + (0 4),(5 4), + (0 5),(5 5), + (0 6),(1 6),(2 6),(3 6),(4 6),(5 6), + (30 0),(31 0),(32 0),(33 0),(34 0),(35 0), + (30 1),(35 1), + (30 2),(35 2), + (30 3),(31 3),(32 3),(33 3),(34 3),(35 3), + (30 4),(35 4), + (30 5),(35 5), + (30 6),(31 6),(32 6),(33 6),(34 6),(35 6) +)', allow_holes => false, nb_components => 2)); SELECT 'CG_OptimalAlphaShape_hole_2components', ST_AsText(CG_OptimalAlphaShape('MULTIPOINT((0 0),(0 1),(0 2),(0 3),(0 4),(0 5),(0 6),(0 7),(0 8),(0 9),(1 10),(2 10),(3 10),(4 10),(4.5 9.5),(5 9),(5.5 8.5),(6 8),(6 7),(6 6),(5.5 5.5),(5 5),(4 5),(3 5),(2 5),(1 5),(1 4),(2 4),(3 4),(4 4),(4.5 3.5),(5 3),(6 2),(6 1),(5.5 0.5),(5 0),(4 0),(3 0),(2 0),(1 0),(0.5 0),(0.5 1),(0.5 2),(0.5 3),(0.5 4),(0.5 5),(0.5 6),(0.5 7),(0.5 8),(0.5 9),(0.5 10),(1 9.5),(2 9.5),(3 9.5),(4 9.5),(4.5 9),(5 8.5),(5.5 8),(5.5 7),(5.5 6),(5.5 6.5),(5 5.5),(4 5.5),(3 5.5),(2 5.5),(1 5.5),(1.5 4.5),(2.5 4.5),(3.5 4.5),(4 4.5),(4.5 4),(5 3.5),(5.5 3),(5.5 2),(5.5 1),(5 0.5),(4 0.5),(3 0.5),(2 0.5),(1 0.5),(12 0),(12 1),(12 2),(12 3),(12 4),(12 5),(12 6),(12 7),(12 8),(12 9),(12 10),(13 10),(14 10),(15 10),(16 10),(16.5 9.5),(17 9),(17.5 8.5),(18 8),(18 7),(18 6),(17.5 5.5),(17 5),(16 5),(15 5),(14 5),(13 5),(12.5 0),(12.5 1),(12.5 2),(12.5 3),(12.5 4),(12.5 5),(12.5 6),(12.5 7),(12.5 8),(12.5 9),(12.5 10),(13 9.5),(14 9.5),(15 9.5),(16 9.5),(16.5 9),(17 8.5),(17.5 8),(17.5 7),(17.5 6),(17.5 6.5),(17 5.5),(16 5.5),(15 5.5),(14 5.5),(13 5.5),(13 1),(13 2),(13 3),(13 4),(17.5 7.4),(18 7.3),(5.1 2.5),(5.8 2.5),(0.03 9.82),(0.23 10))', allow_holes => true, nb_components => 2)); diff --git a/sfcgal/regress/alphashape_components_expected b/sfcgal/regress/alphashape_components_expected index a30a4ad59..b6c81889e 100644 --- a/sfcgal/regress/alphashape_components_expected +++ b/sfcgal/regress/alphashape_components_expected @@ -1,2 +1,2 @@ -CG_Optimalalphashape_2components|MULTIPOLYGON(((8.3 11.8,6.2 12.1,4.1 11.9,2.6 11.2,1.1 10.1,0.3 8.2,0.1 6.1,0.4 4,1.2 2.3,2.5 1,4.2 0.3,6 0,8.1 0.1,10.1 0.2,9.2 2.4,7.8 2.2,6 2.3,3.6 6.2,7.6 9.8,9.1 9.9,10.2 11.1,8.3 11.8)),((55.6 12.1,55.8 15,54.3 15.2,52.9 10.6,52.7 7.3,52.8 4.1,46.9 2.8,43.3 7.1,43.1 10.4,43.1 15.3,41.9 15.6,40.5 15.2,40.2 12.3,40.4 9,39.8 6.2,40.1 3.1,40.3 0.4,42.1 0.3,44.2 0.2,49.8 -0.2,52.6 0.1,55.4 0.5,55.7 3.3,55.5 6,55.9 9.2,55.6 12.1))) +CG_Optimalalphashape_2components|MULTIPOLYGON(((4 6,3 6,2 6,1 6,0 6,0 5,0 4,0 3,0 2,0 1,0 0,1 0,2 0,3 0,4 0,5 0,5 1,5 2,5 3,5 4,5 5,5 6,4 6)),((34 6,33 6,32 6,31 6,30 6,30 5,30 4,30 3,30 2,30 1,30 0,31 0,32 0,33 0,34 0,35 0,35 1,35 2,35 3,35 4,35 5,35 6,34 6))) CG_OptimalAlphaShape_hole_2components|MULTIPOLYGON(((5.5 8.5,5 9,4.5 9.5,4 10,3 10,2 10,1 10,0.5 10,0.23 10,0.03 9.82,0 9,0 8,0 7,0 6,0 5,0 4,0 3,0 2,0 1,0 0,0.5 0,1 0,2 0,3 0,4 0,5 0,5.5 0.5,6 1,6 2,5.8 2.5,5.5 3,5 3.5,4.5 4,4 4.5,5 5,5.5 5.5,6 6,6 7,6 8,5.5 8.5),(0.5 2,0.5 3,1 4,2 4,3 4,4 4,4.5 3.5,5 3,5.1 2.5,5.5 2,5.5 1,5 0.5,4 0.5,3 0.5,2 0.5,1 0.5,0.5 1,0.5 2),(0.5 7,0.5 8,0.5 9,1 9.5,2 9.5,3 9.5,4 9.5,4.5 9,5 8.5,5.5 8,5.5 7,5.5 6.5,5.5 6,5 5.5,4 5.5,3 5.5,2 5.5,1 5.5,0.5 6,0.5 7)),((17.5 8.5,17 9,16.5 9.5,16 10,15 10,14 10,13 10,12.5 10,12 10,12 9,12 8,12 7,12 6,12 5,12 4,12 3,12 2,12 1,12 0,12.5 0,13 1,13 2,13 3,13 4,13 5,14 5,15 5,16 5,17 5,17.5 5.5,18 6,18 7,18 7.3,18 8,17.5 8.5),(12.5 7,12.5 8,12.5 9,13 9.5,14 9.5,15 9.5,16 9.5,16.5 9,17 8.5,17.5 8,17.5 7.4,17.5 7,17.5 6.5,17.5 6,17 5.5,16 5.5,15 5.5,14 5.5,13 5.5,12.5 6,12.5 7))) ----------------------------------------------------------------------- Summary of changes: sfcgal/regress/alphashape_components.sql | 21 ++++++++++++++++++++- sfcgal/regress/alphashape_components_expected | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Mon Jun 8 10:26:31 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 8 Jun 2026 10:26:31 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.6 updated. 3.6.3-14-gdaae069ef Message-ID: <20260608172631.9162619B27D@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.6 has been updated via daae069eff9c6427d3f2801616998774436d3de5 (commit) via 34cc1957e8b999b8981fc019eff5330efb203c89 (commit) via 0eb46c8d2c01d5e511d4c7e21531e694be0ce00c (commit) from bc9704020c519f3b2fccf4376bd2bf4f85236880 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit daae069eff9c6427d3f2801616998774436d3de5 Author: Paul Ramsey Date: Mon Jun 8 10:17:31 2026 -0700 Remove unused PostgreSQL headers diff --git a/libpgcommon/lwgeom_transform.c b/libpgcommon/lwgeom_transform.c index a092fc480..18e7ea631 100644 --- a/libpgcommon/lwgeom_transform.c +++ b/libpgcommon/lwgeom_transform.c @@ -17,8 +17,6 @@ #include "miscadmin.h" #include "utils/memutils.h" #include "executor/spi.h" -#include "access/hash.h" -#include "utils/hsearch.h" /* PostGIS headers */ #include "../postgis_config.h" diff --git a/postgis/lwgeom_geos_prepared.h b/postgis/lwgeom_geos_prepared.h index e945d95c5..f38ac0308 100644 --- a/postgis/lwgeom_geos_prepared.h +++ b/postgis/lwgeom_geos_prepared.h @@ -27,7 +27,6 @@ #include "postgres.h" #include "fmgr.h" #include "miscadmin.h" -#include "utils/hsearch.h" #include "utils/memutils.h" #include "access/hash.h" commit 34cc1957e8b999b8981fc019eff5330efb203c89 Author: Paul Ramsey Date: Thu Jun 4 13:44:05 2026 -0700 News entry for #3916 diff --git a/NEWS b/NEWS index 06510b3a9..d03d043fa 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ PostGIS 3.6.4 - GH-862, use SFCGAL undeprecated function sfcgal_geometry_tessellate() (Jean Felder) - Flatgeobuf schema mismatch vulnerability (NeuroWinter) - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) +- #5916, ST_Split hang with very large ordinates (Paul Ramsey) PostGIS 3.6.3 commit 0eb46c8d2c01d5e511d4c7e21531e694be0ce00c Author: Paul Ramsey Date: Thu Jun 4 13:38:04 2026 -0700 Avoid Inf looping and memory use in ST_Split When fed with very large coordinates, ST_Split could be fooled into an Inf loop, this fixes that case, closes #5916 diff --git a/liblwgeom/lwgeom_geos_split.c b/liblwgeom/lwgeom_geos_split.c index a69b3d502..15ca6ff5c 100644 --- a/liblwgeom/lwgeom_geos_split.c +++ b/liblwgeom/lwgeom_geos_split.c @@ -282,9 +282,12 @@ lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in, LWDEBUGF(3, "Projected point:(%.15g %.15g), seg:%d, p1:(%.15g %.15g), p2:(%.15g %.15g)", pt_projected.x, pt_projected.y, seg, p1.x, p1.y, p2.x, p2.y); - /* When closest point == an endpoint, this is a boundary intersection */ - if ( ( (seg == nsegs-1) && P4D_SAME_STRICT(&pt_projected, &p2) ) || - ( (seg == 0) && P4D_SAME_STRICT(&pt_projected, &p1) ) ) + /* When closest point == an endpoint, this is a boundary intersection. + * Compare only X and Y since pt_projected.x/y were forced to pt.x/y above, + * and Z/M may be NaN when line coordinates are very large (causing Inf/Inf + * in closest_point_on_segment). See #5916. */ + if ( ( (seg == nsegs-1) && (pt_projected.x == p2.x) && (pt_projected.y == p2.y) ) || + ( (seg == 0) && (pt_projected.x == p1.x) && (pt_projected.y == p1.y) ) ) { return 1; } ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/lwgeom_geos_split.c | 9 ++++++--- libpgcommon/lwgeom_transform.c | 2 -- postgis/lwgeom_geos_prepared.h | 1 - 4 files changed, 7 insertions(+), 6 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Mon Jun 8 10:26:34 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 08 Jun 2026 17:26:34 -0000 Subject: [PostGIS] #5916: ST_Split consumes excessive memory when input contains infinity values In-Reply-To: <047.d96a0100e8d34bc08ed7faaea76e286f@osgeo.org> References: <047.d96a0100e8d34bc08ed7faaea76e286f@osgeo.org> Message-ID: <062.aaa31e69c34f0be08c0a5a6cb93bfb5f@osgeo.org> #5916: ST_Split consumes excessive memory when input contains infinity values ----------------------+--------------------------- Reporter: dmyzl | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.5.5 Component: postgis | Version: 3.5.x Resolution: fixed | Keywords: ST_Split ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"0eb46c8d2c01d5e511d4c7e21531e694be0ce00c/git" 0eb46c8/git]: {{{#!CommitTicketReference repository="git" revision="0eb46c8d2c01d5e511d4c7e21531e694be0ce00c" Avoid Inf looping and memory use in ST_Split When fed with very large coordinates, ST_Split could be fooled into an Inf loop, this fixes that case, closes #5916 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Mon Jun 8 10:28:35 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 8 Jun 2026 10:28:35 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.5 updated. 3.5.6-8-g826718222 Message-ID: <20260608172835.D41AC19B518@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.5 has been updated via 826718222abbe0b38c5e56c7086007279d6df942 (commit) via 2cbcdd94dd99caaf147ed07b572aba48853c2783 (commit) from 05d7932adf91edd05fc6e891d6b067f193379218 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 826718222abbe0b38c5e56c7086007279d6df942 Author: Paul Ramsey Date: Thu Jun 4 13:44:11 2026 -0700 News entry for #3916 diff --git a/NEWS b/NEWS index 1bbd739c9..86b1fe3f2 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PostGIS 3.5.7 - Flatgeobuf schema mismatch vulnerability (NeuroWinter) - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) + - #5916, ST_Split hang with very large ordinates (Paul Ramsey) PostGIS 3.5.6 commit 2cbcdd94dd99caaf147ed07b572aba48853c2783 Author: Paul Ramsey Date: Thu Jun 4 13:38:04 2026 -0700 Avoid Inf looping and memory use in ST_Split When fed with very large coordinates, ST_Split could be fooled into an Inf loop, this fixes that case, closes #5916 diff --git a/liblwgeom/lwgeom_geos_split.c b/liblwgeom/lwgeom_geos_split.c index a69b3d502..15ca6ff5c 100644 --- a/liblwgeom/lwgeom_geos_split.c +++ b/liblwgeom/lwgeom_geos_split.c @@ -282,9 +282,12 @@ lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in, LWDEBUGF(3, "Projected point:(%.15g %.15g), seg:%d, p1:(%.15g %.15g), p2:(%.15g %.15g)", pt_projected.x, pt_projected.y, seg, p1.x, p1.y, p2.x, p2.y); - /* When closest point == an endpoint, this is a boundary intersection */ - if ( ( (seg == nsegs-1) && P4D_SAME_STRICT(&pt_projected, &p2) ) || - ( (seg == 0) && P4D_SAME_STRICT(&pt_projected, &p1) ) ) + /* When closest point == an endpoint, this is a boundary intersection. + * Compare only X and Y since pt_projected.x/y were forced to pt.x/y above, + * and Z/M may be NaN when line coordinates are very large (causing Inf/Inf + * in closest_point_on_segment). See #5916. */ + if ( ( (seg == nsegs-1) && (pt_projected.x == p2.x) && (pt_projected.y == p2.y) ) || + ( (seg == 0) && (pt_projected.x == p1.x) && (pt_projected.y == p1.y) ) ) { return 1; } ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/lwgeom_geos_split.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Mon Jun 8 10:28:37 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 08 Jun 2026 17:28:37 -0000 Subject: [PostGIS] #5916: ST_Split consumes excessive memory when input contains infinity values In-Reply-To: <047.d96a0100e8d34bc08ed7faaea76e286f@osgeo.org> References: <047.d96a0100e8d34bc08ed7faaea76e286f@osgeo.org> Message-ID: <062.ca99b2ac95dbf4fdc6d4a45f71cdae04@osgeo.org> #5916: ST_Split consumes excessive memory when input contains infinity values ----------------------+--------------------------- Reporter: dmyzl | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.5.5 Component: postgis | Version: 3.5.x Resolution: fixed | Keywords: ST_Split ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"2cbcdd94dd99caaf147ed07b572aba48853c2783/git" 2cbcdd94/git]: {{{#!CommitTicketReference repository="git" revision="2cbcdd94dd99caaf147ed07b572aba48853c2783" Avoid Inf looping and memory use in ST_Split When fed with very large coordinates, ST_Split could be fooled into an Inf loop, this fixes that case, closes #5916 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Mon Jun 8 10:29:28 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 8 Jun 2026 10:29:28 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.4 updated. 3.4.6-8-gdf288d663 Message-ID: <20260608172928.5E69E19ABF6@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.4 has been updated via df288d663f287faae94a517f106212b8760dfdd5 (commit) via 95be83ddca93a5e85d110c382508e1a7cd2a8fb0 (commit) from fa01ecedb2ba070b429246dac7226f79057a7c0d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit df288d663f287faae94a517f106212b8760dfdd5 Author: Paul Ramsey Date: Thu Jun 4 13:44:13 2026 -0700 News entry for #3916 diff --git a/NEWS b/NEWS index a27721103..1f3d67a41 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PostGIS 3.4.7 - Flatgeobuf schema mismatch vulnerability (NeuroWinter) - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) + - #5916, ST_Split hang with very large ordinates (Paul Ramsey) PostGIS 3.4.6 commit 95be83ddca93a5e85d110c382508e1a7cd2a8fb0 Author: Paul Ramsey Date: Thu Jun 4 13:38:04 2026 -0700 Avoid Inf looping and memory use in ST_Split When fed with very large coordinates, ST_Split could be fooled into an Inf loop, this fixes that case, closes #5916 diff --git a/liblwgeom/lwgeom_geos_split.c b/liblwgeom/lwgeom_geos_split.c index 58f7f2725..3dba1d06d 100644 --- a/liblwgeom/lwgeom_geos_split.c +++ b/liblwgeom/lwgeom_geos_split.c @@ -282,9 +282,12 @@ lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in, LWDEBUGF(3, "Projected point:(%.15g %.15g), seg:%d, p1:(%.15g %.15g), p2:(%.15g %.15g)", pt_projected.x, pt_projected.y, seg, p1.x, p1.y, p2.x, p2.y); - /* When closest point == an endpoint, this is a boundary intersection */ - if ( ( (seg == nsegs-1) && P4D_SAME_STRICT(&pt_projected, &p2) ) || - ( (seg == 0) && P4D_SAME_STRICT(&pt_projected, &p1) ) ) + /* When closest point == an endpoint, this is a boundary intersection. + * Compare only X and Y since pt_projected.x/y were forced to pt.x/y above, + * and Z/M may be NaN when line coordinates are very large (causing Inf/Inf + * in closest_point_on_segment). See #5916. */ + if ( ( (seg == nsegs-1) && (pt_projected.x == p2.x) && (pt_projected.y == p2.y) ) || + ( (seg == 0) && (pt_projected.x == p1.x) && (pt_projected.y == p1.y) ) ) { return 1; } ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/lwgeom_geos_split.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Mon Jun 8 10:29:29 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 08 Jun 2026 17:29:29 -0000 Subject: [PostGIS] #5916: ST_Split consumes excessive memory when input contains infinity values In-Reply-To: <047.d96a0100e8d34bc08ed7faaea76e286f@osgeo.org> References: <047.d96a0100e8d34bc08ed7faaea76e286f@osgeo.org> Message-ID: <062.705fc5dca3884827172d6a083a8736b1@osgeo.org> #5916: ST_Split consumes excessive memory when input contains infinity values ----------------------+--------------------------- Reporter: dmyzl | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.5.5 Component: postgis | Version: 3.5.x Resolution: fixed | Keywords: ST_Split ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"95be83ddca93a5e85d110c382508e1a7cd2a8fb0/git" 95be83dd/git]: {{{#!CommitTicketReference repository="git" revision="95be83ddca93a5e85d110c382508e1a7cd2a8fb0" Avoid Inf looping and memory use in ST_Split When fed with very large coordinates, ST_Split could be fooled into an Inf loop, this fixes that case, closes #5916 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Mon Jun 8 10:29:53 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 8 Jun 2026 10:29:53 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.3 updated. 3.3.10-8-g281c3f70e Message-ID: <20260608172953.CD4A019B5DF@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.3 has been updated via 281c3f70e293c32c6b05c625eb43b47062d5c4af (commit) via d6e0a906d3665f58588d2b5086e9fe785dab5d1a (commit) from 378c1bb3f4626abc30b4ef4d8289ab613d1034b8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 281c3f70e293c32c6b05c625eb43b47062d5c4af Author: Paul Ramsey Date: Thu Jun 4 13:44:14 2026 -0700 News entry for #3916 diff --git a/NEWS b/NEWS index dbd055e18..de3b09c39 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PostGIS 3.3.11 - Flatgeobuf schema mismatch vulnerability (NeuroWinter) - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) + - #5916, ST_Split hang with very large ordinates (Paul Ramsey) PostGIS 3.3.10 commit d6e0a906d3665f58588d2b5086e9fe785dab5d1a Author: Paul Ramsey Date: Thu Jun 4 13:38:04 2026 -0700 Avoid Inf looping and memory use in ST_Split When fed with very large coordinates, ST_Split could be fooled into an Inf loop, this fixes that case, closes #5916 diff --git a/liblwgeom/lwgeom_geos_split.c b/liblwgeom/lwgeom_geos_split.c index 58f7f2725..3dba1d06d 100644 --- a/liblwgeom/lwgeom_geos_split.c +++ b/liblwgeom/lwgeom_geos_split.c @@ -282,9 +282,12 @@ lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in, LWDEBUGF(3, "Projected point:(%.15g %.15g), seg:%d, p1:(%.15g %.15g), p2:(%.15g %.15g)", pt_projected.x, pt_projected.y, seg, p1.x, p1.y, p2.x, p2.y); - /* When closest point == an endpoint, this is a boundary intersection */ - if ( ( (seg == nsegs-1) && P4D_SAME_STRICT(&pt_projected, &p2) ) || - ( (seg == 0) && P4D_SAME_STRICT(&pt_projected, &p1) ) ) + /* When closest point == an endpoint, this is a boundary intersection. + * Compare only X and Y since pt_projected.x/y were forced to pt.x/y above, + * and Z/M may be NaN when line coordinates are very large (causing Inf/Inf + * in closest_point_on_segment). See #5916. */ + if ( ( (seg == nsegs-1) && (pt_projected.x == p2.x) && (pt_projected.y == p2.y) ) || + ( (seg == 0) && (pt_projected.x == p1.x) && (pt_projected.y == p1.y) ) ) { return 1; } ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/lwgeom_geos_split.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Mon Jun 8 10:29:55 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 08 Jun 2026 17:29:55 -0000 Subject: [PostGIS] #5916: ST_Split consumes excessive memory when input contains infinity values In-Reply-To: <047.d96a0100e8d34bc08ed7faaea76e286f@osgeo.org> References: <047.d96a0100e8d34bc08ed7faaea76e286f@osgeo.org> Message-ID: <062.d36f3c677b038fc239becf6087b91014@osgeo.org> #5916: ST_Split consumes excessive memory when input contains infinity values ----------------------+--------------------------- Reporter: dmyzl | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.5.5 Component: postgis | Version: 3.5.x Resolution: fixed | Keywords: ST_Split ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"d6e0a906d3665f58588d2b5086e9fe785dab5d1a/git" d6e0a90/git]: {{{#!CommitTicketReference repository="git" revision="d6e0a906d3665f58588d2b5086e9fe785dab5d1a" Avoid Inf looping and memory use in ST_Split When fed with very large coordinates, ST_Split could be fooled into an Inf loop, this fixes that case, closes #5916 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 8 11:23:15 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 08 Jun 2026 18:23:15 -0000 Subject: [PostGIS] Batch modify: #6038, #6072 In-Reply-To: <049.9d243148bff4c14895bd39a2c494aa44@osgeo.org> References: <049.9d243148bff4c14895bd39a2c494aa44@osgeo.org> Message-ID: <042.c00ca35d915dadf5d127a515f5c6ad78@osgeo.org> Batch modification to #6038, #6072 by pramsey: milestone to PostGIS 3.6.5 Comment: Ticket retargeted after milestone closed -- Tickets URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Mon Jun 8 11:37:03 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 8 Jun 2026 11:37:03 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.6 updated. 3.6.3-15-g94d984bd0 Message-ID: <20260608183703.61D0C19D810@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.6 has been updated via 94d984bd083635c1d253db0f87cf80b32548e406 (commit) from daae069eff9c6427d3f2801616998774436d3de5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 94d984bd083635c1d253db0f87cf80b32548e406 Author: Paul Ramsey Date: Mon Jun 8 11:28:56 2026 -0700 Prep for 3.6.4 release diff --git a/NEWS b/NEWS index d03d043fa..554b99045 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,5 @@ PostGIS 3.6.4 -2026/xx/xx +2026/06/08 * Fixes * diff --git a/README.postgis b/README.postgis index 3166952d6..320e7d2c1 100644 --- a/README.postgis +++ b/README.postgis @@ -1,8 +1,8 @@ PostGIS - Geographic Information Systems Extensions to PostgreSQL ================================================================= -:Version: 3.6.3 -:Date: 2026-04-14 +:Version: 3.6.4 +:Date: 2026-06-08 :Website: https://postgis.net This distribution contains a module which implements GIS simple features, ties diff --git a/Version.config b/Version.config index d2ae378e9..d3e7ae7b8 100644 --- a/Version.config +++ b/Version.config @@ -5,7 +5,7 @@ POSTGIS_MAJOR_VERSION=3 POSTGIS_MINOR_VERSION=6 -POSTGIS_MICRO_VERSION=4dev +POSTGIS_MICRO_VERSION=4 # Liblwgeom interface versioning, reset to 0:0:0 (cur:age:rev) # when changing POSTGIS_MINOR_VERSION diff --git a/doc/release_notes.xml b/doc/release_notes.xml index 825f1839f..930bb8d46 100644 --- a/doc/release_notes.xml +++ b/doc/release_notes.xml @@ -3,6 +3,19 @@ Appendix Release Notes +
+ PostGIS 3.6.4 + 2026/06/08 + + + Fixes + 6076, ST_Length(geography) for GeometryCollection not consistent with geometry implementation + GH-862, Use SFCGAL undeprecated function sfcgal_geometry_tessellate() (Jean Felder) + Flatgeobuf schema mismatch vulnerability (NeuroWinter) + 5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) + 5916, ST_Split hang with very large ordinates (Paul Ramsey) + +
PostGIS 3.6.3 ----------------------------------------------------------------------- Summary of changes: NEWS | 2 +- README.postgis | 4 ++-- Version.config | 2 +- doc/release_notes.xml | 13 +++++++++++++ 4 files changed, 17 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Mon Jun 8 14:16:02 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 8 Jun 2026 14:16:02 -0700 (PDT) Subject: [SCM] postgis.net branch website updated. clarity-final-185-g18f8be9 Message-ID: <20260608211602.89BB719F040@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "postgis.net". The branch, website has been updated via 18f8be98bd30c17c6ab604086932a83e071f837f (commit) via 9a17c0a164a0f888a2de6ca1a9178d91f7789a27 (commit) from ad6f1339ad37cb5f067e07549f57ac7edd71c9b6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 18f8be98bd30c17c6ab604086932a83e071f837f Author: Paul Ramsey Date: Mon Jun 8 14:15:55 2026 -0700 Add 3.6.4 release diff --git a/config.toml b/config.toml index 63cf194..531c23b 100644 --- a/config.toml +++ b/config.toml @@ -170,8 +170,8 @@ enableRobotsTXT = true is_dev = true [params.postgis.releases.36] minor = "3.6" - dev = "3.6.4dev" - tag = "3.6.3" + dev = "3.6.5dev" + tag = "3.6.4" [params.postgis.releases.35] minor = "3.5" dev = "3.5.7dev" commit 9a17c0a164a0f888a2de6ca1a9178d91f7789a27 Author: Paul Ramsey Date: Mon Jun 8 14:14:35 2026 -0700 Syntax diff --git a/content/development/source_code.md b/content/development/source_code.md index c1ed626..a99284c 100644 --- a/content/development/source_code.md +++ b/content/development/source_code.md @@ -21,7 +21,7 @@ The **official** PostGIS GIT repository is hosted at OSGeo. * **https://gitea.osgeo.org/postgis/** -Changes pushed to the official repository will be replicated to the two mirror repository sites. Changes committed to the mirror sites will be over-written the next time a changes are synced from OSGeo. +Changes pushed to the official repository will be replicated to the two mirror repository sites. Changes committed to the mirror sites will be over-written the next time changes are synced from OSGeo. * GitHub mirror: https://github.com/postgis/postgis/ * GitLab mirror: https://gitlab.com/postgis/postgis/ ----------------------------------------------------------------------- Summary of changes: config.toml | 4 ++-- content/development/source_code.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- postgis.net From trac at osgeo.org Mon Jun 8 14:17:45 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 08 Jun 2026 21:17:45 -0000 Subject: [PostGIS] #5618: Images not showing In-Reply-To: <046.41125b25e66623b95b8d680c485bc081@osgeo.org> References: <046.41125b25e66623b95b8d680c485bc081@osgeo.org> Message-ID: <061.481d9a8deb2922d16787b2225959ba2b@osgeo.org> #5618: Images not showing ----------------------------+--------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: blocker | Milestone: PostGIS 3.7.0 Component: documentation | Version: master Resolution: fixed | Keywords: ----------------------------+--------------------------- Changes (by pramsey): * resolution: => fixed * status: reopened => closed Comment: Looks fine to me. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Mon Jun 8 14:21:10 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 8 Jun 2026 14:21:10 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.6 updated. 3.6.4-1-gcb2004603 Message-ID: <20260608212110.4799719F116@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.6 has been updated via cb20046039b693e42ca608aa21a9e774e0ec8fe2 (commit) from 94d984bd083635c1d253db0f87cf80b32548e406 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit cb20046039b693e42ca608aa21a9e774e0ec8fe2 Author: Paul Ramsey Date: Mon Jun 8 14:21:03 2026 -0700 Bump for 3.6.5 dev cycle diff --git a/NEWS b/NEWS index 554b99045..95691e8cc 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,11 @@ +PostGIS 3.6.5 +2026/xx/xx + +* Fixes * + +- + + PostGIS 3.6.4 2026/06/08 diff --git a/Version.config b/Version.config index d3e7ae7b8..4eb920218 100644 --- a/Version.config +++ b/Version.config @@ -5,7 +5,7 @@ POSTGIS_MAJOR_VERSION=3 POSTGIS_MINOR_VERSION=6 -POSTGIS_MICRO_VERSION=4 +POSTGIS_MICRO_VERSION=5dev # Liblwgeom interface versioning, reset to 0:0:0 (cur:age:rev) # when changing POSTGIS_MINOR_VERSION diff --git a/extensions/upgradeable_versions.mk b/extensions/upgradeable_versions.mk index 8524ac3c2..8435eb17e 100644 --- a/extensions/upgradeable_versions.mk +++ b/extensions/upgradeable_versions.mk @@ -122,4 +122,5 @@ UPGRADEABLE_VERSIONS = \ 3.6.0 \ 3.6.1 \ 3.6.2 \ - 3.6.3 + 3.6.3 \ + 3.6.4 ----------------------------------------------------------------------- Summary of changes: NEWS | 8 ++++++++ Version.config | 2 +- extensions/upgradeable_versions.mk | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Mon Jun 8 16:45:45 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 8 Jun 2026 16:45:45 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.2 updated. 3.2.10-6-g69525adbe Message-ID: <20260608234545.6915719FAAF@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.2 has been updated via 69525adbe50c6f70eb7198d8aad88e4e64c9d111 (commit) via c800a006fe796d913ec8463c693a3c11655bbdab (commit) from 94610531f03c30c733853704569ba1bd963151d8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 69525adbe50c6f70eb7198d8aad88e4e64c9d111 Author: Paul Ramsey Date: Mon Jun 8 15:55:39 2026 -0700 NEWS item for flatgeobuf fix diff --git a/NEWS b/NEWS index 91cb13bd6..01e2752ca 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ PostGIS 3.2.11 * Bug Fixes * - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) + - Flatgeobuf schema mismatch vulnerability (NeuroWinter) PostGIS 3.2.10 commit c800a006fe796d913ec8463c693a3c11655bbdab Author: Paul Ramsey Date: Wed May 27 21:52:25 2026 +0000 Check that user-provided flatbuffer schema matches The flatbuffer import maps an incoming file to a provided table schema, and the consistency of those two schemes needs to be checked before data are copied across. diff --git a/postgis/flatgeobuf.c b/postgis/flatgeobuf.c index 545442f31..d8eea1562 100644 --- a/postgis/flatgeobuf.c +++ b/postgis/flatgeobuf.c @@ -288,8 +288,6 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, POSTGIS_DEBUGF(3, "flatgeobuf: decode_properties from byte array with length %d at offset %d", size, offset); - // TODO: init isnull - if (size > 0 && size < (sizeof(uint16_t) + sizeof(uint8_t))) elog(ERROR, "flatgeobuf: decode_properties: Unexpected properties data size %d", size); while (offset + 1 < size) { @@ -390,7 +388,10 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(float) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for float value"); memcpy(&value, data + offset, sizeof(float)); - values[ci] = Float4GetDatum(value); + if (getBaseType(TupleDescAttr(ctx->tupdesc, ci)->atttypid) == FLOAT8OID) + values[ci] = Float8GetDatum((double) value); + else + values[ci] = Float4GetDatum(value); offset += sizeof(float); break; } @@ -459,9 +460,10 @@ void flatgeobuf_decode_row(struct flatgeobuf_decode_ctx *ctx) HeapTuple heapTuple; uint32_t natts = ctx->tupdesc->natts; - Datum *values = palloc0(natts * sizeof(Datum *)); - bool *isnull = palloc0(natts * sizeof(bool *)); - + Datum *values = palloc0(natts * sizeof(Datum)); + bool *isnull = palloc0(natts * sizeof(bool)); + for (uint32_t j = 0; j < natts; j++) isnull[j] = true; + isnull[0] = false; values[0] = Int32GetDatum(ctx->fid); if (flatgeobuf_decode_feature(ctx->ctx)) @@ -469,6 +471,7 @@ void flatgeobuf_decode_row(struct flatgeobuf_decode_ctx *ctx) if (ctx->ctx->lwgeom != NULL) { values[1] = PointerGetDatum(geometry_serialize(ctx->ctx->lwgeom)); + isnull[1] = false; } else { POSTGIS_DEBUG(3, "geometry is null"); isnull[1] = true; diff --git a/postgis/lwgeom_in_flatgeobuf.c b/postgis/lwgeom_in_flatgeobuf.c index ac460ff7a..773b50f98 100644 --- a/postgis/lwgeom_in_flatgeobuf.c +++ b/postgis/lwgeom_in_flatgeobuf.c @@ -67,6 +67,60 @@ static char *get_pgtype(uint8_t column_type) { elog(ERROR, "unknown column_type %d", column_type); } +static const char * +flatgeobuf_type_name(uint8_t fgb_type) +{ + /* Names match FlatGeobuf::EnumNamesColumnType() in header_generated.h */ + static const char * const names[] = { + "Byte", "UByte", "Bool", "Short", "UShort", + "Int", "UInt", "Long", "ULong", + "Float", "Double", "String", "Json", "DateTime", "Binary" + }; + if (fgb_type >= sizeof(names) / sizeof(names[0])) + return "unknown"; + return names[fgb_type]; +} + +static bool +flatgeobuf_type_compatible(uint8_t fgb_type, Oid pgtype) +{ + switch (fgb_type) + { + case flatgeobuf_column_type_bool: + return pgtype == BOOLOID; + /* small integer types: allow widening into larger signed ints */ + case flatgeobuf_column_type_byte: + case flatgeobuf_column_type_ubyte: + case flatgeobuf_column_type_short: + case flatgeobuf_column_type_ushort: + return pgtype == INT2OID || pgtype == INT4OID || pgtype == INT8OID; + /* int32: allow widening to bigint */ + case flatgeobuf_column_type_int: + return pgtype == INT4OID || pgtype == INT8OID; + /* uint32 max exceeds INT4, must land in bigint */ + case flatgeobuf_column_type_uint: + return pgtype == INT8OID; + case flatgeobuf_column_type_long: + case flatgeobuf_column_type_ulong: + return pgtype == INT8OID; + /* float: allow widening to double (explicit conversion handled in decode) */ + case flatgeobuf_column_type_float: + return pgtype == FLOAT4OID || pgtype == FLOAT8OID; + case flatgeobuf_column_type_double: + return pgtype == FLOAT8OID; + case flatgeobuf_column_type_string: + return pgtype == TEXTOID || pgtype == VARCHAROID; + case flatgeobuf_column_type_datetime: + return pgtype == DATEOID || pgtype == TIMEOID || + pgtype == TIMESTAMPOID || pgtype == TIMESTAMPTZOID; + case flatgeobuf_column_type_json: + return pgtype == JSONBOID; + case flatgeobuf_column_type_binary: + return pgtype == BYTEAOID; + } + return false; +} + PG_FUNCTION_INFO_V1(pgis_tablefromflatgeobuf); Datum pgis_tablefromflatgeobuf(PG_FUNCTION_ARGS) { @@ -192,7 +246,29 @@ Datum pgis_fromflatgeobuf(PG_FUNCTION_ARGS) SRF_RETURN_DONE(funcctx); } - // TODO: get table and verify structure against header + /* Validate that the file schema matches the caller-supplied composite type. + * tupdesc positions 0 (fid) and 1 (geom) are fixed; file columns start at 2. */ + if (ctx->ctx->columns_size != (uint32_t)(tupdesc->natts - 2)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("flatgeobuf: column count mismatch: " + "file has %u columns, target type has %d", + ctx->ctx->columns_size, tupdesc->natts - 2))); + + for (uint16_t col_i = 0; col_i < ctx->ctx->columns_size; col_i++) + { + flatgeobuf_column *col = ctx->ctx->columns[col_i]; + Oid pgtype = getBaseType(TupleDescAttr(tupdesc, col_i + 2)->atttypid); + if (!flatgeobuf_type_compatible(col->type, pgtype)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("flatgeobuf: column \"%s\" type mismatch: " + "file type \"%s\" is not compatible with PostgreSQL type %s", + col->name, + flatgeobuf_type_name(col->type), + format_type_be(pgtype)))); + } + MemoryContextSwitchTo(oldcontext); } ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + postgis/flatgeobuf.c | 15 ++++---- postgis/lwgeom_in_flatgeobuf.c | 78 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 7 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Tue Jun 9 07:23:05 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 07:23:05 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-506-g48a6d6d70 Message-ID: <20260609142305.5D8CB1B173A@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 48a6d6d7011848fcbfc1c8f04c9ea82d29db2629 (commit) from 0c06ae1dc5dbb4877ef90c79122ca88f6425b465 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 48a6d6d7011848fcbfc1c8f04c9ea82d29db2629 Author: Darafei Praliaskouski Date: Tue Jun 9 18:22:03 2026 +0400 Move skills to doc/ subdirectory: https://lists.osgeo.org/pipermail/postgis-devel/2026-June/030774.html diff --git a/skills/postgis/SKILL.md b/doc/skills/postgis/SKILL.md similarity index 100% rename from skills/postgis/SKILL.md rename to doc/skills/postgis/SKILL.md diff --git a/skills/sql-programming/SKILL.md b/doc/skills/sql-programming/SKILL.md similarity index 100% rename from skills/sql-programming/SKILL.md rename to doc/skills/sql-programming/SKILL.md ----------------------------------------------------------------------- Summary of changes: {skills => doc/skills}/postgis/SKILL.md | 0 {skills => doc/skills}/sql-programming/SKILL.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {skills => doc/skills}/postgis/SKILL.md (100%) rename {skills => doc/skills}/sql-programming/SKILL.md (100%) hooks/post-receive -- PostGIS From git at osgeo.org Tue Jun 9 10:53:11 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 10:53:11 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-507-g6216b684a Message-ID: <20260609175312.186821B3CB6@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 6216b684aaff36b393d5d5707c95a896b1e89ffc (commit) from 48a6d6d7011848fcbfc1c8f04c9ea82d29db2629 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6216b684aaff36b393d5d5707c95a896b1e89ffc Author: Paul Ramsey Date: Tue Jun 9 00:19:54 2026 +0000 Fix CurvePolygon distance issue, references #5989 diff --git a/liblwgeom/cunit/cu_measures.c b/liblwgeom/cunit/cu_measures.c index c95bf21e1..5cb4b6d81 100644 --- a/liblwgeom/cunit/cu_measures.c +++ b/liblwgeom/cunit/cu_measures.c @@ -235,6 +235,12 @@ static void test_mindistance2d_tolerance(void) DIST2DTEST( "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, -1 5, 0 10), (0 10, -10 10, -10 0, 0 0)))", "POINT(-0.5 5)", 0.5, default_accepted_error); + + /* Ticket 5989 reopened: multi-arc COMPOUNDCURVE with large Finnish coordinates */ + DIST2DTEST( + "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(25493681.3085 6678739.6419,25493637.8256 6678776.2541,25493599.9716 6678818.6604),(25493599.9716 6678818.6604,25493583.8816 6678839.494,25493590.9591 6678844.9594,25493566.9698 6678851.9051,25493526.5793 6678861.0985,25493487.3853 6678868.2546,25493447.392 6678871.7846,25493429.5033 6678876.6846,25493435.0147 6678857.4594,25493454.9254 6678821.6192,25493452.4867 6678816.1292,25493402.3226 6678828.2153,25493354.7526 6678837.8291,25493349.0217 6678838.9873,25493310.914 6678843.6926,25493306.3784 6678859.9295,25493294.1011 6678858.7864,25493169.9028 6678847.2212,25493127.549 6678843.2773,25493057.8888 6678834.6763,25493017.4547 6678826.7261,25492928.2395 6678821.5524,25492909.1067 6678795.0681,25492946.9544 6678794.8193,25492967.1292 6678794.6866,25493010.8878 6678795.9163,25493111.5564 6678804.3109,25493113.4069 6678799.5694,25493134.2375 6678806.0729),CIRCULARSTRING(25493134.2375 6678806.0729,25493223.038 6678812.0533,25493311 .4919 6678802.1948,25493317.3589 6678800.9679,25493323.2107 6678799.6707),(25493323.2107 6678799.6707,25493362.6615 6678792.3924,25493364.6948 6678785.173,25493375.0512 6678781.6008,25493404.9736 6678771.2798),CIRCULARSTRING(25493404.9736 6678771.2798,25493486.8049 6678737.6728,25493566.8862 6678700.0859),(25493566.8862 6678700.0859,25493574.903 6678714.0761,25493600.2214 6678702.8803,25493654.1114 6678670.2493,25493669.7219 6678659.2147,25493677.0288 6678653.353,25493684.6468 6678648.4119,25493724.0447 6678623.7638,25493800.1925 6678583.5847,25493805.6261 6678586.1292,25493811.9258 6678582.3016,25493812.8413 6678583.0522,25493846.581 6678558.6541,25493884.2653 6678531.6272,25493900.9168 6678580.1258,25493830.7852 6678630.9518,25493789.0848 6678661.2736,25493746.1612 6678692.485,25493686.5413 6678735.8369,25493681.3085 6678739.6419))))", + "POLYGON ((25492929.752797972 6678919.124091367,25493008.675235115 6678876.783133076,25493098.02917443 6678854.33589699,25493139.669701554 6678977.913508233,25493122.946292613 6679011.427315322,25493050.53388224 6679068.791126598,25493140.33593199 6679140.958135231,25492931.688606273 6679401.2946243705,25492799.289171 6679295.949040241,25492651.5177725 6679115.144800108,25492929.752797972 6678919.124091367))", + 14.5, 1.0); } static void diff --git a/liblwgeom/measures.c b/liblwgeom/measures.c index 1dcdd6bd2..3ab9b0aaf 100644 --- a/liblwgeom/measures.c +++ b/liblwgeom/measures.c @@ -1392,17 +1392,33 @@ lw_dist2d_seg_arc(const POINT2D *A1, { double length_A; /* length of the segment A */ POINT2D E, F; /* points of intersection of edge A and circle(B) */ - double dist_D_EF; /* distance from D to E or F (same distance both ways) */ + double dist_D_EF; /* distance from D_line to E or F (same distance both ways) */ + POINT2D D_line; /* foot of perpendicular from C to the infinite line through A1-A2 */ + double dist_C_D_line; /* distance from C to the infinite line */ + double t; - dist_D_EF = sqrt(radius_C * radius_C - dist_C_D * dist_C_D); length_A = sqrt((A2->x - A1->x) * (A2->x - A1->x) + (A2->y - A1->y) * (A2->y - A1->y)); + /* + * D (from lw_dist2d_pt_seg) is clamped to the segment, but we need the + * foot of the perpendicular on the *infinite* line to correctly compute + * circle-line intersections E and F. Using the clamped endpoint gives wrong + * intersection points when the perpendicular falls outside the segment. + */ + t = ((C.x - A1->x) * (A2->x - A1->x) + (C.y - A1->y) * (A2->y - A1->y)) + / (length_A * length_A); + D_line.x = A1->x + t * (A2->x - A1->x); + D_line.y = A1->y + t * (A2->y - A1->y); + dist_C_D_line = sqrt((C.x - D_line.x) * (C.x - D_line.x) + (C.y - D_line.y) * (C.y - D_line.y)); + + dist_D_EF = sqrt(radius_C * radius_C - dist_C_D_line * dist_C_D_line); + /* Point of intersection E */ - E.x = D.x - (A2->x - A1->x) * dist_D_EF / length_A; - E.y = D.y - (A2->y - A1->y) * dist_D_EF / length_A; + E.x = D_line.x - (A2->x - A1->x) * dist_D_EF / length_A; + E.y = D_line.y - (A2->y - A1->y) * dist_D_EF / length_A; /* Point of intersection F */ - F.x = D.x + (A2->x - A1->x) * dist_D_EF / length_A; - F.y = D.y + (A2->y - A1->y) * dist_D_EF / length_A; + F.x = D_line.x + (A2->x - A1->x) * dist_D_EF / length_A; + F.y = D_line.y + (A2->y - A1->y) * dist_D_EF / length_A; /* If E is within A and within B then it's an intersection point */ pt_in_arc = lw_pt_in_arc(&E, B1, B2, B3); ----------------------------------------------------------------------- Summary of changes: liblwgeom/cunit/cu_measures.c | 6 ++++++ liblwgeom/measures.c | 28 ++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 10:53:14 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 17:53:14 -0000 Subject: [PostGIS] #5989: ST_Distance error on CurvePolygon In-Reply-To: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> References: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> Message-ID: <064.17ff2fae06b5ac6d60dde6a3948eaaa7@osgeo.org> #5989: ST_Distance error on CurvePolygon ----------------------+--------------------------- Reporter: pramsey | Owner: pramsey Type: defect | Status: reopened Priority: high | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.3.x Resolution: | Keywords: ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"6216b684aaff36b393d5d5707c95a896b1e89ffc/git" 6216b68/git]: {{{#!CommitTicketReference repository="git" revision="6216b684aaff36b393d5d5707c95a896b1e89ffc" Fix CurvePolygon distance issue, references #5989 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 11:20:26 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 11:20:26 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.6 updated. 3.6.4-3-g923c06385 Message-ID: <20260609182026.4A7971B3DC8@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.6 has been updated via 923c0638576b8916829233557224fe77a1a1e570 (commit) via 265a9edd2b6e5bd72944910d61eb9754827451d7 (commit) from cb20046039b693e42ca608aa21a9e774e0ec8fe2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 923c0638576b8916829233557224fe77a1a1e570 Author: Paul Ramsey Date: Tue Jun 9 10:59:25 2026 -0700 News entry for #5989 diff --git a/NEWS b/NEWS index 95691e8cc..51a185b62 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,7 @@ PostGIS 3.6.5 * Fixes * -- +- #5989, CurvePolygon distance corner case (Paul Ramsey) PostGIS 3.6.4 commit 265a9edd2b6e5bd72944910d61eb9754827451d7 Author: Paul Ramsey Date: Tue Jun 9 00:19:54 2026 +0000 Fix CurvePolygon distance issue, references #5989 diff --git a/liblwgeom/cunit/cu_measures.c b/liblwgeom/cunit/cu_measures.c index c95bf21e1..5cb4b6d81 100644 --- a/liblwgeom/cunit/cu_measures.c +++ b/liblwgeom/cunit/cu_measures.c @@ -235,6 +235,12 @@ static void test_mindistance2d_tolerance(void) DIST2DTEST( "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, -1 5, 0 10), (0 10, -10 10, -10 0, 0 0)))", "POINT(-0.5 5)", 0.5, default_accepted_error); + + /* Ticket 5989 reopened: multi-arc COMPOUNDCURVE with large Finnish coordinates */ + DIST2DTEST( + "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(25493681.3085 6678739.6419,25493637.8256 6678776.2541,25493599.9716 6678818.6604),(25493599.9716 6678818.6604,25493583.8816 6678839.494,25493590.9591 6678844.9594,25493566.9698 6678851.9051,25493526.5793 6678861.0985,25493487.3853 6678868.2546,25493447.392 6678871.7846,25493429.5033 6678876.6846,25493435.0147 6678857.4594,25493454.9254 6678821.6192,25493452.4867 6678816.1292,25493402.3226 6678828.2153,25493354.7526 6678837.8291,25493349.0217 6678838.9873,25493310.914 6678843.6926,25493306.3784 6678859.9295,25493294.1011 6678858.7864,25493169.9028 6678847.2212,25493127.549 6678843.2773,25493057.8888 6678834.6763,25493017.4547 6678826.7261,25492928.2395 6678821.5524,25492909.1067 6678795.0681,25492946.9544 6678794.8193,25492967.1292 6678794.6866,25493010.8878 6678795.9163,25493111.5564 6678804.3109,25493113.4069 6678799.5694,25493134.2375 6678806.0729),CIRCULARSTRING(25493134.2375 6678806.0729,25493223.038 6678812.0533,25493311 .4919 6678802.1948,25493317.3589 6678800.9679,25493323.2107 6678799.6707),(25493323.2107 6678799.6707,25493362.6615 6678792.3924,25493364.6948 6678785.173,25493375.0512 6678781.6008,25493404.9736 6678771.2798),CIRCULARSTRING(25493404.9736 6678771.2798,25493486.8049 6678737.6728,25493566.8862 6678700.0859),(25493566.8862 6678700.0859,25493574.903 6678714.0761,25493600.2214 6678702.8803,25493654.1114 6678670.2493,25493669.7219 6678659.2147,25493677.0288 6678653.353,25493684.6468 6678648.4119,25493724.0447 6678623.7638,25493800.1925 6678583.5847,25493805.6261 6678586.1292,25493811.9258 6678582.3016,25493812.8413 6678583.0522,25493846.581 6678558.6541,25493884.2653 6678531.6272,25493900.9168 6678580.1258,25493830.7852 6678630.9518,25493789.0848 6678661.2736,25493746.1612 6678692.485,25493686.5413 6678735.8369,25493681.3085 6678739.6419))))", + "POLYGON ((25492929.752797972 6678919.124091367,25493008.675235115 6678876.783133076,25493098.02917443 6678854.33589699,25493139.669701554 6678977.913508233,25493122.946292613 6679011.427315322,25493050.53388224 6679068.791126598,25493140.33593199 6679140.958135231,25492931.688606273 6679401.2946243705,25492799.289171 6679295.949040241,25492651.5177725 6679115.144800108,25492929.752797972 6678919.124091367))", + 14.5, 1.0); } static void diff --git a/liblwgeom/measures.c b/liblwgeom/measures.c index 458e82978..30d596d4f 100644 --- a/liblwgeom/measures.c +++ b/liblwgeom/measures.c @@ -1392,17 +1392,33 @@ lw_dist2d_seg_arc(const POINT2D *A1, { double length_A; /* length of the segment A */ POINT2D E, F; /* points of intersection of edge A and circle(B) */ - double dist_D_EF; /* distance from D to E or F (same distance both ways) */ + double dist_D_EF; /* distance from D_line to E or F (same distance both ways) */ + POINT2D D_line; /* foot of perpendicular from C to the infinite line through A1-A2 */ + double dist_C_D_line; /* distance from C to the infinite line */ + double t; - dist_D_EF = sqrt(radius_C * radius_C - dist_C_D * dist_C_D); length_A = sqrt((A2->x - A1->x) * (A2->x - A1->x) + (A2->y - A1->y) * (A2->y - A1->y)); + /* + * D (from lw_dist2d_pt_seg) is clamped to the segment, but we need the + * foot of the perpendicular on the *infinite* line to correctly compute + * circle-line intersections E and F. Using the clamped endpoint gives wrong + * intersection points when the perpendicular falls outside the segment. + */ + t = ((C.x - A1->x) * (A2->x - A1->x) + (C.y - A1->y) * (A2->y - A1->y)) + / (length_A * length_A); + D_line.x = A1->x + t * (A2->x - A1->x); + D_line.y = A1->y + t * (A2->y - A1->y); + dist_C_D_line = sqrt((C.x - D_line.x) * (C.x - D_line.x) + (C.y - D_line.y) * (C.y - D_line.y)); + + dist_D_EF = sqrt(radius_C * radius_C - dist_C_D_line * dist_C_D_line); + /* Point of intersection E */ - E.x = D.x - (A2->x - A1->x) * dist_D_EF / length_A; - E.y = D.y - (A2->y - A1->y) * dist_D_EF / length_A; + E.x = D_line.x - (A2->x - A1->x) * dist_D_EF / length_A; + E.y = D_line.y - (A2->y - A1->y) * dist_D_EF / length_A; /* Point of intersection F */ - F.x = D.x + (A2->x - A1->x) * dist_D_EF / length_A; - F.y = D.y + (A2->y - A1->y) * dist_D_EF / length_A; + F.x = D_line.x + (A2->x - A1->x) * dist_D_EF / length_A; + F.y = D_line.y + (A2->y - A1->y) * dist_D_EF / length_A; /* If E is within A and within B then it's an intersection point */ pt_in_arc = lw_pt_in_arc(&E, B1, B2, B3); ----------------------------------------------------------------------- Summary of changes: NEWS | 2 +- liblwgeom/cunit/cu_measures.c | 6 ++++++ liblwgeom/measures.c | 28 ++++++++++++++++++++++------ 3 files changed, 29 insertions(+), 7 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 11:20:27 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 18:20:27 -0000 Subject: [PostGIS] #5989: ST_Distance error on CurvePolygon In-Reply-To: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> References: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> Message-ID: <064.72b60117296f5702a89656d726acb2b5@osgeo.org> #5989: ST_Distance error on CurvePolygon ----------------------+--------------------------- Reporter: pramsey | Owner: pramsey Type: defect | Status: reopened Priority: high | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.3.x Resolution: | Keywords: ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"265a9edd2b6e5bd72944910d61eb9754827451d7/git" 265a9edd/git]: {{{#!CommitTicketReference repository="git" revision="265a9edd2b6e5bd72944910d61eb9754827451d7" Fix CurvePolygon distance issue, references #5989 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 11:20:28 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 11:20:28 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.5 updated. 3.5.6-10-g92d22c181 Message-ID: <20260609182028.F25E21B47B3@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.5 has been updated via 92d22c181b758165927f8c8d2351411e33389802 (commit) via a79617120051b7119944a840bb5802389b4b80f3 (commit) from 826718222abbe0b38c5e56c7086007279d6df942 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 92d22c181b758165927f8c8d2351411e33389802 Author: Paul Ramsey Date: Tue Jun 9 10:59:32 2026 -0700 News entry for #5989 diff --git a/NEWS b/NEWS index 86b1fe3f2..24688176b 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ PostGIS 3.5.7 - Flatgeobuf schema mismatch vulnerability (NeuroWinter) - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) - #5916, ST_Split hang with very large ordinates (Paul Ramsey) + - #5989, CurvePolygon distance corner case (Paul Ramsey) PostGIS 3.5.6 commit a79617120051b7119944a840bb5802389b4b80f3 Author: Paul Ramsey Date: Tue Jun 9 00:19:54 2026 +0000 Fix CurvePolygon distance issue, references #5989 diff --git a/liblwgeom/cunit/cu_measures.c b/liblwgeom/cunit/cu_measures.c index c95bf21e1..5cb4b6d81 100644 --- a/liblwgeom/cunit/cu_measures.c +++ b/liblwgeom/cunit/cu_measures.c @@ -235,6 +235,12 @@ static void test_mindistance2d_tolerance(void) DIST2DTEST( "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, -1 5, 0 10), (0 10, -10 10, -10 0, 0 0)))", "POINT(-0.5 5)", 0.5, default_accepted_error); + + /* Ticket 5989 reopened: multi-arc COMPOUNDCURVE with large Finnish coordinates */ + DIST2DTEST( + "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(25493681.3085 6678739.6419,25493637.8256 6678776.2541,25493599.9716 6678818.6604),(25493599.9716 6678818.6604,25493583.8816 6678839.494,25493590.9591 6678844.9594,25493566.9698 6678851.9051,25493526.5793 6678861.0985,25493487.3853 6678868.2546,25493447.392 6678871.7846,25493429.5033 6678876.6846,25493435.0147 6678857.4594,25493454.9254 6678821.6192,25493452.4867 6678816.1292,25493402.3226 6678828.2153,25493354.7526 6678837.8291,25493349.0217 6678838.9873,25493310.914 6678843.6926,25493306.3784 6678859.9295,25493294.1011 6678858.7864,25493169.9028 6678847.2212,25493127.549 6678843.2773,25493057.8888 6678834.6763,25493017.4547 6678826.7261,25492928.2395 6678821.5524,25492909.1067 6678795.0681,25492946.9544 6678794.8193,25492967.1292 6678794.6866,25493010.8878 6678795.9163,25493111.5564 6678804.3109,25493113.4069 6678799.5694,25493134.2375 6678806.0729),CIRCULARSTRING(25493134.2375 6678806.0729,25493223.038 6678812.0533,25493311 .4919 6678802.1948,25493317.3589 6678800.9679,25493323.2107 6678799.6707),(25493323.2107 6678799.6707,25493362.6615 6678792.3924,25493364.6948 6678785.173,25493375.0512 6678781.6008,25493404.9736 6678771.2798),CIRCULARSTRING(25493404.9736 6678771.2798,25493486.8049 6678737.6728,25493566.8862 6678700.0859),(25493566.8862 6678700.0859,25493574.903 6678714.0761,25493600.2214 6678702.8803,25493654.1114 6678670.2493,25493669.7219 6678659.2147,25493677.0288 6678653.353,25493684.6468 6678648.4119,25493724.0447 6678623.7638,25493800.1925 6678583.5847,25493805.6261 6678586.1292,25493811.9258 6678582.3016,25493812.8413 6678583.0522,25493846.581 6678558.6541,25493884.2653 6678531.6272,25493900.9168 6678580.1258,25493830.7852 6678630.9518,25493789.0848 6678661.2736,25493746.1612 6678692.485,25493686.5413 6678735.8369,25493681.3085 6678739.6419))))", + "POLYGON ((25492929.752797972 6678919.124091367,25493008.675235115 6678876.783133076,25493098.02917443 6678854.33589699,25493139.669701554 6678977.913508233,25493122.946292613 6679011.427315322,25493050.53388224 6679068.791126598,25493140.33593199 6679140.958135231,25492931.688606273 6679401.2946243705,25492799.289171 6679295.949040241,25492651.5177725 6679115.144800108,25492929.752797972 6678919.124091367))", + 14.5, 1.0); } static void diff --git a/liblwgeom/measures.c b/liblwgeom/measures.c index 6e13442cc..dc24ba42a 100644 --- a/liblwgeom/measures.c +++ b/liblwgeom/measures.c @@ -1392,17 +1392,33 @@ lw_dist2d_seg_arc(const POINT2D *A1, { double length_A; /* length of the segment A */ POINT2D E, F; /* points of intersection of edge A and circle(B) */ - double dist_D_EF; /* distance from D to E or F (same distance both ways) */ + double dist_D_EF; /* distance from D_line to E or F (same distance both ways) */ + POINT2D D_line; /* foot of perpendicular from C to the infinite line through A1-A2 */ + double dist_C_D_line; /* distance from C to the infinite line */ + double t; - dist_D_EF = sqrt(radius_C * radius_C - dist_C_D * dist_C_D); length_A = sqrt((A2->x - A1->x) * (A2->x - A1->x) + (A2->y - A1->y) * (A2->y - A1->y)); + /* + * D (from lw_dist2d_pt_seg) is clamped to the segment, but we need the + * foot of the perpendicular on the *infinite* line to correctly compute + * circle-line intersections E and F. Using the clamped endpoint gives wrong + * intersection points when the perpendicular falls outside the segment. + */ + t = ((C.x - A1->x) * (A2->x - A1->x) + (C.y - A1->y) * (A2->y - A1->y)) + / (length_A * length_A); + D_line.x = A1->x + t * (A2->x - A1->x); + D_line.y = A1->y + t * (A2->y - A1->y); + dist_C_D_line = sqrt((C.x - D_line.x) * (C.x - D_line.x) + (C.y - D_line.y) * (C.y - D_line.y)); + + dist_D_EF = sqrt(radius_C * radius_C - dist_C_D_line * dist_C_D_line); + /* Point of intersection E */ - E.x = D.x - (A2->x - A1->x) * dist_D_EF / length_A; - E.y = D.y - (A2->y - A1->y) * dist_D_EF / length_A; + E.x = D_line.x - (A2->x - A1->x) * dist_D_EF / length_A; + E.y = D_line.y - (A2->y - A1->y) * dist_D_EF / length_A; /* Point of intersection F */ - F.x = D.x + (A2->x - A1->x) * dist_D_EF / length_A; - F.y = D.y + (A2->y - A1->y) * dist_D_EF / length_A; + F.x = D_line.x + (A2->x - A1->x) * dist_D_EF / length_A; + F.y = D_line.y + (A2->y - A1->y) * dist_D_EF / length_A; /* If E is within A and within B then it's an intersection point */ pt_in_arc = lw_pt_in_arc(&E, B1, B2, B3); ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/cunit/cu_measures.c | 6 ++++++ liblwgeom/measures.c | 28 ++++++++++++++++++++++------ 3 files changed, 29 insertions(+), 6 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 11:20:30 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 18:20:30 -0000 Subject: [PostGIS] #5989: ST_Distance error on CurvePolygon In-Reply-To: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> References: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> Message-ID: <064.f2d9a7fe83f76e951c81154672a4557f@osgeo.org> #5989: ST_Distance error on CurvePolygon ----------------------+--------------------------- Reporter: pramsey | Owner: pramsey Type: defect | Status: reopened Priority: high | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.3.x Resolution: | Keywords: ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"a79617120051b7119944a840bb5802389b4b80f3/git" a796171/git]: {{{#!CommitTicketReference repository="git" revision="a79617120051b7119944a840bb5802389b4b80f3" Fix CurvePolygon distance issue, references #5989 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 11:20:31 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 11:20:31 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.4 updated. 3.4.6-10-g972920d9e Message-ID: <20260609182031.6A1E51B4664@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.4 has been updated via 972920d9eff7c95fbfa403b077721ccd0f1859e8 (commit) via 2d5bb926c78355ffee3c4cc2816146602bdb3e7f (commit) from df288d663f287faae94a517f106212b8760dfdd5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 972920d9eff7c95fbfa403b077721ccd0f1859e8 Author: Paul Ramsey Date: Tue Jun 9 10:59:33 2026 -0700 News entry for #5989 diff --git a/NEWS b/NEWS index 1f3d67a41..6bc77122d 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ PostGIS 3.4.7 - Flatgeobuf schema mismatch vulnerability (NeuroWinter) - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) - #5916, ST_Split hang with very large ordinates (Paul Ramsey) + - #5989, CurvePolygon distance corner case (Paul Ramsey) PostGIS 3.4.6 commit 2d5bb926c78355ffee3c4cc2816146602bdb3e7f Author: Paul Ramsey Date: Tue Jun 9 00:19:54 2026 +0000 Fix CurvePolygon distance issue, references #5989 diff --git a/liblwgeom/cunit/cu_measures.c b/liblwgeom/cunit/cu_measures.c index c95bf21e1..5cb4b6d81 100644 --- a/liblwgeom/cunit/cu_measures.c +++ b/liblwgeom/cunit/cu_measures.c @@ -235,6 +235,12 @@ static void test_mindistance2d_tolerance(void) DIST2DTEST( "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, -1 5, 0 10), (0 10, -10 10, -10 0, 0 0)))", "POINT(-0.5 5)", 0.5, default_accepted_error); + + /* Ticket 5989 reopened: multi-arc COMPOUNDCURVE with large Finnish coordinates */ + DIST2DTEST( + "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(25493681.3085 6678739.6419,25493637.8256 6678776.2541,25493599.9716 6678818.6604),(25493599.9716 6678818.6604,25493583.8816 6678839.494,25493590.9591 6678844.9594,25493566.9698 6678851.9051,25493526.5793 6678861.0985,25493487.3853 6678868.2546,25493447.392 6678871.7846,25493429.5033 6678876.6846,25493435.0147 6678857.4594,25493454.9254 6678821.6192,25493452.4867 6678816.1292,25493402.3226 6678828.2153,25493354.7526 6678837.8291,25493349.0217 6678838.9873,25493310.914 6678843.6926,25493306.3784 6678859.9295,25493294.1011 6678858.7864,25493169.9028 6678847.2212,25493127.549 6678843.2773,25493057.8888 6678834.6763,25493017.4547 6678826.7261,25492928.2395 6678821.5524,25492909.1067 6678795.0681,25492946.9544 6678794.8193,25492967.1292 6678794.6866,25493010.8878 6678795.9163,25493111.5564 6678804.3109,25493113.4069 6678799.5694,25493134.2375 6678806.0729),CIRCULARSTRING(25493134.2375 6678806.0729,25493223.038 6678812.0533,25493311 .4919 6678802.1948,25493317.3589 6678800.9679,25493323.2107 6678799.6707),(25493323.2107 6678799.6707,25493362.6615 6678792.3924,25493364.6948 6678785.173,25493375.0512 6678781.6008,25493404.9736 6678771.2798),CIRCULARSTRING(25493404.9736 6678771.2798,25493486.8049 6678737.6728,25493566.8862 6678700.0859),(25493566.8862 6678700.0859,25493574.903 6678714.0761,25493600.2214 6678702.8803,25493654.1114 6678670.2493,25493669.7219 6678659.2147,25493677.0288 6678653.353,25493684.6468 6678648.4119,25493724.0447 6678623.7638,25493800.1925 6678583.5847,25493805.6261 6678586.1292,25493811.9258 6678582.3016,25493812.8413 6678583.0522,25493846.581 6678558.6541,25493884.2653 6678531.6272,25493900.9168 6678580.1258,25493830.7852 6678630.9518,25493789.0848 6678661.2736,25493746.1612 6678692.485,25493686.5413 6678735.8369,25493681.3085 6678739.6419))))", + "POLYGON ((25492929.752797972 6678919.124091367,25493008.675235115 6678876.783133076,25493098.02917443 6678854.33589699,25493139.669701554 6678977.913508233,25493122.946292613 6679011.427315322,25493050.53388224 6679068.791126598,25493140.33593199 6679140.958135231,25492931.688606273 6679401.2946243705,25492799.289171 6679295.949040241,25492651.5177725 6679115.144800108,25492929.752797972 6678919.124091367))", + 14.5, 1.0); } static void diff --git a/liblwgeom/measures.c b/liblwgeom/measures.c index d2f7b9783..4d90a12a7 100644 --- a/liblwgeom/measures.c +++ b/liblwgeom/measures.c @@ -1392,17 +1392,33 @@ lw_dist2d_seg_arc(const POINT2D *A1, { double length_A; /* length of the segment A */ POINT2D E, F; /* points of intersection of edge A and circle(B) */ - double dist_D_EF; /* distance from D to E or F (same distance both ways) */ + double dist_D_EF; /* distance from D_line to E or F (same distance both ways) */ + POINT2D D_line; /* foot of perpendicular from C to the infinite line through A1-A2 */ + double dist_C_D_line; /* distance from C to the infinite line */ + double t; - dist_D_EF = sqrt(radius_C * radius_C - dist_C_D * dist_C_D); length_A = sqrt((A2->x - A1->x) * (A2->x - A1->x) + (A2->y - A1->y) * (A2->y - A1->y)); + /* + * D (from lw_dist2d_pt_seg) is clamped to the segment, but we need the + * foot of the perpendicular on the *infinite* line to correctly compute + * circle-line intersections E and F. Using the clamped endpoint gives wrong + * intersection points when the perpendicular falls outside the segment. + */ + t = ((C.x - A1->x) * (A2->x - A1->x) + (C.y - A1->y) * (A2->y - A1->y)) + / (length_A * length_A); + D_line.x = A1->x + t * (A2->x - A1->x); + D_line.y = A1->y + t * (A2->y - A1->y); + dist_C_D_line = sqrt((C.x - D_line.x) * (C.x - D_line.x) + (C.y - D_line.y) * (C.y - D_line.y)); + + dist_D_EF = sqrt(radius_C * radius_C - dist_C_D_line * dist_C_D_line); + /* Point of intersection E */ - E.x = D.x - (A2->x - A1->x) * dist_D_EF / length_A; - E.y = D.y - (A2->y - A1->y) * dist_D_EF / length_A; + E.x = D_line.x - (A2->x - A1->x) * dist_D_EF / length_A; + E.y = D_line.y - (A2->y - A1->y) * dist_D_EF / length_A; /* Point of intersection F */ - F.x = D.x + (A2->x - A1->x) * dist_D_EF / length_A; - F.y = D.y + (A2->y - A1->y) * dist_D_EF / length_A; + F.x = D_line.x + (A2->x - A1->x) * dist_D_EF / length_A; + F.y = D_line.y + (A2->y - A1->y) * dist_D_EF / length_A; /* If E is within A and within B then it's an intersection point */ pt_in_arc = lw_pt_in_arc(&E, B1, B2, B3); ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/cunit/cu_measures.c | 6 ++++++ liblwgeom/measures.c | 28 ++++++++++++++++++++++------ 3 files changed, 29 insertions(+), 6 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 11:20:32 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 18:20:32 -0000 Subject: [PostGIS] #5989: ST_Distance error on CurvePolygon In-Reply-To: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> References: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> Message-ID: <064.473c3b482aafcd3a881930fcabef83d1@osgeo.org> #5989: ST_Distance error on CurvePolygon ----------------------+--------------------------- Reporter: pramsey | Owner: pramsey Type: defect | Status: reopened Priority: high | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.3.x Resolution: | Keywords: ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"2d5bb926c78355ffee3c4cc2816146602bdb3e7f/git" 2d5bb92/git]: {{{#!CommitTicketReference repository="git" revision="2d5bb926c78355ffee3c4cc2816146602bdb3e7f" Fix CurvePolygon distance issue, references #5989 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 11:20:33 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 11:20:33 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.3 updated. 3.3.10-10-g3d8ea8159 Message-ID: <20260609182033.D0DB31B4A35@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.3 has been updated via 3d8ea8159afc4a68c54098eac24a1794e360f1aa (commit) via 8a5594e4d4fd27331c5f127aee04ecaad66a239c (commit) from 281c3f70e293c32c6b05c625eb43b47062d5c4af (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 3d8ea8159afc4a68c54098eac24a1794e360f1aa Author: Paul Ramsey Date: Tue Jun 9 10:59:35 2026 -0700 News entry for #5989 diff --git a/NEWS b/NEWS index de3b09c39..bea7bd871 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ PostGIS 3.3.11 - Flatgeobuf schema mismatch vulnerability (NeuroWinter) - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) - #5916, ST_Split hang with very large ordinates (Paul Ramsey) + - #5989, CurvePolygon distance corner case (Paul Ramsey) PostGIS 3.3.10 commit 8a5594e4d4fd27331c5f127aee04ecaad66a239c Author: Paul Ramsey Date: Tue Jun 9 00:19:54 2026 +0000 Fix CurvePolygon distance issue, references #5989 diff --git a/liblwgeom/cunit/cu_measures.c b/liblwgeom/cunit/cu_measures.c index 9713bf653..c589e609f 100644 --- a/liblwgeom/cunit/cu_measures.c +++ b/liblwgeom/cunit/cu_measures.c @@ -229,6 +229,17 @@ static void test_mindistance2d_tolerance(void) DIST2DTEST( "CURVEPOLYGON(CIRCULARSTRING(7874821 8715927,8907663 8715927,8844683 7750316,7937800 7750316,7874821 8715927))", "POINT(5433865 8243495)", 2271704.2698450615, default_accepted_error); + + /* Ticket 5989 */ + DIST2DTEST( + "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, -1 5, 0 10), (0 10, -10 10, -10 0, 0 0)))", + "POINT(-0.5 5)", 0.5, default_accepted_error); + + /* Ticket 5989 reopened: multi-arc COMPOUNDCURVE with large Finnish coordinates */ + DIST2DTEST( + "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(25493681.3085 6678739.6419,25493637.8256 6678776.2541,25493599.9716 6678818.6604),(25493599.9716 6678818.6604,25493583.8816 6678839.494,25493590.9591 6678844.9594,25493566.9698 6678851.9051,25493526.5793 6678861.0985,25493487.3853 6678868.2546,25493447.392 6678871.7846,25493429.5033 6678876.6846,25493435.0147 6678857.4594,25493454.9254 6678821.6192,25493452.4867 6678816.1292,25493402.3226 6678828.2153,25493354.7526 6678837.8291,25493349.0217 6678838.9873,25493310.914 6678843.6926,25493306.3784 6678859.9295,25493294.1011 6678858.7864,25493169.9028 6678847.2212,25493127.549 6678843.2773,25493057.8888 6678834.6763,25493017.4547 6678826.7261,25492928.2395 6678821.5524,25492909.1067 6678795.0681,25492946.9544 6678794.8193,25492967.1292 6678794.6866,25493010.8878 6678795.9163,25493111.5564 6678804.3109,25493113.4069 6678799.5694,25493134.2375 6678806.0729),CIRCULARSTRING(25493134.2375 6678806.0729,25493223.038 6678812.0533,25493311 .4919 6678802.1948,25493317.3589 6678800.9679,25493323.2107 6678799.6707),(25493323.2107 6678799.6707,25493362.6615 6678792.3924,25493364.6948 6678785.173,25493375.0512 6678781.6008,25493404.9736 6678771.2798),CIRCULARSTRING(25493404.9736 6678771.2798,25493486.8049 6678737.6728,25493566.8862 6678700.0859),(25493566.8862 6678700.0859,25493574.903 6678714.0761,25493600.2214 6678702.8803,25493654.1114 6678670.2493,25493669.7219 6678659.2147,25493677.0288 6678653.353,25493684.6468 6678648.4119,25493724.0447 6678623.7638,25493800.1925 6678583.5847,25493805.6261 6678586.1292,25493811.9258 6678582.3016,25493812.8413 6678583.0522,25493846.581 6678558.6541,25493884.2653 6678531.6272,25493900.9168 6678580.1258,25493830.7852 6678630.9518,25493789.0848 6678661.2736,25493746.1612 6678692.485,25493686.5413 6678735.8369,25493681.3085 6678739.6419))))", + "POLYGON ((25492929.752797972 6678919.124091367,25493008.675235115 6678876.783133076,25493098.02917443 6678854.33589699,25493139.669701554 6678977.913508233,25493122.946292613 6679011.427315322,25493050.53388224 6679068.791126598,25493140.33593199 6679140.958135231,25492931.688606273 6679401.2946243705,25492799.289171 6679295.949040241,25492651.5177725 6679115.144800108,25492929.752797972 6678919.124091367))", + 14.5, 1.0); } static void diff --git a/liblwgeom/measures.c b/liblwgeom/measures.c index 2774b38c0..fe6440565 100644 --- a/liblwgeom/measures.c +++ b/liblwgeom/measures.c @@ -1392,17 +1392,33 @@ lw_dist2d_seg_arc(const POINT2D *A1, { double length_A; /* length of the segment A */ POINT2D E, F; /* points of intersection of edge A and circle(B) */ - double dist_D_EF; /* distance from D to E or F (same distance both ways) */ + double dist_D_EF; /* distance from D_line to E or F (same distance both ways) */ + POINT2D D_line; /* foot of perpendicular from C to the infinite line through A1-A2 */ + double dist_C_D_line; /* distance from C to the infinite line */ + double t; - dist_D_EF = sqrt(radius_C * radius_C - dist_C_D * dist_C_D); length_A = sqrt((A2->x - A1->x) * (A2->x - A1->x) + (A2->y - A1->y) * (A2->y - A1->y)); + /* + * D (from lw_dist2d_pt_seg) is clamped to the segment, but we need the + * foot of the perpendicular on the *infinite* line to correctly compute + * circle-line intersections E and F. Using the clamped endpoint gives wrong + * intersection points when the perpendicular falls outside the segment. + */ + t = ((C.x - A1->x) * (A2->x - A1->x) + (C.y - A1->y) * (A2->y - A1->y)) + / (length_A * length_A); + D_line.x = A1->x + t * (A2->x - A1->x); + D_line.y = A1->y + t * (A2->y - A1->y); + dist_C_D_line = sqrt((C.x - D_line.x) * (C.x - D_line.x) + (C.y - D_line.y) * (C.y - D_line.y)); + + dist_D_EF = sqrt(radius_C * radius_C - dist_C_D_line * dist_C_D_line); + /* Point of intersection E */ - E.x = D.x - (A2->x - A1->x) * dist_D_EF / length_A; - E.y = D.y - (A2->y - A1->y) * dist_D_EF / length_A; + E.x = D_line.x - (A2->x - A1->x) * dist_D_EF / length_A; + E.y = D_line.y - (A2->y - A1->y) * dist_D_EF / length_A; /* Point of intersection F */ - F.x = D.x + (A2->x - A1->x) * dist_D_EF / length_A; - F.y = D.y + (A2->y - A1->y) * dist_D_EF / length_A; + F.x = D_line.x + (A2->x - A1->x) * dist_D_EF / length_A; + F.y = D_line.y + (A2->y - A1->y) * dist_D_EF / length_A; /* If E is within A and within B then it's an intersection point */ pt_in_arc = lw_pt_in_arc(&E, B1, B2, B3); ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/cunit/cu_measures.c | 11 +++++++++++ liblwgeom/measures.c | 28 ++++++++++++++++++++++------ 3 files changed, 34 insertions(+), 6 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 11:20:35 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 18:20:35 -0000 Subject: [PostGIS] #5989: ST_Distance error on CurvePolygon In-Reply-To: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> References: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> Message-ID: <064.c32ef5519414a130b47c7f0ec1ba8a40@osgeo.org> #5989: ST_Distance error on CurvePolygon ----------------------+--------------------------- Reporter: pramsey | Owner: pramsey Type: defect | Status: reopened Priority: high | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.3.x Resolution: | Keywords: ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"8a5594e4d4fd27331c5f127aee04ecaad66a239c/git" 8a5594e/git]: {{{#!CommitTicketReference repository="git" revision="8a5594e4d4fd27331c5f127aee04ecaad66a239c" Fix CurvePolygon distance issue, references #5989 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 11:20:36 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 11:20:36 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.2 updated. 3.2.10-8-g49f46836b Message-ID: <20260609182036.A297F1B4669@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.2 has been updated via 49f46836bd6c55167d60532b5b9b382f4b9a05d6 (commit) via a00a220ecfeb15c231310bd806b26ab86398689c (commit) from 69525adbe50c6f70eb7198d8aad88e4e64c9d111 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 49f46836bd6c55167d60532b5b9b382f4b9a05d6 Author: Paul Ramsey Date: Tue Jun 9 10:59:36 2026 -0700 News entry for #5989 diff --git a/NEWS b/NEWS index 01e2752ca..e300de28d 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PostGIS 3.2.11 - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) - Flatgeobuf schema mismatch vulnerability (NeuroWinter) + - #5989, CurvePolygon distance corner case (Paul Ramsey) PostGIS 3.2.10 commit a00a220ecfeb15c231310bd806b26ab86398689c Author: Paul Ramsey Date: Tue Jun 9 00:19:54 2026 +0000 Fix CurvePolygon distance issue, references #5989 diff --git a/liblwgeom/cunit/cu_measures.c b/liblwgeom/cunit/cu_measures.c index c7e44facc..1bef756e4 100644 --- a/liblwgeom/cunit/cu_measures.c +++ b/liblwgeom/cunit/cu_measures.c @@ -229,6 +229,18 @@ static void test_mindistance2d_tolerance(void) DIST2DTEST( "CURVEPOLYGON(CIRCULARSTRING(7874821 8715927,8907663 8715927,8844683 7750316,7937800 7750316,7874821 8715927))", "POINT(5433865 8243495)", 2271704.2698450615, default_accepted_error); + + + /* Ticket 5989 */ + DIST2DTEST( + "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, -1 5, 0 10), (0 10, -10 10, -10 0, 0 0)))", + "POINT(-0.5 5)", 0.5, default_accepted_error); + + /* Ticket 5989 reopened: multi-arc COMPOUNDCURVE with large Finnish coordinates */ + DIST2DTEST( + "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(25493681.3085 6678739.6419,25493637.8256 6678776.2541,25493599.9716 6678818.6604),(25493599.9716 6678818.6604,25493583.8816 6678839.494,25493590.9591 6678844.9594,25493566.9698 6678851.9051,25493526.5793 6678861.0985,25493487.3853 6678868.2546,25493447.392 6678871.7846,25493429.5033 6678876.6846,25493435.0147 6678857.4594,25493454.9254 6678821.6192,25493452.4867 6678816.1292,25493402.3226 6678828.2153,25493354.7526 6678837.8291,25493349.0217 6678838.9873,25493310.914 6678843.6926,25493306.3784 6678859.9295,25493294.1011 6678858.7864,25493169.9028 6678847.2212,25493127.549 6678843.2773,25493057.8888 6678834.6763,25493017.4547 6678826.7261,25492928.2395 6678821.5524,25492909.1067 6678795.0681,25492946.9544 6678794.8193,25492967.1292 6678794.6866,25493010.8878 6678795.9163,25493111.5564 6678804.3109,25493113.4069 6678799.5694,25493134.2375 6678806.0729),CIRCULARSTRING(25493134.2375 6678806.0729,25493223.038 6678812.0533,25493311 .4919 6678802.1948,25493317.3589 6678800.9679,25493323.2107 6678799.6707),(25493323.2107 6678799.6707,25493362.6615 6678792.3924,25493364.6948 6678785.173,25493375.0512 6678781.6008,25493404.9736 6678771.2798),CIRCULARSTRING(25493404.9736 6678771.2798,25493486.8049 6678737.6728,25493566.8862 6678700.0859),(25493566.8862 6678700.0859,25493574.903 6678714.0761,25493600.2214 6678702.8803,25493654.1114 6678670.2493,25493669.7219 6678659.2147,25493677.0288 6678653.353,25493684.6468 6678648.4119,25493724.0447 6678623.7638,25493800.1925 6678583.5847,25493805.6261 6678586.1292,25493811.9258 6678582.3016,25493812.8413 6678583.0522,25493846.581 6678558.6541,25493884.2653 6678531.6272,25493900.9168 6678580.1258,25493830.7852 6678630.9518,25493789.0848 6678661.2736,25493746.1612 6678692.485,25493686.5413 6678735.8369,25493681.3085 6678739.6419))))", + "POLYGON ((25492929.752797972 6678919.124091367,25493008.675235115 6678876.783133076,25493098.02917443 6678854.33589699,25493139.669701554 6678977.913508233,25493122.946292613 6679011.427315322,25493050.53388224 6679068.791126598,25493140.33593199 6679140.958135231,25492931.688606273 6679401.2946243705,25492799.289171 6679295.949040241,25492651.5177725 6679115.144800108,25492929.752797972 6678919.124091367))", + 14.5, 1.0); } static void diff --git a/liblwgeom/measures.c b/liblwgeom/measures.c index 2fd00f944..99241379a 100644 --- a/liblwgeom/measures.c +++ b/liblwgeom/measures.c @@ -1381,17 +1381,33 @@ lw_dist2d_seg_arc(const POINT2D *A1, { double length_A; /* length of the segment A */ POINT2D E, F; /* points of intersection of edge A and circle(B) */ - double dist_D_EF; /* distance from D to E or F (same distance both ways) */ + double dist_D_EF; /* distance from D_line to E or F (same distance both ways) */ + POINT2D D_line; /* foot of perpendicular from C to the infinite line through A1-A2 */ + double dist_C_D_line; /* distance from C to the infinite line */ + double t; - dist_D_EF = sqrt(radius_C * radius_C - dist_C_D * dist_C_D); length_A = sqrt((A2->x - A1->x) * (A2->x - A1->x) + (A2->y - A1->y) * (A2->y - A1->y)); + /* + * D (from lw_dist2d_pt_seg) is clamped to the segment, but we need the + * foot of the perpendicular on the *infinite* line to correctly compute + * circle-line intersections E and F. Using the clamped endpoint gives wrong + * intersection points when the perpendicular falls outside the segment. + */ + t = ((C.x - A1->x) * (A2->x - A1->x) + (C.y - A1->y) * (A2->y - A1->y)) + / (length_A * length_A); + D_line.x = A1->x + t * (A2->x - A1->x); + D_line.y = A1->y + t * (A2->y - A1->y); + dist_C_D_line = sqrt((C.x - D_line.x) * (C.x - D_line.x) + (C.y - D_line.y) * (C.y - D_line.y)); + + dist_D_EF = sqrt(radius_C * radius_C - dist_C_D_line * dist_C_D_line); + /* Point of intersection E */ - E.x = D.x - (A2->x - A1->x) * dist_D_EF / length_A; - E.y = D.y - (A2->y - A1->y) * dist_D_EF / length_A; + E.x = D_line.x - (A2->x - A1->x) * dist_D_EF / length_A; + E.y = D_line.y - (A2->y - A1->y) * dist_D_EF / length_A; /* Point of intersection F */ - F.x = D.x + (A2->x - A1->x) * dist_D_EF / length_A; - F.y = D.y + (A2->y - A1->y) * dist_D_EF / length_A; + F.x = D_line.x + (A2->x - A1->x) * dist_D_EF / length_A; + F.y = D_line.y + (A2->y - A1->y) * dist_D_EF / length_A; /* If E is within A and within B then it's an intersection point */ pt_in_arc = lw_pt_in_arc(&E, B1, B2, B3); ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/cunit/cu_measures.c | 12 ++++++++++++ liblwgeom/measures.c | 28 ++++++++++++++++++++++------ 3 files changed, 35 insertions(+), 6 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 11:20:38 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 18:20:38 -0000 Subject: [PostGIS] #5989: ST_Distance error on CurvePolygon In-Reply-To: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> References: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> Message-ID: <064.9663b0ecec98237e5f433ec91c9d5c97@osgeo.org> #5989: ST_Distance error on CurvePolygon ----------------------+--------------------------- Reporter: pramsey | Owner: pramsey Type: defect | Status: reopened Priority: high | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.3.x Resolution: | Keywords: ----------------------+--------------------------- Comment (by Paul Ramsey ): In [changeset:"a00a220ecfeb15c231310bd806b26ab86398689c/git" a00a220/git]: {{{#!CommitTicketReference repository="git" revision="a00a220ecfeb15c231310bd806b26ab86398689c" Fix CurvePolygon distance issue, references #5989 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Tue Jun 9 11:20:58 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 18:20:58 -0000 Subject: [PostGIS] #5989: ST_Distance error on CurvePolygon In-Reply-To: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> References: <049.160f5b03509401c2e12090c58b6e5840@osgeo.org> Message-ID: <064.fae341cf49af6d13157140c7c8651b4e@osgeo.org> #5989: ST_Distance error on CurvePolygon ----------------------+--------------------------- Reporter: pramsey | Owner: pramsey Type: defect | Status: closed Priority: high | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.3.x Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by pramsey): * resolution: => fixed * status: reopened => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 12:40:11 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 12:40:11 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-509-gbbbe84257 Message-ID: <20260609194011.58CA61B57A1@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via bbbe84257be29b0101088e5da69677924f65cdd0 (commit) via 8da97650d154e7b70b0a58f5be4c2870848bd06c (commit) from 6216b684aaff36b393d5d5707c95a896b1e89ffc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit bbbe84257be29b0101088e5da69677924f65cdd0 Author: Paul Ramsey Date: Tue Jun 9 12:40:05 2026 -0700 News item for #4560 diff --git a/NEWS b/NEWS index aaf9f2c05..17b07b97f 100644 --- a/NEWS +++ b/NEWS @@ -40,6 +40,7 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.2+ is needed - #2614, Use GEOSPreparedDistance and caching to accelerate ST_DWithin (Paul Ramsey) - GH-839, ST_Multi support for TIN and surfaces (Lo?c Bartoletti) - #4398, Add ST_CatmullSmoothing smoothes but retains original vertices (Paul Ramsey) + - #4560, ST_3DInterpolatePoint for M interpolation from XYZ inputs (Paul Ramsey) * Enhancements * commit 8da97650d154e7b70b0a58f5be4c2870848bd06c Author: Paul Ramsey Date: Tue Jun 9 19:32:57 2026 +0000 Add ST_3DInterpolatePoint for ZM geometry measure interpolation Projects a query point onto a LINESTRING ZM using 3D (XYZ) distance, returning the interpolated M value. Closes #4560. diff --git a/doc/reference_lrs.xml b/doc/reference_lrs.xml index 570d4daea..c0c797c65 100644 --- a/doc/reference_lrs.xml +++ b/doc/reference_lrs.xml @@ -744,6 +744,68 @@ SELECT ST_AsText( , , + + + + + ST_3DInterpolatePoint + + Returns the interpolated measure of a geometry closest to a point in 3D. + + + + + + float8 ST_3DInterpolatePoint + geometry linear_geom_with_measure + geometry point + + + + + + Description + + Returns the interpolated measure value of a linear ZM geometry + at the location closest to the given point, using 3D (XYZ) distance + for the projection. Use this function when the geometry has + significant Z variation, such as flight trajectories, where + would give incorrect results + by ignoring the Z dimension. + + The line must have both Z and M dimensions. + The point should have a Z dimension. + + Availability: 3.7.0 + + &Z_support; + + + + Examples + + -- Line rising diagonally in Z; point at the 3D midpoint +SELECT ST_3DInterpolatePoint( + 'LINESTRING ZM (0 0 0 0, 10 0 10 20)', + 'POINT Z (5 0 5)'); + --------------------- + 10 + +-- Vertical line (zero XY extent); 3D projection works where 2D would not +SELECT ST_3DInterpolatePoint( + 'LINESTRING ZM (0 0 0 0, 0 0 10 100)', + 'POINT Z (5 5 5)'); + --------------------- + 50 + + + + + See Also + , , + , + + diff --git a/liblwgeom/cunit/cu_algorithm.c b/liblwgeom/cunit/cu_algorithm.c index 1194785c4..6ac9da3c7 100644 --- a/liblwgeom/cunit/cu_algorithm.c +++ b/liblwgeom/cunit/cu_algorithm.c @@ -596,6 +596,52 @@ test_lwline_interpolate_point_3d(void) lwline_free(line); } +static void +test_lwgeom_interpolate_point_3d(void) +{ + LWGEOM *line; + LWPOINT *pt; + double result; + + /* Simple diagonal line in XYZ, point at 3D midpoint */ + line = lwgeom_from_wkt("LINESTRING ZM (0 0 0 0, 10 0 10 20)", LW_PARSER_CHECK_NONE); + pt = lwgeom_as_lwpoint(lwgeom_from_wkt("POINT Z (5 0 5)", LW_PARSER_CHECK_NONE)); + result = lwgeom_interpolate_point_3d(line, pt); + CU_ASSERT_DOUBLE_EQUAL(result, 10.0, 1e-10); + lwpoint_free(pt); + + /* Point offset in Y but same XZ projection: same result */ + pt = lwgeom_as_lwpoint(lwgeom_from_wkt("POINT Z (5 99 5)", LW_PARSER_CHECK_NONE)); + result = lwgeom_interpolate_point_3d(line, pt); + CU_ASSERT_DOUBLE_EQUAL(result, 10.0, 1e-10); + lwpoint_free(pt); + lwgeom_free(line); + + /* Vertical line (zero XY extent): 3D projection works where 2D would not */ + line = lwgeom_from_wkt("LINESTRING ZM (0 0 0 0, 0 0 10 100)", LW_PARSER_CHECK_NONE); + pt = lwgeom_as_lwpoint(lwgeom_from_wkt("POINT Z (5 5 5)", LW_PARSER_CHECK_NONE)); + result = lwgeom_interpolate_point_3d(line, pt); + CU_ASSERT_DOUBLE_EQUAL(result, 50.0, 1e-10); + lwpoint_free(pt); + lwgeom_free(line); + + /* Point beyond end of line: clamped to end M */ + line = lwgeom_from_wkt("LINESTRING ZM (0 0 0 0, 10 0 0 100)", LW_PARSER_CHECK_NONE); + pt = lwgeom_as_lwpoint(lwgeom_from_wkt("POINT Z (20 0 0)", LW_PARSER_CHECK_NONE)); + result = lwgeom_interpolate_point_3d(line, pt); + CU_ASSERT_DOUBLE_EQUAL(result, 100.0, 1e-10); + lwpoint_free(pt); + lwgeom_free(line); + + /* Point before start of line: clamped to start M */ + line = lwgeom_from_wkt("LINESTRING ZM (0 0 0 0, 10 0 0 100)", LW_PARSER_CHECK_NONE); + pt = lwgeom_as_lwpoint(lwgeom_from_wkt("POINT Z (-5 0 0)", LW_PARSER_CHECK_NONE)); + result = lwgeom_interpolate_point_3d(line, pt); + CU_ASSERT_DOUBLE_EQUAL(result, 0.0, 1e-10); + lwpoint_free(pt); + lwgeom_free(line); +} + static void test_lwline_clip(void) { LWCOLLECTION *c; @@ -1844,6 +1890,7 @@ void algorithms_suite_setup(void) PG_ADD_TEST(suite,test_point_interpolate); PG_ADD_TEST(suite,test_lwline_interpolate_points); PG_ADD_TEST(suite, test_lwline_interpolate_point_3d); + PG_ADD_TEST(suite, test_lwgeom_interpolate_point_3d); PG_ADD_TEST(suite,test_lwline_clip); PG_ADD_TEST(suite, test_lwpoly_clip); PG_ADD_TEST(suite, test_lwtriangle_clip); diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index 3ac202217..692167c13 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -1623,6 +1623,7 @@ extern LWCOLLECTION* lwgeom_locate_between(const LWGEOM *lwin, double from, doub * Find the measure value at the location on the line closest to the point. */ extern double lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt); +extern double lwgeom_interpolate_point_3d(const LWGEOM *lwin, const LWPOINT *lwpt); /** * Find the time of closest point of approach diff --git a/liblwgeom/lwlinearreferencing.c b/liblwgeom/lwlinearreferencing.c index 610f0cf4e..ace84cc08 100644 --- a/liblwgeom/lwlinearreferencing.c +++ b/liblwgeom/lwlinearreferencing.c @@ -947,6 +947,86 @@ lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt) return ret; } +double +lwgeom_interpolate_point_3d(const LWGEOM *lwin, const LWPOINT *lwpt) +{ + POINT4D p, A, B, closest; + double mindist2 = DBL_MAX; + double best_m = 0.0; + uint32_t i; + + if (!lwin) + lwerror("lwgeom_interpolate_point_3d: null input geometry!"); + + if (!lwgeom_has_m(lwin)) + lwerror("Input geometry does not have a measure dimension"); + + if (!lwgeom_has_z(lwin)) + lwerror("Input geometry does not have a Z dimension"); + + if (lwgeom_is_empty(lwin) || lwpoint_is_empty(lwpt)) + lwerror("Input geometry is empty"); + + switch (lwin->type) + { + case LINETYPE: + { + LWLINE *lwline = lwgeom_as_lwline(lwin); + POINTARRAY *pa = lwline->points; + + lwpoint_getPoint4d_p(lwpt, &p); + + if (pa->npoints == 1) + { + getPoint4d_p(pa, 0, &closest); + return closest.m; + } + + for (i = 0; i < pa->npoints - 1; i++) + { + double dx, dy, dz, len2, r; + double cx, cy, cz, d2; + + getPoint4d_p(pa, i, &A); + getPoint4d_p(pa, i + 1, &B); + + dx = B.x - A.x; + dy = B.y - A.y; + dz = B.z - A.z; + len2 = dx * dx + dy * dy + dz * dz; + + if (len2 == 0.0) + { + /* Degenerate segment: distance to point A */ + r = 0.0; + } + else + { + r = ((p.x - A.x) * dx + (p.y - A.y) * dy + (p.z - A.z) * dz) / len2; + if (r < 0.0) r = 0.0; + if (r > 1.0) r = 1.0; + } + + cx = A.x + r * dx; + cy = A.y + r * dy; + cz = A.z + r * dz; + + d2 = (p.x - cx) * (p.x - cx) + (p.y - cy) * (p.y - cy) + (p.z - cz) * (p.z - cz); + + if (d2 < mindist2) + { + mindist2 = d2; + best_m = A.m + r * (B.m - A.m); + } + } + break; + } + default: + lwerror("This function does not accept %s geometries.", lwtype_name(lwin->type)); + } + return best_m; +} + /* * Time of closest point of approach * diff --git a/postgis/lwgeom_functions_lrs.c b/postgis/lwgeom_functions_lrs.c index 474d07ea9..b02afb5bb 100644 --- a/postgis/lwgeom_functions_lrs.c +++ b/postgis/lwgeom_functions_lrs.c @@ -214,6 +214,47 @@ Datum ST_InterpolatePoint(PG_FUNCTION_ARGS) } +Datum ST_3DInterpolatePoint(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(ST_3DInterpolatePoint); +Datum ST_3DInterpolatePoint(PG_FUNCTION_ARGS) +{ + GSERIALIZED *gser_line = PG_GETARG_GSERIALIZED_P(0); + GSERIALIZED *gser_point = PG_GETARG_GSERIALIZED_P(1); + LWGEOM *lwline; + LWPOINT *lwpoint; + + if ( gserialized_get_type(gser_line) != LINETYPE ) + { + elog(ERROR,"ST_3DInterpolatePoint: 1st argument isn't a line"); + PG_RETURN_NULL(); + } + if ( gserialized_get_type(gser_point) != POINTTYPE ) + { + elog(ERROR,"ST_3DInterpolatePoint: 2nd argument isn't a point"); + PG_RETURN_NULL(); + } + + gserialized_error_if_srid_mismatch(gser_line, gser_point, __func__); + + if ( ! gserialized_has_m(gser_line) ) + { + elog(ERROR,"ST_3DInterpolatePoint only accepts geometries that have an M dimension"); + PG_RETURN_NULL(); + } + + if ( ! gserialized_has_z(gser_line) ) + { + elog(ERROR,"ST_3DInterpolatePoint only accepts geometries that have a Z dimension"); + PG_RETURN_NULL(); + } + + lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(gser_point)); + lwline = lwgeom_from_gserialized(gser_line); + + PG_RETURN_FLOAT8(lwgeom_interpolate_point_3d(lwline, lwpoint)); +} + + Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(LWGEOM_line_locate_point); Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS) diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 73d41a465..bf3a094d9 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -6682,6 +6682,13 @@ CREATE OR REPLACE FUNCTION ST_InterpolatePoint(Line geometry, Point geometry) LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE _COST_MEDIUM; +-- Availability: 3.7.0 +CREATE OR REPLACE FUNCTION ST_3DInterpolatePoint(Line geometry, Point geometry) + RETURNS float8 + AS 'MODULE_PATHNAME', 'ST_3DInterpolatePoint' + LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE + _COST_MEDIUM; + --------------------------------------------------------------- -- Grid / Hexagon coverage functions --- diff --git a/regress/core/regress_lrs.sql b/regress/core/regress_lrs.sql index 06e419dae..92706eb26 100644 --- a/regress/core/regress_lrs.sql +++ b/regress/core/regress_lrs.sql @@ -99,3 +99,11 @@ select 'addMeasure2', ST_AsText(ST_AddMeasure('LINESTRING(0 0, 9 0, 10 0)', 10, select 'interpolatePoint1', ST_InterpolatePoint('LINESTRINGM(0 0 0, 10 0 4)', 'POINT(5 0)'); select 'interpolatePoint2', ST_InterpolatePoint('LINESTRINGM(0 0 0, 10 0 4)', 'POINT(7.5 0)'); + +-- +-- ST_3DInterpolatePoint +-- + +select '3DinterpolatePoint1', ST_3DInterpolatePoint('LINESTRING ZM (0 0 0 0, 10 0 10 20)', 'POINT Z (5 0 5)'); +select '3DinterpolatePoint2', ST_3DInterpolatePoint('LINESTRING ZM (0 0 0 0, 10 0 10 20)', 'POINT Z (5 5 5)'); +select '3DinterpolatePoint3', ST_3DInterpolatePoint('LINESTRING ZM (0 0 0 0, 0 0 10 100)', 'POINT Z (5 5 5)'); diff --git a/regress/core/regress_lrs_expected b/regress/core/regress_lrs_expected index bdc232637..868662a6f 100644 --- a/regress/core/regress_lrs_expected +++ b/regress/core/regress_lrs_expected @@ -47,3 +47,6 @@ addMeasure1|LINESTRING M (0 0 10,2 0 15,4 0 20) addMeasure2|LINESTRING M (0 0 10,9 0 19,10 0 20) interpolatePoint1|2 interpolatePoint2|3 +3DinterpolatePoint1|10 +3DinterpolatePoint2|10 +3DinterpolatePoint3|50 ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + doc/reference_lrs.xml | 62 ++++++++++++++++++++++++++++++ liblwgeom/cunit/cu_algorithm.c | 47 +++++++++++++++++++++++ liblwgeom/liblwgeom.h.in | 1 + liblwgeom/lwlinearreferencing.c | 80 +++++++++++++++++++++++++++++++++++++++ postgis/lwgeom_functions_lrs.c | 41 ++++++++++++++++++++ postgis/postgis.sql.in | 7 ++++ regress/core/regress_lrs.sql | 8 ++++ regress/core/regress_lrs_expected | 3 ++ 9 files changed, 250 insertions(+) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 12:40:13 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 19:40:13 -0000 Subject: [PostGIS] #4560: ST_3DInterpolatePoint In-Reply-To: <046.0c5f530ced274a58e267beab933ae3f5@osgeo.org> References: <046.0c5f530ced274a58e267beab933ae3f5@osgeo.org> Message-ID: <061.21468f6a2481c03465929089b3b1f011@osgeo.org> #4560: ST_3DInterpolatePoint ----------------------+--------------------------- Reporter: robe | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by Paul Ramsey ): * resolution: => fixed * status: new => closed Comment: In [changeset:"8da97650d154e7b70b0a58f5be4c2870848bd06c/git" 8da9765/git]: {{{#!CommitTicketReference repository="git" revision="8da97650d154e7b70b0a58f5be4c2870848bd06c" Add ST_3DInterpolatePoint for ZM geometry measure interpolation Projects a query point onto a LINESTRING ZM using 3D (XYZ) distance, returning the interpolated M value. Closes #4560. }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Tue Jun 9 13:05:43 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 20:05:43 -0000 Subject: [PostGIS] #5844: ST_AsMVTGeom producing null results on valid geoms In-Reply-To: <051.b260e5b57879f6a4c45ac40e9f41e4b8@osgeo.org> References: <051.b260e5b57879f6a4c45ac40e9f41e4b8@osgeo.org> Message-ID: <066.bb2a989d017b3fb545881416f700e884@osgeo.org> #5844: ST_AsMVTGeom producing null results on valid geoms -------------------------+------------------------------- Reporter: pratishta | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS Packaging Component: postgis | Version: 3.2.x Resolution: worksforme | Keywords: -------------------------+------------------------------- Changes (by pramsey): * resolution: => worksforme * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Tue Jun 9 13:06:20 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 20:06:20 -0000 Subject: [PostGIS] #5207: ST_Transform NAD27 --> WGS84 Inconsistencies In-Reply-To: <054.118d7c052670f670b4b22616d16f2748@osgeo.org> References: <054.118d7c052670f670b4b22616d16f2748@osgeo.org> Message-ID: <069.0ec4275c45bf22bfe87d6e2d617c438f@osgeo.org> #5207: ST_Transform NAD27 --> WGS84 Inconsistencies ---------------------------+------------------------------- Reporter: judsoncrouch | Owner: pramsey Type: defect | Status: closed Priority: high | Milestone: PostGIS Packaging Component: postgis | Version: 3.2.x Resolution: worksforme | Keywords: ---------------------------+------------------------------- Changes (by pramsey): * resolution: => worksforme * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 15:51:32 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 15:51:32 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-510-g38faa8d51 Message-ID: <20260609225132.7E5731B7887@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 38faa8d5146b32dbc71a99e64208fd23719999e8 (commit) from bbbe84257be29b0101088e5da69677924f65cdd0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 38faa8d5146b32dbc71a99e64208fd23719999e8 Author: Paul Ramsey Date: Tue Jun 9 22:38:17 2026 +0000 Fix ST_LineFromEncodedPolyline dropping close points Use int32_t accumulators instead of double. Closes #5357 diff --git a/liblwgeom/cunit/cu_in_encoded_polyline.c b/liblwgeom/cunit/cu_in_encoded_polyline.c index f76b726f9..6af16b9a2 100644 --- a/liblwgeom/cunit/cu_in_encoded_polyline.c +++ b/liblwgeom/cunit/cu_in_encoded_polyline.c @@ -53,6 +53,15 @@ static void in_encoded_polyline_test_precision(void) "SRID=4326;LINESTRING(-0.250691 49.283048,-0.250633 49.283376,-0.250502 49.283972,-0.251245 49.284028,-0.251938 49.284232,-0.251938 49.2842)"); } +static void in_encoded_polyline_test_close_points(void) +{ + /* #5357: two close points must not collapse to one */ + do_encoded_polyline_test( + "__nphBgcoeiA?@", + 6, + "SRID=4326;LINESTRING(38.903876 55.336448,38.903875 55.336448)"); +} + /* ** Used by test harness to register the tests in this file. */ @@ -62,4 +71,5 @@ void in_encoded_polyline_suite_setup(void) CU_pSuite suite = CU_add_suite("encoded_polyline_input", NULL, NULL); PG_ADD_TEST(suite, in_encoded_polyline_test_geoms); PG_ADD_TEST(suite, in_encoded_polyline_test_precision); + PG_ADD_TEST(suite, in_encoded_polyline_test_close_points); } diff --git a/liblwgeom/lwin_encoded_polyline.c b/liblwgeom/lwin_encoded_polyline.c index 7212314a6..2bb9f7341 100644 --- a/liblwgeom/lwin_encoded_polyline.c +++ b/liblwgeom/lwin_encoded_polyline.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "liblwgeom.h" #include "../postgis_config.h" @@ -39,8 +40,8 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) int idx = 0; double scale = pow(10,precision); - float latitude = 0.0f; - float longitude = 0.0f; + int32_t latitude = 0; + int32_t longitude = 0; pa = ptarray_construct_empty(LW_FALSE, LW_FALSE, 1); @@ -55,7 +56,7 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) res |= (byte & 0x1F) << shift; shift += 5; } while (byte >= 0x20); - float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1)); + int32_t deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1)); latitude += deltaLat; shift = 0; @@ -65,7 +66,7 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) res |= (byte & 0x1F) << shift; shift += 5; } while (byte >= 0x20); - float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1)); + int32_t deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1)); longitude += deltaLon; pt.x = longitude/scale; diff --git a/regress/core/tickets.sql b/regress/core/tickets.sql index 1dd8f2e98..7da7f4c1f 100644 --- a/regress/core/tickets.sql +++ b/regress/core/tickets.sql @@ -1641,3 +1641,6 @@ INSERT INTO fault6028 (fid, geom) SELECT * FROM fault6028; DROP TABLE IF EXISTS fault6028; +-- #5357 +SELECT '#5357', ST_AsText(ST_LineFromEncodedPolyline('__nphBgcoeiA?@', 6), 6); + diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected index c6185f24e..dcdffa995 100644 --- a/regress/core/tickets_expected +++ b/regress/core/tickets_expected @@ -498,3 +498,4 @@ public|test5978|shape|2|4326|POINT #5938|1FF00F212|t #5938|1FF00F212|t 1|01030000209713000000000000 +#5357|LINESTRING(38.903876 55.336448,38.903875 55.336448) ----------------------------------------------------------------------- Summary of changes: liblwgeom/cunit/cu_in_encoded_polyline.c | 10 ++++++++++ liblwgeom/lwin_encoded_polyline.c | 9 +++++---- regress/core/tickets.sql | 3 +++ regress/core/tickets_expected | 1 + 4 files changed, 19 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 15:51:41 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 22:51:41 -0000 Subject: [PostGIS] #5357: Invalid conversion of 2-points line in ST_LineFromEncodedPolyline In-Reply-To: <051.69879864d0c6ae2c8d6efe6d103d1dbf@osgeo.org> References: <051.69879864d0c6ae2c8d6efe6d103d1dbf@osgeo.org> Message-ID: <066.0f127ba4487c1a85d4c60f4452c11767@osgeo.org> #5357: Invalid conversion of 2-points line in ST_LineFromEncodedPolyline ------------------------+---------------------------------------- Reporter: perikrone | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS PostgreSQL Component: postgis | Version: 3.2.x Resolution: fixed | Keywords: ST_LineFromEncodedPolyline ------------------------+---------------------------------------- Changes (by Paul Ramsey ): * resolution: => fixed * status: new => closed Comment: In [changeset:"38faa8d5146b32dbc71a99e64208fd23719999e8/git" 38faa8d5/git]: {{{#!CommitTicketReference repository="git" revision="38faa8d5146b32dbc71a99e64208fd23719999e8" Fix ST_LineFromEncodedPolyline dropping close points Use int32_t accumulators instead of double. Closes #5357 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 15:51:48 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 15:51:48 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.6 updated. 3.6.4-5-g5027c2502 Message-ID: <20260609225148.3199D1B725B@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.6 has been updated via 5027c25025a6927058f12d3de2e7bdf04fc10149 (commit) via ebece270c829f552e5eb5a12f972171c51df667b (commit) from 923c0638576b8916829233557224fe77a1a1e570 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5027c25025a6927058f12d3de2e7bdf04fc10149 Author: Paul Ramsey Date: Tue Jun 9 15:50:42 2026 -0700 News entry for #5357 diff --git a/NEWS b/NEWS index 51a185b62..3e8a53cf0 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ PostGIS 3.6.5 * Fixes * - #5989, CurvePolygon distance corner case (Paul Ramsey) +- #5357, ST_LineFromEncodedPolyline dropping close points (Paul Ramsey) PostGIS 3.6.4 commit ebece270c829f552e5eb5a12f972171c51df667b Author: Paul Ramsey Date: Tue Jun 9 22:38:17 2026 +0000 Fix ST_LineFromEncodedPolyline dropping close points Use int32_t accumulators instead of double. Closes #5357 diff --git a/liblwgeom/cunit/cu_in_encoded_polyline.c b/liblwgeom/cunit/cu_in_encoded_polyline.c index f76b726f9..6af16b9a2 100644 --- a/liblwgeom/cunit/cu_in_encoded_polyline.c +++ b/liblwgeom/cunit/cu_in_encoded_polyline.c @@ -53,6 +53,15 @@ static void in_encoded_polyline_test_precision(void) "SRID=4326;LINESTRING(-0.250691 49.283048,-0.250633 49.283376,-0.250502 49.283972,-0.251245 49.284028,-0.251938 49.284232,-0.251938 49.2842)"); } +static void in_encoded_polyline_test_close_points(void) +{ + /* #5357: two close points must not collapse to one */ + do_encoded_polyline_test( + "__nphBgcoeiA?@", + 6, + "SRID=4326;LINESTRING(38.903876 55.336448,38.903875 55.336448)"); +} + /* ** Used by test harness to register the tests in this file. */ @@ -62,4 +71,5 @@ void in_encoded_polyline_suite_setup(void) CU_pSuite suite = CU_add_suite("encoded_polyline_input", NULL, NULL); PG_ADD_TEST(suite, in_encoded_polyline_test_geoms); PG_ADD_TEST(suite, in_encoded_polyline_test_precision); + PG_ADD_TEST(suite, in_encoded_polyline_test_close_points); } diff --git a/liblwgeom/lwin_encoded_polyline.c b/liblwgeom/lwin_encoded_polyline.c index 7212314a6..2bb9f7341 100644 --- a/liblwgeom/lwin_encoded_polyline.c +++ b/liblwgeom/lwin_encoded_polyline.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "liblwgeom.h" #include "../postgis_config.h" @@ -39,8 +40,8 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) int idx = 0; double scale = pow(10,precision); - float latitude = 0.0f; - float longitude = 0.0f; + int32_t latitude = 0; + int32_t longitude = 0; pa = ptarray_construct_empty(LW_FALSE, LW_FALSE, 1); @@ -55,7 +56,7 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) res |= (byte & 0x1F) << shift; shift += 5; } while (byte >= 0x20); - float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1)); + int32_t deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1)); latitude += deltaLat; shift = 0; @@ -65,7 +66,7 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) res |= (byte & 0x1F) << shift; shift += 5; } while (byte >= 0x20); - float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1)); + int32_t deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1)); longitude += deltaLon; pt.x = longitude/scale; diff --git a/regress/core/tickets.sql b/regress/core/tickets.sql index 81eae6fae..b7c5cedff 100644 --- a/regress/core/tickets.sql +++ b/regress/core/tickets.sql @@ -1598,3 +1598,7 @@ SELECT f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, t FROM geometry_columns WHERE f_table_name IN ('test5829', 'test5978') ORDER BY f_table_name, f_geometry_column; DROP TABLE IF EXISTS test5829, test5978; + + +-- #5357 +SELECT '#5357', ST_AsText(ST_LineFromEncodedPolyline('__nphBgcoeiA?@', 6), 6); diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected index 37218c8f9..e100e2806 100644 --- a/regress/core/tickets_expected +++ b/regress/core/tickets_expected @@ -489,3 +489,4 @@ public.test5978.geometry SRID:4326 TYPE:POINT DIMS:2 public|test5829|geom|2|4326|GEOMETRY public|test5978|geometry|2|4326|POINT public|test5978|shape|2|4326|POINT +#5357|LINESTRING(38.903876 55.336448,38.903875 55.336448) ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/cunit/cu_in_encoded_polyline.c | 10 ++++++++++ liblwgeom/lwin_encoded_polyline.c | 9 +++++---- regress/core/tickets.sql | 4 ++++ regress/core/tickets_expected | 1 + 5 files changed, 21 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 15:51:49 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 22:51:49 -0000 Subject: [PostGIS] #5357: Invalid conversion of 2-points line in ST_LineFromEncodedPolyline In-Reply-To: <051.69879864d0c6ae2c8d6efe6d103d1dbf@osgeo.org> References: <051.69879864d0c6ae2c8d6efe6d103d1dbf@osgeo.org> Message-ID: <066.6b0c4a7e44b5e59735477ccc92cfddcf@osgeo.org> #5357: Invalid conversion of 2-points line in ST_LineFromEncodedPolyline ------------------------+---------------------------------------- Reporter: perikrone | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS PostgreSQL Component: postgis | Version: 3.2.x Resolution: fixed | Keywords: ST_LineFromEncodedPolyline ------------------------+---------------------------------------- Comment (by Paul Ramsey ): In [changeset:"ebece270c829f552e5eb5a12f972171c51df667b/git" ebece27/git]: {{{#!CommitTicketReference repository="git" revision="ebece270c829f552e5eb5a12f972171c51df667b" Fix ST_LineFromEncodedPolyline dropping close points Use int32_t accumulators instead of double. Closes #5357 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 15:51:50 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 15:51:50 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.5 updated. 3.5.6-12-g8150016e7 Message-ID: <20260609225150.9862D1B77DD@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.5 has been updated via 8150016e768bae6b9279cadf47ec9417c242a696 (commit) via 76e0415357a6e516b0a76068faa22ca65376b883 (commit) from 92d22c181b758165927f8c8d2351411e33389802 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 8150016e768bae6b9279cadf47ec9417c242a696 Author: Paul Ramsey Date: Tue Jun 9 15:50:44 2026 -0700 News entry for #5357 diff --git a/NEWS b/NEWS index 24688176b..2ea9ba65d 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ PostGIS 3.5.7 - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) - #5916, ST_Split hang with very large ordinates (Paul Ramsey) - #5989, CurvePolygon distance corner case (Paul Ramsey) + - #5357, ST_LineFromEncodedPolyline dropping close points (Paul Ramsey) PostGIS 3.5.6 commit 76e0415357a6e516b0a76068faa22ca65376b883 Author: Paul Ramsey Date: Tue Jun 9 22:38:17 2026 +0000 Fix ST_LineFromEncodedPolyline dropping close points Use int32_t accumulators instead of double. Closes #5357 diff --git a/liblwgeom/cunit/cu_in_encoded_polyline.c b/liblwgeom/cunit/cu_in_encoded_polyline.c index f76b726f9..6af16b9a2 100644 --- a/liblwgeom/cunit/cu_in_encoded_polyline.c +++ b/liblwgeom/cunit/cu_in_encoded_polyline.c @@ -53,6 +53,15 @@ static void in_encoded_polyline_test_precision(void) "SRID=4326;LINESTRING(-0.250691 49.283048,-0.250633 49.283376,-0.250502 49.283972,-0.251245 49.284028,-0.251938 49.284232,-0.251938 49.2842)"); } +static void in_encoded_polyline_test_close_points(void) +{ + /* #5357: two close points must not collapse to one */ + do_encoded_polyline_test( + "__nphBgcoeiA?@", + 6, + "SRID=4326;LINESTRING(38.903876 55.336448,38.903875 55.336448)"); +} + /* ** Used by test harness to register the tests in this file. */ @@ -62,4 +71,5 @@ void in_encoded_polyline_suite_setup(void) CU_pSuite suite = CU_add_suite("encoded_polyline_input", NULL, NULL); PG_ADD_TEST(suite, in_encoded_polyline_test_geoms); PG_ADD_TEST(suite, in_encoded_polyline_test_precision); + PG_ADD_TEST(suite, in_encoded_polyline_test_close_points); } diff --git a/liblwgeom/lwin_encoded_polyline.c b/liblwgeom/lwin_encoded_polyline.c index 7212314a6..2bb9f7341 100644 --- a/liblwgeom/lwin_encoded_polyline.c +++ b/liblwgeom/lwin_encoded_polyline.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "liblwgeom.h" #include "../postgis_config.h" @@ -39,8 +40,8 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) int idx = 0; double scale = pow(10,precision); - float latitude = 0.0f; - float longitude = 0.0f; + int32_t latitude = 0; + int32_t longitude = 0; pa = ptarray_construct_empty(LW_FALSE, LW_FALSE, 1); @@ -55,7 +56,7 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) res |= (byte & 0x1F) << shift; shift += 5; } while (byte >= 0x20); - float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1)); + int32_t deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1)); latitude += deltaLat; shift = 0; @@ -65,7 +66,7 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) res |= (byte & 0x1F) << shift; shift += 5; } while (byte >= 0x20); - float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1)); + int32_t deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1)); longitude += deltaLon; pt.x = longitude/scale; diff --git a/regress/core/tickets.sql b/regress/core/tickets.sql index db5741fee..9c1825928 100644 --- a/regress/core/tickets.sql +++ b/regress/core/tickets.sql @@ -1588,3 +1588,7 @@ SELECT f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, t FROM geometry_columns WHERE f_table_name IN ('test5829', 'test5978') ORDER BY f_table_name, f_geometry_column; DROP TABLE IF EXISTS test5829, test5978; + + +-- #5357 +SELECT '#5357', ST_AsText(ST_LineFromEncodedPolyline('__nphBgcoeiA?@', 6), 6); diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected index bfebd9a86..be0841b9a 100644 --- a/regress/core/tickets_expected +++ b/regress/core/tickets_expected @@ -488,3 +488,4 @@ public.test5978.geometry SRID:4326 TYPE:POINT DIMS:2 public|test5829|geom|2|4326|GEOMETRY public|test5978|geometry|2|4326|POINT public|test5978|shape|2|4326|POINT +#5357|LINESTRING(38.903876 55.336448,38.903875 55.336448) ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/cunit/cu_in_encoded_polyline.c | 10 ++++++++++ liblwgeom/lwin_encoded_polyline.c | 9 +++++---- regress/core/tickets.sql | 4 ++++ regress/core/tickets_expected | 1 + 5 files changed, 21 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 15:51:52 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 22:51:52 -0000 Subject: [PostGIS] #5357: Invalid conversion of 2-points line in ST_LineFromEncodedPolyline In-Reply-To: <051.69879864d0c6ae2c8d6efe6d103d1dbf@osgeo.org> References: <051.69879864d0c6ae2c8d6efe6d103d1dbf@osgeo.org> Message-ID: <066.6ca401b114aec15d5292a75454992534@osgeo.org> #5357: Invalid conversion of 2-points line in ST_LineFromEncodedPolyline ------------------------+---------------------------------------- Reporter: perikrone | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS PostgreSQL Component: postgis | Version: 3.2.x Resolution: fixed | Keywords: ST_LineFromEncodedPolyline ------------------------+---------------------------------------- Comment (by Paul Ramsey ): In [changeset:"76e0415357a6e516b0a76068faa22ca65376b883/git" 76e0415/git]: {{{#!CommitTicketReference repository="git" revision="76e0415357a6e516b0a76068faa22ca65376b883" Fix ST_LineFromEncodedPolyline dropping close points Use int32_t accumulators instead of double. Closes #5357 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 15:51:54 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 15:51:54 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.4 updated. 3.4.6-12-g74a2d3936 Message-ID: <20260609225154.672811B77DE@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.4 has been updated via 74a2d3936b89d4d9afa87d054203446239b2c3de (commit) via 8016c749937a20b097bc720389dbc0e062505bd6 (commit) from 972920d9eff7c95fbfa403b077721ccd0f1859e8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 74a2d3936b89d4d9afa87d054203446239b2c3de Author: Paul Ramsey Date: Tue Jun 9 15:50:45 2026 -0700 News entry for #5357 diff --git a/NEWS b/NEWS index 6bc77122d..5f9ced28d 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ PostGIS 3.4.7 - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) - #5916, ST_Split hang with very large ordinates (Paul Ramsey) - #5989, CurvePolygon distance corner case (Paul Ramsey) + - #5357, ST_LineFromEncodedPolyline dropping close points (Paul Ramsey) PostGIS 3.4.6 commit 8016c749937a20b097bc720389dbc0e062505bd6 Author: Paul Ramsey Date: Tue Jun 9 22:38:17 2026 +0000 Fix ST_LineFromEncodedPolyline dropping close points Use int32_t accumulators instead of double. Closes #5357 diff --git a/liblwgeom/cunit/cu_in_encoded_polyline.c b/liblwgeom/cunit/cu_in_encoded_polyline.c index 597493c81..d3d44b408 100644 --- a/liblwgeom/cunit/cu_in_encoded_polyline.c +++ b/liblwgeom/cunit/cu_in_encoded_polyline.c @@ -53,6 +53,15 @@ static void in_encoded_polyline_test_precision(void) "SRID=4326;LINESTRING(-0.250691 49.283048,-0.250633 49.283376,-0.250502 49.283972,-0.251245 49.284028,-0.251938 49.284232,-0.251938 49.2842)"); } +static void in_encoded_polyline_test_close_points(void) +{ + /* #5357: two close points must not collapse to one */ + do_encoded_polyline_test( + "__nphBgcoeiA?@", + 6, + "SRID=4326;LINESTRING(38.903876 55.336448,38.903875 55.336448)"); +} + /* ** Used by test harness to register the tests in this file. */ @@ -62,4 +71,5 @@ void in_encoded_polyline_suite_setup(void) CU_pSuite suite = CU_add_suite("encoded_polyline_input", NULL, NULL); PG_ADD_TEST(suite, in_encoded_polyline_test_geoms); PG_ADD_TEST(suite, in_encoded_polyline_test_precision); + PG_ADD_TEST(suite, in_encoded_polyline_test_close_points); } diff --git a/liblwgeom/lwin_encoded_polyline.c b/liblwgeom/lwin_encoded_polyline.c index 7212314a6..2bb9f7341 100644 --- a/liblwgeom/lwin_encoded_polyline.c +++ b/liblwgeom/lwin_encoded_polyline.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "liblwgeom.h" #include "../postgis_config.h" @@ -39,8 +40,8 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) int idx = 0; double scale = pow(10,precision); - float latitude = 0.0f; - float longitude = 0.0f; + int32_t latitude = 0; + int32_t longitude = 0; pa = ptarray_construct_empty(LW_FALSE, LW_FALSE, 1); @@ -55,7 +56,7 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) res |= (byte & 0x1F) << shift; shift += 5; } while (byte >= 0x20); - float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1)); + int32_t deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1)); latitude += deltaLat; shift = 0; @@ -65,7 +66,7 @@ lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision) res |= (byte & 0x1F) << shift; shift += 5; } while (byte >= 0x20); - float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1)); + int32_t deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1)); longitude += deltaLon; pt.x = longitude/scale; diff --git a/regress/core/tickets.sql b/regress/core/tickets.sql index 4bbf7ddb1..cf0ea56d0 100644 --- a/regress/core/tickets.sql +++ b/regress/core/tickets.sql @@ -1577,3 +1577,7 @@ SELECT f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, t FROM geometry_columns WHERE f_table_name IN ('test5829', 'test5978') ORDER BY f_table_name, f_geometry_column; DROP TABLE IF EXISTS test5829, test5978; + + +-- #5357 +SELECT '#5357', ST_AsText(ST_LineFromEncodedPolyline('__nphBgcoeiA?@', 6), 6); diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected index 2effcd0fd..239364576 100644 --- a/regress/core/tickets_expected +++ b/regress/core/tickets_expected @@ -479,3 +479,4 @@ public.test5978.geometry SRID:4326 TYPE:POINT DIMS:2 public|test5829|geom|2|4326|GEOMETRY public|test5978|geometry|2|4326|POINT public|test5978|shape|2|4326|POINT +#5357|LINESTRING(38.903876 55.336448,38.903875 55.336448) ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + liblwgeom/cunit/cu_in_encoded_polyline.c | 10 ++++++++++ liblwgeom/lwin_encoded_polyline.c | 9 +++++---- regress/core/tickets.sql | 4 ++++ regress/core/tickets_expected | 1 + 5 files changed, 21 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 9 15:51:55 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 22:51:55 -0000 Subject: [PostGIS] #5357: Invalid conversion of 2-points line in ST_LineFromEncodedPolyline In-Reply-To: <051.69879864d0c6ae2c8d6efe6d103d1dbf@osgeo.org> References: <051.69879864d0c6ae2c8d6efe6d103d1dbf@osgeo.org> Message-ID: <066.18f9896a0507eefefbf244a78edab9d4@osgeo.org> #5357: Invalid conversion of 2-points line in ST_LineFromEncodedPolyline ------------------------+---------------------------------------- Reporter: perikrone | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS PostgreSQL Component: postgis | Version: 3.2.x Resolution: fixed | Keywords: ST_LineFromEncodedPolyline ------------------------+---------------------------------------- Comment (by Paul Ramsey ): In [changeset:"8016c749937a20b097bc720389dbc0e062505bd6/git" 8016c74/git]: {{{#!CommitTicketReference repository="git" revision="8016c749937a20b097bc720389dbc0e062505bd6" Fix ST_LineFromEncodedPolyline dropping close points Use int32_t accumulators instead of double. Closes #5357 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Tue Jun 9 16:15:22 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 09 Jun 2026 23:15:22 -0000 Subject: [PostGIS] #5807: Joined table ST_Transform runs on each filter evaluation instead of just once per input row In-Reply-To: <049.300f7bf1efc2f0e07722ac43db44baba@osgeo.org> References: <049.300f7bf1efc2f0e07722ac43db44baba@osgeo.org> Message-ID: <064.a0deb852fc3d261577205b7f4f59c93a@osgeo.org> #5807: Joined table ST_Transform runs on each filter evaluation instead of just once per input row ----------------------+-------------------------------- Reporter: lnicola | Owner: pramsey Type: defect | Status: new Priority: medium | Milestone: PostGIS PostgreSQL Component: postgis | Version: 3.5.x Resolution: | Keywords: ----------------------+-------------------------------- Changes (by pramsey): * milestone: PostGIS 3.5.7 => PostGIS PostgreSQL Comment: This is a planner / executor issue and not something we can fix ourselves. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Tue Jun 9 22:13:36 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 05:13:36 -0000 Subject: [PostGIS] #6080: Error casting int -> uint8_t Message-ID: <050.ca96fba3af513625ac4b9117964eefa1@osgeo.org> #6080: Error casting int -> uint8_t ----------------------+--------------------------- Reporter: ezimanyi | Owner: pramsey Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.6.5 Component: postgis | Version: 3.6.x Keywords: | ----------------------+--------------------------- In MobililityDB we have found a bug that appears on some platforms https://github.com/MobilityDB/MobilityDB/pull/1195#pullrequestreview-4449261865 Since we have vendored part of the PostGIS code in MEOS it would be useful also to fix it in PostGIS https://github.com/postgis/postgis/blob/master/liblwgeom/lwin_wkb.c#L108-L109 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 9 23:33:24 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 23:33:24 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-520-g91dd9dbfd Message-ID: <20260610063324.E88A316C88D@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 91dd9dbfd60c93b510160076a5b520dc6fc3854f (commit) via b1e736c207d8068ffd6d0d476faaebc159a56ffb (commit) via d83390ba48c0df2a58b13ae1894eeb6d9b72a047 (commit) via ce1596f8f05cf524601e574f03ed8d4d73fe0a2d (commit) via 9b21502078522e9b5973120db2664731ac91b9cf (commit) via 55e186147d5add56e8203fbaff273e83f2003e35 (commit) via afbe34be9ea5379debd594442ab53bda0f013c45 (commit) via 10ab504c6dd5036c1ff65db83e1e8e76ed713ada (commit) via a63959a97b85bb029b8ab12712a14db8c4689653 (commit) via ea9aa716c07a95b1ebd586cdf7e8ca6c506b3acf (commit) from 38faa8d5146b32dbc71a99e64208fd23719999e8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 91dd9dbfd60c93b510160076a5b520dc6fc3854f Author: Lo?c Bartoletti Date: Mon Jun 8 12:52:27 2026 +0200 feat(sfcgal): add CG_ApproximateMedialAxis(geometry, boolean) overload diff --git a/sfcgal/lwgeom_sfcgal.c b/sfcgal/lwgeom_sfcgal.c index 4ecaf0c9b..5ee90f878 100644 --- a/sfcgal/lwgeom_sfcgal.c +++ b/sfcgal/lwgeom_sfcgal.c @@ -450,16 +450,33 @@ sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS) GSERIALIZED *input, *output; sfcgal_geometry_t *geom; sfcgal_geometry_t *result; + bool projected = false; srid_t srid; sfcgal_postgis_init(); input = PG_GETARG_GSERIALIZED_P(0); srid = gserialized_get_srid(input); + + if (PG_NARGS() > 1 && !PG_ARGISNULL(1)) + projected = PG_GETARG_BOOL(1); + geom = POSTGIS2SFCGALGeometry(input); PG_FREE_IF_COPY(input, 0); +#if POSTGIS_SFCGAL_VERSION >= 20300 + if (projected) + result = sfcgal_geometry_projected_medial_axis(geom); + else + result = sfcgal_geometry_approximate_medial_axis(geom); +#else + if (projected) + lwpgnotice( + "CG_ApproximateMedialAxis with projected=true requires SFCGAL 2.3.0+, " + "falling back to non-projected result."); result = sfcgal_geometry_approximate_medial_axis(geom); +#endif + sfcgal_geometry_delete(geom); output = SFCGALGeometry2POSTGIS(result, 0, srid); diff --git a/sfcgal/sfcgal.sql.in b/sfcgal/sfcgal.sql.in index a8e9809a4..f0ca979f0 100644 --- a/sfcgal/sfcgal.sql.in +++ b/sfcgal/sfcgal.sql.in @@ -309,6 +309,14 @@ CREATE OR REPLACE FUNCTION CG_ApproximateMedialAxis(geometry) IMMUTABLE STRICT PARALLEL SAFE COST 100; +-- Availability: 3.7.0 - requires SFCGAL >= 2.3.0 when projected is true +CREATE OR REPLACE FUNCTION CG_ApproximateMedialAxis(geom geometry, projected boolean) + RETURNS geometry + AS 'MODULE_PATHNAME','sfcgal_approximate_medial_axis' + LANGUAGE 'c' + IMMUTABLE STRICT PARALLEL SAFE + COST 100; + -- Availability: 2.2.0 -- Deprecation in 3.5.0 CREATE OR REPLACE FUNCTION ST_ApproximateMedialAxis(geometry) commit b1e736c207d8068ffd6d0d476faaebc159a56ffb Author: Lo?c Bartoletti Date: Mon Jun 8 12:52:30 2026 +0200 test(sfcgal): add tests for CG_ApproximateMedialAxis projected overload diff --git a/sfcgal/regress/approximatemedialaxis.sql b/sfcgal/regress/approximatemedialaxis.sql index 1b5c10519..dcc78b9a5 100644 --- a/sfcgal/regress/approximatemedialaxis.sql +++ b/sfcgal/regress/approximatemedialaxis.sql @@ -1,2 +1,5 @@ SELECT 'square', ST_AsEwkt(CG_ApproximateMedialAxis('SRID=3857;POLYGON((0 0,1 0,1 1,0 1,0 0))')); -SELECT 'rect1', ST_AsEwkt(CG_ApproximateMedialAxis('SRID=4326;POLYGON((0 0,2 0,2 1,0 1,0 0))')); +SELECT 'rect', ST_AsEwkt(CG_ApproximateMedialAxis('SRID=3857;POLYGON((0 0,2 0,2 1,0 1,0 0))')); +-- projected=false must equal 1-arg overload +SELECT 'square_proj_false', ST_AsEwkt(CG_ApproximateMedialAxis('SRID=3857;POLYGON((0 0,1 0,1 1,0 1,0 0))', false)); +SELECT 'rect_proj_false', ST_AsEwkt(CG_ApproximateMedialAxis('SRID=3857;POLYGON((0 0,2 0,2 1,0 1,0 0))', false)); diff --git a/sfcgal/regress/approximatemedialaxis_expected b/sfcgal/regress/approximatemedialaxis_expected index 2677ed75b..7f5a721f6 100644 --- a/sfcgal/regress/approximatemedialaxis_expected +++ b/sfcgal/regress/approximatemedialaxis_expected @@ -1,2 +1,4 @@ square|SRID=3857;MULTILINESTRING EMPTY -rect1|SRID=4326;MULTILINESTRING((0.5 0.5,1.5 0.5)) +rect|SRID=3857;MULTILINESTRING((0.5 0.5,1.5 0.5)) +square_proj_false|SRID=3857;MULTILINESTRING EMPTY +rect_proj_false|SRID=3857;MULTILINESTRING((0.5 0.5,1.5 0.5)) diff --git a/sfcgal/regress/approximatemedialaxis_projected.sql b/sfcgal/regress/approximatemedialaxis_projected.sql new file mode 100644 index 000000000..42ac7ec19 --- /dev/null +++ b/sfcgal/regress/approximatemedialaxis_projected.sql @@ -0,0 +1,3 @@ +-- projected=true extends free endpoints to polygon boundary (requires SFCGAL >= 2.3.0) +SELECT 'square_proj_true', ST_AsEwkt(CG_ApproximateMedialAxis('SRID=3857;POLYGON((0 0,1 0,1 1,0 1,0 0))', true)); +SELECT 'rect_proj_true', ST_AsEwkt(CG_ApproximateMedialAxis('SRID=3857;POLYGON((0 0,2 0,2 1,0 1,0 0))', true)); diff --git a/sfcgal/regress/approximatemedialaxis_projected_expected b/sfcgal/regress/approximatemedialaxis_projected_expected new file mode 100644 index 000000000..302aab162 --- /dev/null +++ b/sfcgal/regress/approximatemedialaxis_projected_expected @@ -0,0 +1,2 @@ +square_proj_true|SRID=3857;MULTILINESTRING EMPTY +rect_proj_true|SRID=3857;MULTILINESTRING((0 0.5,0.5 0.5,1.5 0.5,2 0.5)) diff --git a/sfcgal/regress/approximatemedialaxis_projected_pre230.sql b/sfcgal/regress/approximatemedialaxis_projected_pre230.sql new file mode 100644 index 000000000..f70b45f62 --- /dev/null +++ b/sfcgal/regress/approximatemedialaxis_projected_pre230.sql @@ -0,0 +1,3 @@ +-- projected=true falls back to non-projected result with a notice on SFCGAL < 2.3.0 +SELECT 'square_proj_true', ST_AsEwkt(CG_ApproximateMedialAxis('SRID=3857;POLYGON((0 0,1 0,1 1,0 1,0 0))', true)); +SELECT 'rect_proj_true', ST_AsEwkt(CG_ApproximateMedialAxis('SRID=3857;POLYGON((0 0,2 0,2 1,0 1,0 0))', true)); diff --git a/sfcgal/regress/approximatemedialaxis_projected_pre230_expected b/sfcgal/regress/approximatemedialaxis_projected_pre230_expected new file mode 100644 index 000000000..39a0a299d --- /dev/null +++ b/sfcgal/regress/approximatemedialaxis_projected_pre230_expected @@ -0,0 +1,4 @@ +NOTICE: CG_ApproximateMedialAxis with projected=true requires SFCGAL 2.3.0+, falling back to non-projected result. +square_proj_true|SRID=3857;MULTILINESTRING EMPTY +NOTICE: CG_ApproximateMedialAxis with projected=true requires SFCGAL 2.3.0+, falling back to non-projected result. +rect_proj_true|SRID=3857;MULTILINESTRING((0.5 0.5,1.5 0.5)) diff --git a/sfcgal/regress/tests.mk.in b/sfcgal/regress/tests.mk.in index 053a1953a..19a6b037b 100644 --- a/sfcgal/regress/tests.mk.in +++ b/sfcgal/regress/tests.mk.in @@ -49,10 +49,14 @@ ifeq ($(shell expr "$(POSTGIS_SFCGAL_VERSION)" ">=" 20300),1) TESTS += \ $(top_srcdir)/sfcgal/regress/alphashape_components.sql \ $(top_srcdir)/sfcgal/regress/roofgeneration.sql \ - $(top_srcdir)/sfcgal/regress/polygonrepair.sql + $(top_srcdir)/sfcgal/regress/polygonrepair.sql \ + $(top_srcdir)/sfcgal/regress/approximatemedialaxis_projected.sql ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 601),1) TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union.sql else TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union_pre61.sql endif +else + TESTS += \ + $(top_srcdir)/sfcgal/regress/approximatemedialaxis_projected_pre230.sql endif commit d83390ba48c0df2a58b13ae1894eeb6d9b72a047 Author: Lo?c Bartoletti Date: Mon Jun 8 12:52:34 2026 +0200 docs(sfcgal): document CG_ApproximateMedialAxis projected parameter diff --git a/doc/reference_sfcgal.xml b/doc/reference_sfcgal.xml index 0ebf6a4d3..2bcaa35a3 100644 --- a/doc/reference_sfcgal.xml +++ b/doc/reference_sfcgal.xml @@ -1755,6 +1755,11 @@ ST_GeomFromText('POLYHEDRALSURFACE Z( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)), geometry CG_ApproximateMedialAxis geometry geom + + geometry CG_ApproximateMedialAxis + geometry geom + boolean projected + @@ -1767,8 +1772,16 @@ ST_GeomFromText('POLYHEDRALSURFACE Z( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)), a capable version (1.2.0+). Otherwise the function is just a wrapper around CG_StraightSkeleton (slower case). + + When projected is true, free + endpoints of the medial axis are extended to reach the polygon boundary + (projected medial axis). Requires SFCGAL 2.3.0+. When built against + an older SFCGAL version, a notice is emitted and the non-projected + result is returned instead. + Availability: 3.5.0 + Availability: 3.7.0 - projected parameter. Requires SFCGAL >= 2.3.0 for projected result; falls back to non-projected with a notice on older versions. This function ignores the Z dimension. It always gives a 2D result even when used on a 3D geometry. &sfcgal_required; @@ -1796,6 +1809,10 @@ It always gives a 2D result even when used on a 3D geometry. + + -- Projected medial axis: free endpoints extended to polygon boundary +SELECT CG_ApproximateMedialAxis('POLYGON((0 0,2 0,2 1,0 1,0 0))', true); +-- Result: MULTILINESTRING((0 0.5,2 0.5)) commit ce1596f8f05cf524601e574f03ed8d4d73fe0a2d Author: Lo?c Bartoletti Date: Mon Jun 8 13:51:40 2026 +0200 docs(sfcgal): document CG_PolygonRepair diff --git a/doc/reference_sfcgal.xml b/doc/reference_sfcgal.xml index a33f797cf..0ebf6a4d3 100644 --- a/doc/reference_sfcgal.xml +++ b/doc/reference_sfcgal.xml @@ -2169,6 +2169,64 @@ SELECT ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'FLAT', 2.0)) + + + CG_PolygonRepair + Repair an invalid polygon or multipolygon. + + + + + + geometry CG_PolygonRepair + geometry geom + text rule + + + + + + Description + + Repair an invalid polygon or multipolygon using CGAL's 2D Polygon + Repair algorithm. Returns a MultiPolygon. + + + The rule parameter controls the repair strategy: + + + EVEN_ODD (default) ? areas covered an odd + number of times are kept. Available with CGAL 6.0+. + NON_ZERO ? areas with non-zero winding + number are kept. Requires CGAL 6.1+. + UNION ? union of all input polygons. + Requires CGAL 6.1+. + INTERSECTION ? intersection of all input + polygons. Requires CGAL 6.1+. + + Availability: 3.7.0 - requires SFCGAL >= 2.3.0 and CGAL >= 6.0. + &sfcgal_required; + &P_support; + + + + Examples + -- Repair a bowtie (self-intersecting) polygon +SELECT ST_AsText(CG_PolygonRepair('POLYGON((0 0,2 2,2 0,0 2,0 0))')); +-- MULTIPOLYGON(((0 0,1 1,0 2,0 0)),((1 1,2 0,2 2,1 1))) + +-- Keep all winding area with UNION rule (requires CGAL 6.1 or later) +SELECT ST_AsText(CG_PolygonRepair('POLYGON((0 0,2 2,2 0,0 2,0 0))', 'UNION')); +-- MULTIPOLYGON(((0 0,1 1,0 2,0 0))) + + + + See Also + , + + + + ST_ConstrainedDelaunayTriangles commit 9b21502078522e9b5973120db2664731ac91b9cf Author: Lo?c Bartoletti Date: Mon Jun 8 13:51:36 2026 +0200 test(sfcgal): add tests for CG_PolygonRepair diff --git a/sfcgal/regress/polygonrepair.sql b/sfcgal/regress/polygonrepair.sql new file mode 100644 index 000000000..b1379625a --- /dev/null +++ b/sfcgal/regress/polygonrepair.sql @@ -0,0 +1,8 @@ +-- Empty polygon +SELECT 'empty', ST_AsText(CG_PolygonRepair('POLYGON EMPTY')); +-- bowtie polygon (self-intersecting): split into two triangles by EVEN_ODD +SELECT 'bowtie_even_odd', ST_AsText(CG_PolygonRepair('POLYGON((0 0,2 2,2 0,0 2,0 0))')); +-- explicit rule +SELECT 'bowtie_even_odd_explicit', ST_AsText(CG_PolygonRepair('POLYGON((0 0,2 2,2 0,0 2,0 0))', 'EVEN_ODD')); +-- valid polygon is returned unchanged +SELECT 'valid', ST_AsText(CG_PolygonRepair('POLYGON((0 0,1 0,1 1,0 1,0 0))')); diff --git a/sfcgal/regress/polygonrepair_expected b/sfcgal/regress/polygonrepair_expected new file mode 100644 index 000000000..820476f2a --- /dev/null +++ b/sfcgal/regress/polygonrepair_expected @@ -0,0 +1,4 @@ +empty|MULTIPOLYGON EMPTY +bowtie_even_odd|MULTIPOLYGON(((0 0,1 1,0 2,0 0)),((1 1,2 0,2 2,1 1))) +bowtie_even_odd_explicit|MULTIPOLYGON(((0 0,1 1,0 2,0 0)),((1 1,2 0,2 2,1 1))) +valid|MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0))) diff --git a/sfcgal/regress/polygonrepair_union.sql b/sfcgal/regress/polygonrepair_union.sql new file mode 100644 index 000000000..74bb06eb2 --- /dev/null +++ b/sfcgal/regress/polygonrepair_union.sql @@ -0,0 +1,2 @@ +-- UNION rule: keep all winding area (requires CGAL 6.1+) +SELECT 'bowtie_union', ST_AsText(CG_PolygonRepair('POLYGON((0 0,2 2,2 0,0 2,0 0))', 'UNION')); diff --git a/sfcgal/regress/polygonrepair_union_expected b/sfcgal/regress/polygonrepair_union_expected new file mode 100644 index 000000000..c19353709 --- /dev/null +++ b/sfcgal/regress/polygonrepair_union_expected @@ -0,0 +1 @@ +bowtie_union|MULTIPOLYGON(((0 0,1 1,0 2,0 0))) diff --git a/sfcgal/regress/polygonrepair_union_pre61.sql b/sfcgal/regress/polygonrepair_union_pre61.sql new file mode 100644 index 000000000..74bb06eb2 --- /dev/null +++ b/sfcgal/regress/polygonrepair_union_pre61.sql @@ -0,0 +1,2 @@ +-- UNION rule: keep all winding area (requires CGAL 6.1+) +SELECT 'bowtie_union', ST_AsText(CG_PolygonRepair('POLYGON((0 0,2 2,2 0,0 2,0 0))', 'UNION')); diff --git a/sfcgal/regress/polygonrepair_union_pre61_expected b/sfcgal/regress/polygonrepair_union_pre61_expected new file mode 100644 index 000000000..4345071d2 --- /dev/null +++ b/sfcgal/regress/polygonrepair_union_pre61_expected @@ -0,0 +1 @@ +ERROR: CG_PolygonRepair: 'UNION' rule requires CGAL 6.1 or later diff --git a/sfcgal/regress/tests.mk.in b/sfcgal/regress/tests.mk.in index 54c3c6190..053a1953a 100644 --- a/sfcgal/regress/tests.mk.in +++ b/sfcgal/regress/tests.mk.in @@ -12,6 +12,7 @@ POSTGIS_PGSQL_VERSION=@POSTGIS_PGSQL_VERSION@ POSTGIS_GEOS_VERSION=@POSTGIS_GEOS_VERSION@ POSTGIS_SFCGAL_VERSION=@POSTGIS_SFCGAL_VERSION@ +POSTGIS_CGAL_VERSION=@POSTGIS_CGAL_VERSION@ TESTS += \ $(top_srcdir)/sfcgal/regress/regress_sfcgal \ @@ -47,5 +48,11 @@ endif ifeq ($(shell expr "$(POSTGIS_SFCGAL_VERSION)" ">=" 20300),1) TESTS += \ $(top_srcdir)/sfcgal/regress/alphashape_components.sql \ - $(top_srcdir)/sfcgal/regress/roofgeneration.sql + $(top_srcdir)/sfcgal/regress/roofgeneration.sql \ + $(top_srcdir)/sfcgal/regress/polygonrepair.sql + ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 601),1) + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union.sql + else + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union_pre61.sql + endif endif commit 55e186147d5add56e8203fbaff273e83f2003e35 Author: Lo?c Bartoletti Date: Mon Jun 8 13:51:32 2026 +0200 feat(sfcgal): add CG_PolygonRepair diff --git a/configure.ac b/configure.ac index 4de164b61..6d84d5568 100644 --- a/configure.ac +++ b/configure.ac @@ -964,6 +964,17 @@ if test "x$with_sfcgal" != "xno"; then POSTGIS_SFCGAL_VERSION="$SFCGAL_MAJOR_VERSION$SFCGAL_NUMERIC_MINOR_VERSION$SFCGAL_NUMERIC_PATCH_VERSION" AC_DEFINE_UNQUOTED([POSTGIS_SFCGAL_VERSION], [$POSTGIS_SFCGAL_VERSION], [SFCGAL library version at build time]) + POSTGIS_CGAL_VERSION="0" + _sfcgal_inc=`echo "$SFCGAL_CPPFLAGS" | tr ' ' '\n' | grep '^-I' | head -1 | sed 's/^-I//'` + if test -n "$_sfcgal_inc" && test -f "${_sfcgal_inc}/SFCGAL/version.h"; then + _cgal_major=`grep '#define SFCGAL_CGAL_VERSION_MAJOR' "${_sfcgal_inc}/SFCGAL/version.h" | awk '{print $3}'` + _cgal_minor=`grep '#define SFCGAL_CGAL_VERSION_MINOR' "${_sfcgal_inc}/SFCGAL/version.h" | awk '{print $3}'` + if test -n "$_cgal_major" && test -n "$_cgal_minor"; then + _cgal_minor_pad=`printf "%02d" $_cgal_minor` + POSTGIS_CGAL_VERSION="${_cgal_major}${_cgal_minor_pad}" + fi + fi + SFCGAL_STATIC=`$SFCGAL_CONFIG --static` if test "x$SFCGAL_STATIC" = "xON"; then AC_MSG_WARN([The SFCGAL version found is not installed as a dynamic library.]) @@ -984,6 +995,7 @@ if test "x$with_sfcgal" != "xno"; then fi AC_SUBST([POSTGIS_SFCGAL_VERSION]) +AC_SUBST([POSTGIS_CGAL_VERSION]) AC_SUBST([SFCGAL_VERSION]) AC_SUBST([SFCGAL_CPPFLAGS]) AC_SUBST([SFCGAL_LDFLAGS]) @@ -1929,6 +1941,7 @@ fi if test "x$SFCGAL" = "xsfcgal"; then AC_MSG_RESULT([ SFCGAL config: ${SFCGAL_CONFIG}]) AC_MSG_RESULT([ SFCGAL version: ${SFCGAL_VERSION}]) + AC_MSG_RESULT([ CGAL version: ${POSTGIS_CGAL_VERSION}]) fi if test "x$SUPPORT_POSTGRESQL" = "xyes"; then AC_MSG_RESULT([ PostgreSQL config: ${PG_CONFIG}]) diff --git a/sfcgal/lwgeom_sfcgal.c b/sfcgal/lwgeom_sfcgal.c index bf58c04a7..4ecaf0c9b 100644 --- a/sfcgal/lwgeom_sfcgal.c +++ b/sfcgal/lwgeom_sfcgal.c @@ -91,6 +91,7 @@ Datum sfcgal_generate_hipped_roof(PG_FUNCTION_ARGS); Datum sfcgal_generate_gable_roof(PG_FUNCTION_ARGS); Datum sfcgal_generate_skillion_roof(PG_FUNCTION_ARGS); Datum sfcgal_generate_roof(PG_FUNCTION_ARGS); +Datum sfcgal_polygon_repair(PG_FUNCTION_ARGS); GSERIALIZED *geometry_serialize(LWGEOM *lwgeom); char *text_to_cstring(const text *textptr); @@ -2106,3 +2107,73 @@ sfcgal_generate_roof(PG_FUNCTION_ARGS) PG_RETURN_POINTER(output); #endif } + +PG_FUNCTION_INFO_V1(sfcgal_polygon_repair); +Datum +sfcgal_polygon_repair(PG_FUNCTION_ARGS) +{ +#if POSTGIS_SFCGAL_VERSION < 20300 || \ + !defined(SFCGAL_CGAL_VERSION_MAJOR) || \ + SFCGAL_CGAL_VERSION_MAJOR < 6 + lwpgerror( + "The SFCGAL version this PostGIS binary was compiled against (%d) doesn't support " + "'sfcgal_geometry_polygon_repair' function (requires SFCGAL 2.3.0+ and CGAL 6.0+)", + POSTGIS_SFCGAL_VERSION); + PG_RETURN_NULL(); +#else + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom, *result; + sfcgal_polygon_repair_rule_t rule = SFCGAL_POLYGON_REPAIR_EVEN_ODD; + srid_t srid; + + sfcgal_postgis_init(); + + input = PG_GETARG_GSERIALIZED_P(0); + srid = gserialized_get_srid(input); + + if (!PG_ARGISNULL(1)) + { + char *rule_str = text_to_cstring(PG_GETARG_TEXT_P(1)); + + if (strcmp(rule_str, "EVEN_ODD") == 0) + rule = SFCGAL_POLYGON_REPAIR_EVEN_ODD; + else if (strcmp(rule_str, "NON_ZERO") == 0 || + strcmp(rule_str, "UNION") == 0 || + strcmp(rule_str, "INTERSECTION") == 0) + { + if (SFCGAL_CGAL_VERSION_MAJOR < 6 || + (SFCGAL_CGAL_VERSION_MAJOR == 6 && SFCGAL_CGAL_VERSION_MINOR < 1)) + { + lwpgerror("CG_PolygonRepair: '%s' rule requires CGAL 6.1 or later", rule_str); + pfree(rule_str); + PG_RETURN_NULL(); + } + if (strcmp(rule_str, "NON_ZERO") == 0) + rule = SFCGAL_POLYGON_REPAIR_NON_ZERO; + else if (strcmp(rule_str, "UNION") == 0) + rule = SFCGAL_POLYGON_REPAIR_UNION; + else + rule = SFCGAL_POLYGON_REPAIR_INTERSECTION; + } + else + { + lwpgerror("CG_PolygonRepair: unknown rule '%s', expected EVEN_ODD, NON_ZERO, UNION or INTERSECTION", + rule_str); + pfree(rule_str); + PG_RETURN_NULL(); + } + pfree(rule_str); /* alloc'ed in text_to_cstring */ + } + + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_polygon_repair(geom, rule); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 0, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +#endif +} diff --git a/sfcgal/sfcgal.sql.in b/sfcgal/sfcgal.sql.in index dcba5b678..a8e9809a4 100644 --- a/sfcgal/sfcgal.sql.in +++ b/sfcgal/sfcgal.sql.in @@ -644,4 +644,11 @@ AS 'MODULE_PATHNAME', 'sfcgal_generate_roof' LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE _COST_DEFAULT; +-- Availability: 3.7.0 - requires SFCGAL >= 2.3.0 and CGAL >= 6.0 +CREATE OR REPLACE FUNCTION CG_PolygonRepair(geom geometry, rule text DEFAULT 'EVEN_ODD') +RETURNS geometry +AS 'MODULE_PATHNAME', 'sfcgal_polygon_repair' +LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE +_COST_DEFAULT; + COMMIT; commit afbe34be9ea5379debd594442ab53bda0f013c45 Author: Lo?c Bartoletti Date: Tue Jun 9 14:13:36 2026 +0200 fix(garden): polygon must be valid diff --git a/doc/xsl/sfcgal_gardentest.sql.xsl b/doc/xsl/sfcgal_gardentest.sql.xsl index 0e48ecd1c..8c6f18e81 100644 --- a/doc/xsl/sfcgal_gardentest.sql.xsl +++ b/doc/xsl/sfcgal_gardentest.sql.xsl @@ -13,7 +13,7 @@ 3.7.0 AddGeometryColumn DropGeometryColumn DropGeometryTable - CG_Simplify CG_Visibility CG_YMonotonePartition ST_AlphaShape ST_OptimalAlphaShape + CG_GenerateFlatRoof CG_GenerateGableRoof CG_GenerateHippedRoof CG_GenerateRoof CG_GenerateSkillionRoof CG_Simplify CG_Visibility CG_YMonotonePartition ST_AlphaShape ST_OptimalAlphaShape 3395 commit 10ab504c6dd5036c1ff65db83e1e8e76ed713ada Author: Lo?c Bartoletti Date: Mon Jun 8 14:29:48 2026 +0200 docs(sfcgal): document roof generation functions diff --git a/doc/html/images/static/cg_generateflatroof01.png b/doc/html/images/static/cg_generateflatroof01.png new file mode 100644 index 000000000..7174e08da Binary files /dev/null and b/doc/html/images/static/cg_generateflatroof01.png differ diff --git a/doc/html/images/static/cg_generategableroof01.png b/doc/html/images/static/cg_generategableroof01.png new file mode 100644 index 000000000..0ee27cfac Binary files /dev/null and b/doc/html/images/static/cg_generategableroof01.png differ diff --git a/doc/html/images/static/cg_generatehippedroof01.png b/doc/html/images/static/cg_generatehippedroof01.png new file mode 100644 index 000000000..a3e5ccd28 Binary files /dev/null and b/doc/html/images/static/cg_generatehippedroof01.png differ diff --git a/doc/html/images/static/cg_generateskillionroof01.png b/doc/html/images/static/cg_generateskillionroof01.png new file mode 100644 index 000000000..b2073908f Binary files /dev/null and b/doc/html/images/static/cg_generateskillionroof01.png differ diff --git a/doc/reference_sfcgal.xml b/doc/reference_sfcgal.xml index b27b72804..a33f797cf 100644 --- a/doc/reference_sfcgal.xml +++ b/doc/reference_sfcgal.xml @@ -1806,6 +1806,369 @@ It always gives a 2D result even when used on a 3D geometry. + + + CG_GenerateFlatRoof + Generate a flat (box) roof from a footprint polygon. + + + + + + geometry CG_GenerateFlatRoof + geometry geom + float8 height + + + + + + Description + + Generate a flat (box-shaped) roof as a 3D + PolyhedralSurface Z from a 2D footprint polygon. + The roof height above the ground plane is given by + height (default 3.0). + + Availability: 3.7.0 - requires SFCGAL >= 2.3.0. + &sfcgal_required; + &P_support; + + + + Examples + + + + + + SELECT ST_AsText( + CG_GenerateFlatRoof( + 'POLYGON((0 0,5 0,5 4,0 4,0 0))', + 2.0)); +-- POLYHEDRALSURFACE Z (...) + + + + + + + + + + + + + + + + See Also + + , + , + , + + + + + + + + + CG_GenerateHippedRoof + Generate a hipped roof from a footprint polygon. + + + + + + geometry CG_GenerateHippedRoof + geometry geom + float8 height + + + + + + Description + + Generate a hipped roof as a 3D PolyhedralSurface Z + from a 2D footprint polygon. All sides slope upward to meet at a ridge + or apex. The roof height is given by height + (default 3.0). + + Availability: 3.7.0 - requires SFCGAL >= 2.3.0. + &sfcgal_required; + &P_support; + + + + Examples + + + + + + SELECT ST_AsText( + CG_GenerateHippedRoof( + 'POLYGON((0 0,5 0,5 4,0 4,0 0))', + 2.0)); +-- POLYHEDRALSURFACE Z (...) + + + + + + + + + + + + + + + + See Also + + , + , + , + + + + + + + + + CG_GenerateGableRoof + Generate a gable roof from a footprint polygon. + + + + + + geometry CG_GenerateGableRoof + geometry geom + float8 height + float8 slope_angle + + + + + + Description + + Generate a gable roof as a 3D PolyhedralSurface Z + from a 2D footprint polygon. Two opposite sides are vertical gable + ends; the other two sides slope to a horizontal ridge. + height sets the ridge height above the ground + (default 3.0) and slope_angle controls the pitch + in degrees (default 30.0). The SRID of the input geometry is + preserved. + + Availability: 3.7.0 - requires SFCGAL >= 2.3.0. + &sfcgal_required; + &P_support; + + + + Examples + + + + + + SELECT ST_CoordDim( + CG_GenerateGableRoof( + 'POLYGON((0 0,5 0,5 4,0 4,0 0))', + 2.0, 30.0)); +-- 3 + + + + + + + + + + + + + + + + See Also + + , + , + , + + + + + + + + + CG_GenerateSkillionRoof + Generate a skillion (single-slope) roof from a footprint polygon. + + + + + + geometry CG_GenerateSkillionRoof + geometry geom + float8 height + float8 slope_angle + integer primary_edge_index + + + + + + Description + + Generate a skillion (single-slope, shed-style) roof as a 3D + PolyhedralSurface Z from a 2D footprint polygon. + The entire roof surface slopes in one direction. + height sets the maximum ridge height (default 3.0), + slope_angle sets the pitch in degrees (default + 30.0), and primary_edge_index selects which + polygon edge defines the high side (0-based, default 0). + + + When the combination of height and + slope_angle would cause a side wall to vanish + (the slope reaches the far edge before the full height is achieved), + that face is omitted from the result. This means the number of + output patches can vary depending on the parameters ? a lower + height relative to the footprint depth produces more faces than + a taller, steeper configuration. + + Availability: 3.7.0 - requires SFCGAL >= 2.3.0. + &sfcgal_required; + &P_support; + + + + Examples + + Height 2.0 produces 6 faces (all walls present); height 4.0 + produces 5 faces (one side wall is filtered out because the + slope reaches the far edge before the full height). + + + + + + + -- height 2.0 ? 6 patches +SELECT ST_NumPatches( + CG_GenerateSkillionRoof( + 'POLYGON((0 0,5 0,5 4,0 4,0 0))', + 2.0)); +-- 6 + +-- height 4.0 ? 5 patches (one face filtered) +SELECT ST_NumPatches( + CG_GenerateSkillionRoof( + 'POLYGON((0 0,5 0,5 4,0 4,0 0))', + 4.0)); +-- 5 + + + + + + + + + + + + + + + + See Also + + , + , + , + + + + + + + + + CG_GenerateRoof + Generate a roof of the requested type from a footprint polygon. + + + + + + geometry CG_GenerateRoof + geometry geom + text roof_type + float8 height + float8 slope_angle + integer primary_edge_index + + + + + + Description + + Generate a roof as a 3D PolyhedralSurface Z from + a 2D footprint polygon. The roof_type parameter + selects the roof style (default 'HIPPED'): + + + FLAT ? flat box roof. + HIPPED ? hipped roof (all sides slope to apex). + GABLE ? gable roof (two sloping sides, two vertical ends). + SKILLION ? single-slope (shed) roof. + + + height sets the roof height (default 3.0), + slope_angle sets the pitch in degrees (default + 30.0), and primary_edge_index selects the + reference edge for skillion roofs (default 0). + + Availability: 3.7.0 - requires SFCGAL >= 2.3.0. + &sfcgal_required; + &P_support; + + + + Examples + SELECT ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'HIPPED', 2.0, 30.0, 0)); +-- POLYHEDRALSURFACE Z (((0 4 0,4 4 0,4 0 0,0 0 0,0 4 0)), ...) + +SELECT ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'FLAT', 2.0)); +-- POLYHEDRALSURFACE Z (((0 0 0,0 4 0,4 4 0,4 0 0,0 0 0)), ...) + + + + See Also + + , + , + , + + + + + + ST_ConstrainedDelaunayTriangles commit a63959a97b85bb029b8ab12712a14db8c4689653 Author: Lo?c Bartoletti Date: Mon Jun 8 14:29:44 2026 +0200 test(sfcgal): add tests for roof generation functions diff --git a/sfcgal/regress/roofgeneration.sql b/sfcgal/regress/roofgeneration.sql new file mode 100644 index 000000000..106f5105e --- /dev/null +++ b/sfcgal/regress/roofgeneration.sql @@ -0,0 +1,16 @@ +-- Tests for CG_GenerateFlatRoof, CG_GenerateHippedRoof, CG_GenerateGableRoof, +-- CG_GenerateSkillionRoof, CG_GenerateRoof +-- Uses square polygon with integer coordinates to ensure exact WKT for flat/hipped. +-- Gable/skillion involve trigonometric values so only dimensionality is checked. + +SELECT 'flat', ST_AsText(CG_GenerateFlatRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 2.0)); +SELECT 'hipped', ST_AsText(CG_GenerateHippedRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 2.0)); +SELECT 'flat_3d', ST_CoordDim(CG_GenerateFlatRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 2.0)); +SELECT 'hipped_3d', ST_CoordDim(CG_GenerateHippedRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 2.0)); +SELECT 'gable_3d', ST_CoordDim(CG_GenerateGableRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 2.0, 30.0)); +SELECT 'skillion_3d', ST_CoordDim(CG_GenerateSkillionRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 2.0, 30.0, 0)); +SELECT 'generic_hipped', ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'HIPPED', 2.0, 30.0, 0)); +SELECT 'generic_flat', ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'FLAT', 2.0, 30.0, 0)); +SELECT 'generic_gable_3d', ST_CoordDim(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'GABLE', 2.0, 30.0, 0)); +SELECT 'generic_skillion_3d', ST_CoordDim(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'SKILLION', 2.0, 30.0, 0)); +SELECT 'invalid_type', CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'DOME', 2.0, 30.0, 0); diff --git a/sfcgal/regress/roofgeneration_expected b/sfcgal/regress/roofgeneration_expected new file mode 100644 index 000000000..d67b1e24d --- /dev/null +++ b/sfcgal/regress/roofgeneration_expected @@ -0,0 +1,11 @@ +flat|POLYHEDRALSURFACE Z (((0 0 0,0 4 0,4 4 0,4 0 0,0 0 0)),((0 0 2,4 0 2,4 4 2,0 4 2,0 0 2)),((0 0 0,0 0 2,0 4 2,0 4 0,0 0 0)),((0 4 0,0 4 2,4 4 2,4 4 0,0 4 0)),((4 4 0,4 4 2,4 0 2,4 0 0,4 4 0)),((4 0 0,4 0 2,0 0 2,0 0 0,4 0 0))) +hipped|POLYHEDRALSURFACE Z (((0 4 0,4 4 0,4 0 0,0 0 0,0 4 0)),((0 4 0,0 0 0,2 2 2,0 4 0)),((0 0 0,4 0 0,2 2 2,0 0 0)),((4 0 0,4 4 0,2 2 2,4 0 0)),((4 4 0,0 4 0,2 2 2,4 4 0))) +flat_3d|3 +hipped_3d|3 +gable_3d|3 +skillion_3d|3 +generic_hipped|POLYHEDRALSURFACE Z (((0 4 0,4 4 0,4 0 0,0 0 0,0 4 0)),((0 4 0,0 0 0,2 2 2,0 4 0)),((0 0 0,4 0 0,2 2 2,0 0 0)),((4 0 0,4 4 0,2 2 2,4 0 0)),((4 4 0,0 4 0,2 2 2,4 4 0))) +generic_flat|POLYHEDRALSURFACE Z (((0 0 0,0 4 0,4 4 0,4 0 0,0 0 0)),((0 0 2,4 0 2,4 4 2,0 4 2,0 0 2)),((0 0 0,0 0 2,0 4 2,0 4 0,0 0 0)),((0 4 0,0 4 2,4 4 2,4 4 0,0 4 0)),((4 4 0,4 4 2,4 0 2,4 0 0,4 4 0)),((4 0 0,4 0 2,0 0 2,0 0 0,4 0 0))) +generic_gable_3d|3 +generic_skillion_3d|3 +ERROR: CG_GenerateRoof: unknown roof type 'DOME', expected FLAT, HIPPED, GABLE or SKILLION diff --git a/sfcgal/regress/tests.mk.in b/sfcgal/regress/tests.mk.in index 8dd78b2ec..54c3c6190 100644 --- a/sfcgal/regress/tests.mk.in +++ b/sfcgal/regress/tests.mk.in @@ -46,5 +46,6 @@ ifeq ($(shell expr "$(POSTGIS_SFCGAL_VERSION)" ">=" 20100),1) endif ifeq ($(shell expr "$(POSTGIS_SFCGAL_VERSION)" ">=" 20300),1) TESTS += \ - $(top_srcdir)/sfcgal/regress/alphashape_components.sql + $(top_srcdir)/sfcgal/regress/alphashape_components.sql \ + $(top_srcdir)/sfcgal/regress/roofgeneration.sql endif commit ea9aa716c07a95b1ebd586cdf7e8ca6c506b3acf Author: Lo?c Bartoletti Date: Mon Jun 8 14:29:40 2026 +0200 feat(sfcgal): add CG_GenerateFlatRoof, CG_GenerateHippedRoof, CG_GenerateGableRoof, CG_GenerateSkillionRoof, CG_GenerateRoof diff --git a/sfcgal/lwgeom_sfcgal.c b/sfcgal/lwgeom_sfcgal.c index 66b2b33cc..bf58c04a7 100644 --- a/sfcgal/lwgeom_sfcgal.c +++ b/sfcgal/lwgeom_sfcgal.c @@ -86,6 +86,11 @@ Datum sfcgal_convexhull3D(PG_FUNCTION_ARGS); Datum sfcgal_alphashape(PG_FUNCTION_ARGS); Datum sfcgal_optimalalphashape(PG_FUNCTION_ARGS); Datum sfcgal_simplify(PG_FUNCTION_ARGS); +Datum sfcgal_generate_flat_roof(PG_FUNCTION_ARGS); +Datum sfcgal_generate_hipped_roof(PG_FUNCTION_ARGS); +Datum sfcgal_generate_gable_roof(PG_FUNCTION_ARGS); +Datum sfcgal_generate_skillion_roof(PG_FUNCTION_ARGS); +Datum sfcgal_generate_roof(PG_FUNCTION_ARGS); GSERIALIZED *geometry_serialize(LWGEOM *lwgeom); char *text_to_cstring(const text *textptr); @@ -1856,3 +1861,248 @@ sfcgal_alphawrapping_3d(PG_FUNCTION_ARGS) PG_RETURN_POINTER(output); #endif } + +PG_FUNCTION_INFO_V1(sfcgal_generate_flat_roof); +Datum +sfcgal_generate_flat_roof(PG_FUNCTION_ARGS) +{ +#if POSTGIS_SFCGAL_VERSION < 20300 + lwpgerror( + "The SFCGAL version this PostGIS binary was compiled against (%d) doesn't support " + "'sfcgal_geometry_generate_flat_roof' function (requires SFCGAL 2.3.0+)", + POSTGIS_SFCGAL_VERSION); + PG_RETURN_NULL(); +#else + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom, *result; + double height; + srid_t srid; + + sfcgal_postgis_init(); + + input = PG_GETARG_GSERIALIZED_P(0); + if (gserialized_get_type(input) != POLYGONTYPE) + { + PG_FREE_IF_COPY(input, 0); + lwpgerror("CG_GenerateFlatRoof: input geometry must be a Polygon"); + PG_RETURN_NULL(); + } + height = PG_GETARG_FLOAT8(1); + srid = gserialized_get_srid(input); + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_generate_flat_roof(geom, height); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 1, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +#endif +} + +PG_FUNCTION_INFO_V1(sfcgal_generate_hipped_roof); +Datum +sfcgal_generate_hipped_roof(PG_FUNCTION_ARGS) +{ +#if POSTGIS_SFCGAL_VERSION < 20300 + lwpgerror( + "The SFCGAL version this PostGIS binary was compiled against (%d) doesn't support " + "'sfcgal_geometry_generate_hipped_roof' function (requires SFCGAL 2.3.0+)", + POSTGIS_SFCGAL_VERSION); + PG_RETURN_NULL(); +#else + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom, *result; + double height; + srid_t srid; + + sfcgal_postgis_init(); + + input = PG_GETARG_GSERIALIZED_P(0); + if (gserialized_get_type(input) != POLYGONTYPE) + { + PG_FREE_IF_COPY(input, 0); + lwpgerror("CG_GenerateHippedRoof: input geometry must be a Polygon"); + PG_RETURN_NULL(); + } + height = PG_GETARG_FLOAT8(1); + srid = gserialized_get_srid(input); + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_generate_hipped_roof(geom, height); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 1, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +#endif +} + +PG_FUNCTION_INFO_V1(sfcgal_generate_gable_roof); +Datum +sfcgal_generate_gable_roof(PG_FUNCTION_ARGS) +{ +#if POSTGIS_SFCGAL_VERSION < 20300 + lwpgerror( + "The SFCGAL version this PostGIS binary was compiled against (%d) doesn't support " + "'sfcgal_geometry_generate_gable_roof' function (requires SFCGAL 2.3.0+)", + POSTGIS_SFCGAL_VERSION); + PG_RETURN_NULL(); +#else + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom, *result; + double height; + double slope_angle; + srid_t srid; + + sfcgal_postgis_init(); + + input = PG_GETARG_GSERIALIZED_P(0); + if (gserialized_get_type(input) != POLYGONTYPE) + { + PG_FREE_IF_COPY(input, 0); + lwpgerror("CG_GenerateGableRoof: input geometry must be a Polygon"); + PG_RETURN_NULL(); + } + height = PG_GETARG_FLOAT8(1); + slope_angle = PG_GETARG_FLOAT8(2); + srid = gserialized_get_srid(input); + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_generate_gable_roof(geom, height, slope_angle); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 1, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +#endif +} + +PG_FUNCTION_INFO_V1(sfcgal_generate_skillion_roof); +Datum +sfcgal_generate_skillion_roof(PG_FUNCTION_ARGS) +{ +#if POSTGIS_SFCGAL_VERSION < 20300 + lwpgerror( + "The SFCGAL version this PostGIS binary was compiled against (%d) doesn't support " + "'sfcgal_geometry_generate_skillion_roof' function (requires SFCGAL 2.3.0+)", + POSTGIS_SFCGAL_VERSION); + PG_RETURN_NULL(); +#else + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom, *result; + double height; + double slope_angle; + int primary_edge_index; + srid_t srid; + + sfcgal_postgis_init(); + + input = PG_GETARG_GSERIALIZED_P(0); + if (gserialized_get_type(input) != POLYGONTYPE) + { + PG_FREE_IF_COPY(input, 0); + lwpgerror("CG_GenerateSkillionRoof: input geometry must be a Polygon"); + PG_RETURN_NULL(); + } + height = PG_GETARG_FLOAT8(1); + slope_angle = PG_GETARG_FLOAT8(2); + primary_edge_index = PG_GETARG_INT32(3); + if (primary_edge_index < 0) + { + PG_FREE_IF_COPY(input, 0); + lwpgerror("CG_GenerateSkillionRoof: primary_edge_index must be >= 0"); + PG_RETURN_NULL(); + } + srid = gserialized_get_srid(input); + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_generate_skillion_roof(geom, height, slope_angle, (size_t)primary_edge_index); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 1, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +#endif +} + +PG_FUNCTION_INFO_V1(sfcgal_generate_roof); +Datum +sfcgal_generate_roof(PG_FUNCTION_ARGS) +{ +#if POSTGIS_SFCGAL_VERSION < 20300 + lwpgerror( + "The SFCGAL version this PostGIS binary was compiled against (%d) doesn't support " + "'sfcgal_geometry_generate_roof' function (requires SFCGAL 2.3.0+)", + POSTGIS_SFCGAL_VERSION); + PG_RETURN_NULL(); +#else + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom, *result; + sfcgal_roof_type_t roof_type; + double height; + double slope_angle; + int primary_edge_index; + srid_t srid; + + sfcgal_postgis_init(); + + input = PG_GETARG_GSERIALIZED_P(0); + if (gserialized_get_type(input) != POLYGONTYPE) + { + PG_FREE_IF_COPY(input, 0); + lwpgerror("CG_GenerateRoof: input geometry must be a Polygon"); + PG_RETURN_NULL(); + } + height = PG_GETARG_FLOAT8(2); + slope_angle = PG_GETARG_FLOAT8(3); + primary_edge_index = PG_GETARG_INT32(4); + if (primary_edge_index < 0) + { + PG_FREE_IF_COPY(input, 0); + lwpgerror("CG_GenerateRoof: primary_edge_index must be >= 0"); + PG_RETURN_NULL(); + } + srid = gserialized_get_srid(input); + + { + char *type_str = text_to_cstring(PG_GETARG_TEXT_P(1)); + + if (strcmp(type_str, "FLAT") == 0) + roof_type = SFCGAL_ROOF_FLAT; + else if (strcmp(type_str, "HIPPED") == 0) + roof_type = SFCGAL_ROOF_HIPPED; + else if (strcmp(type_str, "GABLE") == 0) + roof_type = SFCGAL_ROOF_GABLE; + else if (strcmp(type_str, "SKILLION") == 0) + roof_type = SFCGAL_ROOF_SKILLION; + else + { + lwpgerror("CG_GenerateRoof: unknown roof type '%s', expected FLAT, HIPPED, GABLE or SKILLION", + type_str); + pfree(type_str); + PG_RETURN_NULL(); + } + pfree(type_str); /* alloc'ed in text_to_cstring */ + } + + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_generate_roof(geom, roof_type, slope_angle, height, (size_t)primary_edge_index); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 1, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +#endif +} diff --git a/sfcgal/sfcgal.sql.in b/sfcgal/sfcgal.sql.in index e377d6691..dcba5b678 100644 --- a/sfcgal/sfcgal.sql.in +++ b/sfcgal/sfcgal.sql.in @@ -609,4 +609,39 @@ AS 'MODULE_PATHNAME', 'sfcgal_alphawrapping_3d' LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE _COST_LOW; +-- Availability: 3.7.0 - requires SFCGAL >= 2.3.0 +CREATE OR REPLACE FUNCTION CG_GenerateFlatRoof(geom geometry, height float8 DEFAULT 3.0) +RETURNS geometry +AS 'MODULE_PATHNAME', 'sfcgal_generate_flat_roof' +LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE +_COST_DEFAULT; + +-- Availability: 3.7.0 - requires SFCGAL >= 2.3.0 +CREATE OR REPLACE FUNCTION CG_GenerateHippedRoof(geom geometry, height float8 DEFAULT 3.0) +RETURNS geometry +AS 'MODULE_PATHNAME', 'sfcgal_generate_hipped_roof' +LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE +_COST_DEFAULT; + +-- Availability: 3.7.0 - requires SFCGAL >= 2.3.0 +CREATE OR REPLACE FUNCTION CG_GenerateGableRoof(geom geometry, height float8 DEFAULT 3.0, slope_angle float8 DEFAULT 30.0) +RETURNS geometry +AS 'MODULE_PATHNAME', 'sfcgal_generate_gable_roof' +LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE +_COST_DEFAULT; + +-- Availability: 3.7.0 - requires SFCGAL >= 2.3.0 +CREATE OR REPLACE FUNCTION CG_GenerateSkillionRoof(geom geometry, height float8 DEFAULT 3.0, slope_angle float8 DEFAULT 30.0, primary_edge_index integer DEFAULT 0) +RETURNS geometry +AS 'MODULE_PATHNAME', 'sfcgal_generate_skillion_roof' +LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE +_COST_DEFAULT; + +-- Availability: 3.7.0 - requires SFCGAL >= 2.3.0 +CREATE OR REPLACE FUNCTION CG_GenerateRoof(geom geometry, roof_type text DEFAULT 'HIPPED', height float8 DEFAULT 3.0, slope_angle float8 DEFAULT 30.0, primary_edge_index integer DEFAULT 0) +RETURNS geometry +AS 'MODULE_PATHNAME', 'sfcgal_generate_roof' +LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE +_COST_DEFAULT; + COMMIT; ----------------------------------------------------------------------- Summary of changes: configure.ac | 13 + doc/html/images/static/cg_generateflatroof01.png | Bin 0 -> 3249 bytes doc/html/images/static/cg_generategableroof01.png | Bin 0 -> 2624 bytes doc/html/images/static/cg_generatehippedroof01.png | Bin 0 -> 3072 bytes .../images/static/cg_generateskillionroof01.png | Bin 0 -> 3306 bytes doc/reference_sfcgal.xml | 438 +++++++++++++++++++++ doc/xsl/sfcgal_gardentest.sql.xsl | 2 +- sfcgal/lwgeom_sfcgal.c | 338 ++++++++++++++++ sfcgal/regress/approximatemedialaxis.sql | 5 +- sfcgal/regress/approximatemedialaxis_expected | 4 +- sfcgal/regress/approximatemedialaxis_projected.sql | 3 + .../approximatemedialaxis_projected_expected | 2 + .../approximatemedialaxis_projected_pre230.sql | 3 + ...approximatemedialaxis_projected_pre230_expected | 4 + sfcgal/regress/polygonrepair.sql | 8 + sfcgal/regress/polygonrepair_expected | 4 + sfcgal/regress/polygonrepair_union.sql | 2 + sfcgal/regress/polygonrepair_union_expected | 1 + sfcgal/regress/polygonrepair_union_pre61.sql | 2 + sfcgal/regress/polygonrepair_union_pre61_expected | 1 + sfcgal/regress/roofgeneration.sql | 16 + sfcgal/regress/roofgeneration_expected | 11 + sfcgal/regress/tests.mk.in | 14 +- sfcgal/sfcgal.sql.in | 50 +++ 24 files changed, 917 insertions(+), 4 deletions(-) create mode 100644 doc/html/images/static/cg_generateflatroof01.png create mode 100644 doc/html/images/static/cg_generategableroof01.png create mode 100644 doc/html/images/static/cg_generatehippedroof01.png create mode 100644 doc/html/images/static/cg_generateskillionroof01.png create mode 100644 sfcgal/regress/approximatemedialaxis_projected.sql create mode 100644 sfcgal/regress/approximatemedialaxis_projected_expected create mode 100644 sfcgal/regress/approximatemedialaxis_projected_pre230.sql create mode 100644 sfcgal/regress/approximatemedialaxis_projected_pre230_expected create mode 100644 sfcgal/regress/polygonrepair.sql create mode 100644 sfcgal/regress/polygonrepair_expected create mode 100644 sfcgal/regress/polygonrepair_union.sql create mode 100644 sfcgal/regress/polygonrepair_union_expected create mode 100644 sfcgal/regress/polygonrepair_union_pre61.sql create mode 100644 sfcgal/regress/polygonrepair_union_pre61_expected create mode 100644 sfcgal/regress/roofgeneration.sql create mode 100644 sfcgal/regress/roofgeneration_expected hooks/post-receive -- PostGIS From git at osgeo.org Tue Jun 9 23:34:39 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 9 Jun 2026 23:34:39 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-521-ge9672a33a Message-ID: <20260610063439.71EF116CDE8@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via e9672a33a6965271da6d6f95e21ffddb911e423b (commit) from 91dd9dbfd60c93b510160076a5b520dc6fc3854f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e9672a33a6965271da6d6f95e21ffddb911e423b Author: Lo?c Bartoletti Date: Wed Jun 10 08:34:34 2026 +0200 ci: gh actions are now ok to run on master diff --git a/.github/workflows/ci-freebsd.yml b/.github/workflows/ci-freebsd.yml index 93f7360fe..95e881178 100644 --- a/.github/workflows/ci-freebsd.yml +++ b/.github/workflows/ci-freebsd.yml @@ -3,12 +3,6 @@ name: "CI (FreeBSD)" -on: - push: - branches-ignore: - - 'master' - pull_request: ~ - jobs: freebsd: diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index 27c3cd565..28fcf7797 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -3,12 +3,6 @@ name: "CI (macOS)" -on: - push: - branches-ignore: - - 'master' - pull_request: ~ - jobs: macos: ----------------------------------------------------------------------- Summary of changes: .github/workflows/ci-freebsd.yml | 6 ------ .github/workflows/ci-macos.yml | 6 ------ 2 files changed, 12 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Wed Jun 10 00:05:10 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Jun 2026 00:05:10 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-522-gcbf9d94b1 Message-ID: <20260610070510.E78CA16D6AB@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via cbf9d94b1fbec4a56302bb1a38c3b02ff147c434 (commit) from e9672a33a6965271da6d6f95e21ffddb911e423b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit cbf9d94b1fbec4a56302bb1a38c3b02ff147c434 Author: Lo?c Bartoletti Date: Wed Jun 10 09:04:07 2026 +0200 fix(ci): restore on: triggers for FreeBSD and macOS workflows diff --git a/.github/workflows/ci-freebsd.yml b/.github/workflows/ci-freebsd.yml index 95e881178..601aebfc7 100644 --- a/.github/workflows/ci-freebsd.yml +++ b/.github/workflows/ci-freebsd.yml @@ -3,6 +3,10 @@ name: "CI (FreeBSD)" +on: + push: ~ + pull_request: ~ + jobs: freebsd: diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index 28fcf7797..c4ae069c1 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -3,6 +3,10 @@ name: "CI (macOS)" +on: + push: ~ + pull_request: ~ + jobs: macos: ----------------------------------------------------------------------- Summary of changes: .github/workflows/ci-freebsd.yml | 4 ++++ .github/workflows/ci-macos.yml | 4 ++++ 2 files changed, 8 insertions(+) hooks/post-receive -- PostGIS From trac at osgeo.org Wed Jun 10 09:17:19 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 16:17:19 -0000 Subject: [PostGIS] #5793: Crash on Buffer of Empty array on PG17 In-Reply-To: <049.503e7382537fd48e85a82281f124bc52@osgeo.org> References: <049.503e7382537fd48e85a82281f124bc52@osgeo.org> Message-ID: <064.1f188b5c9cf04d4cb1ce6ce6555ced60@osgeo.org> #5793: Crash on Buffer of Empty array on PG17 ----------------------+-------------------------------- Reporter: pramsey | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS PostgreSQL Component: postgis | Version: 3.4.x Resolution: fixed | Keywords: pg17 ----------------------+-------------------------------- Changes (by pramsey): * resolution: => fixed * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 09:18:07 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 16:18:07 -0000 Subject: [PostGIS] #5192: Error executing PostGIS function In-Reply-To: <053.0e5c69439d00a30cf656447fea17bad0@osgeo.org> References: <053.0e5c69439d00a30cf656447fea17bad0@osgeo.org> Message-ID: <068.214ed6ccc2eb414d9c76c6f2fe957ef7@osgeo.org> #5192: Error executing PostGIS function --------------------------+-------------------------------- Reporter: thomasmarti | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS PostgreSQL Component: postgis | Version: 3.2.x Resolution: worksforme | Keywords: --------------------------+-------------------------------- Changes (by pramsey): * resolution: => worksforme * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 09:22:55 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 16:22:55 -0000 Subject: [PostGIS] #2181: ST_Buffer returning multipolygon with linestring/polygon input In-Reply-To: <050.1c3ec6a9dcb0a0b8df3ce00ff834a605@osgeo.org> References: <050.1c3ec6a9dcb0a0b8df3ce00ff834a605@osgeo.org> Message-ID: <065.3da9b27304408a28079a432c84ff5b75@osgeo.org> #2181: ST_Buffer returning multipolygon with linestring/polygon input -----------------------+---------------------------------------------- Reporter: mcastrog | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS GEOS Component: postgis | Version: 2.0.x Resolution: fixed | Keywords: Buffer, linestring, multipolygon -----------------------+---------------------------------------------- Changes (by pramsey): * resolution: => fixed * status: new => closed Comment: This has been fixed in GEOS, see https://github.com/libgeos/geos/pull/1323 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 09:28:20 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 16:28:20 -0000 Subject: [PostGIS] #3195: ST_Length on 3D geography gives 3D length In-Reply-To: <049.fd7e6e49f8e0be12230aa0f003722462@osgeo.org> References: <049.fd7e6e49f8e0be12230aa0f003722462@osgeo.org> Message-ID: <064.f5b1d7831133d8658f90ae92ebd4f474@osgeo.org> #3195: ST_Length on 3D geography gives 3D length -------------------------+----------------------------- Reporter: Mike Taves | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: -------------------------+----------------------------- Changes (by pramsey): * resolution: => fixed * status: new => closed Comment: Seems to have been fixed in intervening decade. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 10:40:16 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 17:40:16 -0000 Subject: [PostGIS] #4794: ST_3DIntersection does not behave correctly with line strings when no vertex is seen within the intersecion In-Reply-To: <051.4c92cc58f785b100c85003a6a2a4d1a2@osgeo.org> References: <051.4c92cc58f785b100c85003a6a2a4d1a2@osgeo.org> Message-ID: <066.a9bb163cecdba0446c83076f81a7a9c7@osgeo.org> #4794: ST_3DIntersection does not behave correctly with line strings when no vertex is seen within the intersecion ------------------------+----------------------------- Reporter: basilrabi | Owner: Lo?c Bartoletti Type: defect | Status: new Priority: medium | Milestone: PostGIS SFCGAL Component: sfcgal | Version: 3.0.x Resolution: | Keywords: ------------------------+----------------------------- Changes (by pramsey): * component: postgis => sfcgal * owner: pramsey => Lo?c Bartoletti -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 10:44:55 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 17:44:55 -0000 Subject: [PostGIS] #4954: ST_Transform error involving NAD27 In-Reply-To: <052.c09c47b13315972abf07f6d2e45e58be@osgeo.org> References: <052.c09c47b13315972abf07f6d2e45e58be@osgeo.org> Message-ID: <067.9f39d07ad57ca250ef9345b6ff7685f0@osgeo.org> #4954: ST_Transform error involving NAD27 -------------------------+-------------------------- Reporter: turntwo463 | Owner: pramsey Type: defect | Status: closed Priority: critical | Milestone: PostGIS GDAL Component: postgis | Version: 3.1.x Resolution: worksforme | Keywords: -------------------------+-------------------------- Changes (by pramsey): * resolution: => worksforme * status: new => closed Comment: End of the day, we take the answers from Proj and consider them golden. If you can show a case that is different from ST_Transform than from using cs2cs, that's something I am (vaguely) interested in. Vaguely, because it is still very dependent on your local environment, what grids you have installed and so on, which is outside our control, but hopefully in general you would see ST_Transform matching cs2cs run on the same machine. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Wed Jun 10 11:38:53 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Jun 2026 11:38:53 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.5 updated. 3.5.6-13-g9816f8245 Message-ID: <20260610183854.0C20218F440@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.5 has been updated via 9816f82458db774e62906cfb2c4f01f8b262c862 (commit) from 8150016e768bae6b9279cadf47ec9417c242a696 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 9816f82458db774e62906cfb2c4f01f8b262c862 Author: Paul Ramsey Date: Wed Jun 10 11:38:16 2026 -0700 Prepare for 3.5.7 release diff --git a/NEWS b/NEWS index 2ea9ba65d..4fd2190ae 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,5 @@ PostGIS 3.5.7 -2026/xx/xx +2026/06/10 * Bug Fixes * diff --git a/README.postgis b/README.postgis index 2b7efae2b..473eef58f 100644 --- a/README.postgis +++ b/README.postgis @@ -1,8 +1,8 @@ PostGIS - Geographic Information Systems Extensions to PostgreSQL ================================================================= -:Version: 3.5.6 -:Date: 2026-04-14 +:Version: 3.5.7 +:Date: 2026-06-10 :Website: https://postgis.net This distribution contains a module which implements GIS simple features, ties diff --git a/Version.config b/Version.config index 8057027e3..23e465b5d 100644 --- a/Version.config +++ b/Version.config @@ -5,7 +5,7 @@ POSTGIS_MAJOR_VERSION=3 POSTGIS_MINOR_VERSION=5 -POSTGIS_MICRO_VERSION=7dev +POSTGIS_MICRO_VERSION=7 # Liblwgeom interface versioning, reset to 0:0:0 (cur:age:rev) # when changing POSTGIS_MINOR_VERSION diff --git a/doc/release_notes.xml b/doc/release_notes.xml index 93d0f803b..27fc1f0c9 100644 --- a/doc/release_notes.xml +++ b/doc/release_notes.xml @@ -3,6 +3,19 @@ Appendix Release Notes +
+ PostGIS 3.5.7 + 2026/06/10 + + Bug Fixes + 5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) + Flatgeobuf schema mismatch vulnerability (NeuroWinter) + 5916, ST_Split hang with very large ordinates (Paul Ramsey) + 5989, CurvePolygon distance corner case (Paul Ramsey) + 5357, ST_LineFromEncodedPolyline dropping close points (Paul Ramsey) + +
+
PostGIS 3.5.6 2026/04/14 ----------------------------------------------------------------------- Summary of changes: NEWS | 2 +- README.postgis | 4 ++-- Version.config | 2 +- doc/release_notes.xml | 13 +++++++++++++ 4 files changed, 17 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Wed Jun 10 13:47:22 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Jun 2026 13:47:22 -0700 (PDT) Subject: [SCM] postgis.net branch website updated. clarity-final-186-gade329e Message-ID: <20260610204722.3629A18F788@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "postgis.net". The branch, website has been updated via ade329e6cc06842f4ccb2d36a408f834afc0ac46 (commit) from 18f8be98bd30c17c6ab604086932a83e071f837f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit ade329e6cc06842f4ccb2d36a408f834afc0ac46 Author: Paul Ramsey Date: Wed Jun 10 13:47:12 2026 -0700 PostGIS 3.5.7 diff --git a/config.toml b/config.toml index 531c23b..67b82f7 100644 --- a/config.toml +++ b/config.toml @@ -174,8 +174,8 @@ enableRobotsTXT = true tag = "3.6.4" [params.postgis.releases.35] minor = "3.5" - dev = "3.5.7dev" - tag = "3.5.6" + dev = "3.5.8dev" + tag = "3.5.7" [params.postgis.releases.34] minor = "3.4" dev = "3.4.7dev" ----------------------------------------------------------------------- Summary of changes: config.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- postgis.net From git at osgeo.org Wed Jun 10 15:20:20 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Jun 2026 15:20:20 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-523-g24e75f75b Message-ID: <20260610222020.BB1DD18F70F@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 24e75f75b94ce51ce88fad7a4b9fadae12ae3ef3 (commit) from cbf9d94b1fbec4a56302bb1a38c3b02ff147c434 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 24e75f75b94ce51ce88fad7a4b9fadae12ae3ef3 Author: Paul Ramsey Date: Wed Jun 10 21:56:31 2026 +0000 Handle 32-bit platform in fromFlatGeobuf diff --git a/postgis/flatgeobuf.c b/postgis/flatgeobuf.c index c984557dd..dc4621eba 100644 --- a/postgis/flatgeobuf.c +++ b/postgis/flatgeobuf.c @@ -360,7 +360,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(uint32_t) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for uint value"); memcpy(&value, data + offset, sizeof(uint32_t)); - values[ci] = UInt32GetDatum(value); + values[ci] = Int64GetDatum((int64_t)(uint64_t) value); offset += sizeof(uint32_t); break; } @@ -387,10 +387,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(float) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for float value"); memcpy(&value, data + offset, sizeof(float)); - if (getBaseType(TupleDescAttr(ctx->tupdesc, ci)->atttypid) == FLOAT8OID) - values[ci] = Float8GetDatum((double) value); - else - values[ci] = Float4GetDatum(value); + values[ci] = Float4GetDatum(value); offset += sizeof(float); break; } diff --git a/postgis/lwgeom_in_flatgeobuf.c b/postgis/lwgeom_in_flatgeobuf.c index 8fc2e6efb..235fbbeed 100644 --- a/postgis/lwgeom_in_flatgeobuf.c +++ b/postgis/lwgeom_in_flatgeobuf.c @@ -88,24 +88,19 @@ flatgeobuf_type_compatible(uint8_t fgb_type, Oid pgtype) { case flatgeobuf_column_type_bool: return pgtype == BOOLOID; - /* small integer types: allow widening into larger signed ints */ case flatgeobuf_column_type_byte: case flatgeobuf_column_type_ubyte: case flatgeobuf_column_type_short: case flatgeobuf_column_type_ushort: - return pgtype == INT2OID || pgtype == INT4OID || pgtype == INT8OID; - /* int32: allow widening to bigint */ + return pgtype == INT2OID; case flatgeobuf_column_type_int: - return pgtype == INT4OID || pgtype == INT8OID; - /* uint32 max exceeds INT4, must land in bigint */ + return pgtype == INT4OID; case flatgeobuf_column_type_uint: - return pgtype == INT8OID; case flatgeobuf_column_type_long: case flatgeobuf_column_type_ulong: return pgtype == INT8OID; - /* float: allow widening to double (explicit conversion handled in decode) */ case flatgeobuf_column_type_float: - return pgtype == FLOAT4OID || pgtype == FLOAT8OID; + return pgtype == FLOAT4OID; case flatgeobuf_column_type_double: return pgtype == FLOAT8OID; case flatgeobuf_column_type_string: diff --git a/regress/core/flatgeobuf.sql b/regress/core/flatgeobuf.sql index 7fb731aa1..f5390a258 100644 --- a/regress/core/flatgeobuf.sql +++ b/regress/core/flatgeobuf.sql @@ -176,20 +176,6 @@ select 'MM1' from ST_FromFlatGeobuf(null::flatgeobuf_mm_text, ( select 'MM2' from ST_FromFlatGeobuf(null::flatgeobuf_mm_long, ( select ST_AsFlatGeobuf(q) fgb from (select null::geometry, 42::bigint as val1, 43::bigint as val2) q)); -select '--- Numeric widening ---'; - --- integer (int32 in file) widened to bigint in target -select ST_FromFlatGeobufToTable('public', 'flatgeobuf_widen_i', (select ST_AsFlatGeobuf(q) fgb from (select - null::geometry, null::bigint as val) q)); -select 'W1', id, val from ST_FromFlatGeobuf(null::flatgeobuf_widen_i, ( - select ST_AsFlatGeobuf(q) fgb from (select null::geometry, 42::integer as val) q)); - --- real (float4 in file) widened to double precision in target -select ST_FromFlatGeobufToTable('public', 'flatgeobuf_widen_f', (select ST_AsFlatGeobuf(q) fgb from (select - null::geometry, null::double precision as val) q)); -select 'W2', id, val from ST_FromFlatGeobuf(null::flatgeobuf_widen_f, ( - select ST_AsFlatGeobuf(q) fgb from (select null::geometry, 1.5::real as val) q)); - select '--- Quoted identifiers ---'; -- Verify that special characters in column names are properly quoted @@ -216,5 +202,3 @@ drop table if exists public.flatgeobuf_qi; drop table if exists public.flatgeobuf_mm_long; drop table if exists public.flatgeobuf_mm_text; drop table if exists public.flatgeobuf_mm_twocols; -drop table if exists public.flatgeobuf_widen_i; -drop table if exists public.flatgeobuf_widen_f; diff --git a/regress/core/flatgeobuf_expected b/regress/core/flatgeobuf_expected index ea7e022cc..6e97ee425 100644 --- a/regress/core/flatgeobuf_expected +++ b/regress/core/flatgeobuf_expected @@ -27,9 +27,6 @@ E1|0|t|POINT(1.1 2.1)|f --- Type mismatch detection --- ERROR: flatgeobuf: column "val" type mismatch: file type "Long" is not compatible with PostgreSQL type text ERROR: flatgeobuf: column count mismatch: file has 2 columns, target type has 1 ---- Numeric widening --- -W1|0|42 -W2|0|1.5 --- Quoted identifiers --- QI1 QI2 ----------------------------------------------------------------------- Summary of changes: postgis/flatgeobuf.c | 7 ++----- postgis/lwgeom_in_flatgeobuf.c | 11 +++-------- regress/core/flatgeobuf.sql | 16 ---------------- regress/core/flatgeobuf_expected | 3 --- 4 files changed, 5 insertions(+), 32 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Wed Jun 10 15:25:45 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Jun 2026 15:25:45 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.6 updated. 3.6.4-6-g86bf6bf19 Message-ID: <20260610222546.0621318FCF8@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.6 has been updated via 86bf6bf1965bc03b53a391da5a17f1ff134f1fd2 (commit) from 5027c25025a6927058f12d3de2e7bdf04fc10149 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 86bf6bf1965bc03b53a391da5a17f1ff134f1fd2 Author: Paul Ramsey Date: Wed Jun 10 15:23:49 2026 -0700 Handle 32-bit platform in fromFlatGeobuf diff --git a/postgis/flatgeobuf.c b/postgis/flatgeobuf.c index c984557dd..dc4621eba 100644 --- a/postgis/flatgeobuf.c +++ b/postgis/flatgeobuf.c @@ -360,7 +360,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(uint32_t) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for uint value"); memcpy(&value, data + offset, sizeof(uint32_t)); - values[ci] = UInt32GetDatum(value); + values[ci] = Int64GetDatum((int64_t)(uint64_t) value); offset += sizeof(uint32_t); break; } @@ -387,10 +387,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(float) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for float value"); memcpy(&value, data + offset, sizeof(float)); - if (getBaseType(TupleDescAttr(ctx->tupdesc, ci)->atttypid) == FLOAT8OID) - values[ci] = Float8GetDatum((double) value); - else - values[ci] = Float4GetDatum(value); + values[ci] = Float4GetDatum(value); offset += sizeof(float); break; } diff --git a/postgis/lwgeom_in_flatgeobuf.c b/postgis/lwgeom_in_flatgeobuf.c index 8fc2e6efb..235fbbeed 100644 --- a/postgis/lwgeom_in_flatgeobuf.c +++ b/postgis/lwgeom_in_flatgeobuf.c @@ -88,24 +88,19 @@ flatgeobuf_type_compatible(uint8_t fgb_type, Oid pgtype) { case flatgeobuf_column_type_bool: return pgtype == BOOLOID; - /* small integer types: allow widening into larger signed ints */ case flatgeobuf_column_type_byte: case flatgeobuf_column_type_ubyte: case flatgeobuf_column_type_short: case flatgeobuf_column_type_ushort: - return pgtype == INT2OID || pgtype == INT4OID || pgtype == INT8OID; - /* int32: allow widening to bigint */ + return pgtype == INT2OID; case flatgeobuf_column_type_int: - return pgtype == INT4OID || pgtype == INT8OID; - /* uint32 max exceeds INT4, must land in bigint */ + return pgtype == INT4OID; case flatgeobuf_column_type_uint: - return pgtype == INT8OID; case flatgeobuf_column_type_long: case flatgeobuf_column_type_ulong: return pgtype == INT8OID; - /* float: allow widening to double (explicit conversion handled in decode) */ case flatgeobuf_column_type_float: - return pgtype == FLOAT4OID || pgtype == FLOAT8OID; + return pgtype == FLOAT4OID; case flatgeobuf_column_type_double: return pgtype == FLOAT8OID; case flatgeobuf_column_type_string: ----------------------------------------------------------------------- Summary of changes: postgis/flatgeobuf.c | 7 ++----- postgis/lwgeom_in_flatgeobuf.c | 11 +++-------- 2 files changed, 5 insertions(+), 13 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Wed Jun 10 15:25:48 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Jun 2026 15:25:48 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.5 updated. 3.5.7-1-gb1bf0d52d Message-ID: <20260610222548.432DB18FF23@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.5 has been updated via b1bf0d52d1f1eb043b2b6aeecfd2edec4cdb65c8 (commit) from 9816f82458db774e62906cfb2c4f01f8b262c862 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b1bf0d52d1f1eb043b2b6aeecfd2edec4cdb65c8 Author: Paul Ramsey Date: Wed Jun 10 15:23:49 2026 -0700 Handle 32-bit platform in fromFlatGeobuf diff --git a/postgis/flatgeobuf.c b/postgis/flatgeobuf.c index 048e9fbe0..fcab4850d 100644 --- a/postgis/flatgeobuf.c +++ b/postgis/flatgeobuf.c @@ -360,7 +360,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(uint32_t) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for uint value"); memcpy(&value, data + offset, sizeof(uint32_t)); - values[ci] = UInt32GetDatum(value); + values[ci] = Int64GetDatum((int64_t)(uint64_t) value); offset += sizeof(uint32_t); break; } @@ -387,10 +387,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(float) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for float value"); memcpy(&value, data + offset, sizeof(float)); - if (getBaseType(TupleDescAttr(ctx->tupdesc, ci)->atttypid) == FLOAT8OID) - values[ci] = Float8GetDatum((double) value); - else - values[ci] = Float4GetDatum(value); + values[ci] = Float4GetDatum(value); offset += sizeof(float); break; } diff --git a/postgis/lwgeom_in_flatgeobuf.c b/postgis/lwgeom_in_flatgeobuf.c index 773b50f98..9b8f53874 100644 --- a/postgis/lwgeom_in_flatgeobuf.c +++ b/postgis/lwgeom_in_flatgeobuf.c @@ -88,24 +88,19 @@ flatgeobuf_type_compatible(uint8_t fgb_type, Oid pgtype) { case flatgeobuf_column_type_bool: return pgtype == BOOLOID; - /* small integer types: allow widening into larger signed ints */ case flatgeobuf_column_type_byte: case flatgeobuf_column_type_ubyte: case flatgeobuf_column_type_short: case flatgeobuf_column_type_ushort: - return pgtype == INT2OID || pgtype == INT4OID || pgtype == INT8OID; - /* int32: allow widening to bigint */ + return pgtype == INT2OID; case flatgeobuf_column_type_int: - return pgtype == INT4OID || pgtype == INT8OID; - /* uint32 max exceeds INT4, must land in bigint */ + return pgtype == INT4OID; case flatgeobuf_column_type_uint: - return pgtype == INT8OID; case flatgeobuf_column_type_long: case flatgeobuf_column_type_ulong: return pgtype == INT8OID; - /* float: allow widening to double (explicit conversion handled in decode) */ case flatgeobuf_column_type_float: - return pgtype == FLOAT4OID || pgtype == FLOAT8OID; + return pgtype == FLOAT4OID; case flatgeobuf_column_type_double: return pgtype == FLOAT8OID; case flatgeobuf_column_type_string: ----------------------------------------------------------------------- Summary of changes: postgis/flatgeobuf.c | 7 ++----- postgis/lwgeom_in_flatgeobuf.c | 11 +++-------- 2 files changed, 5 insertions(+), 13 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Wed Jun 10 15:25:49 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Jun 2026 15:25:49 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.4 updated. 3.4.6-13-g4201384f1 Message-ID: <20260610222550.0E1E718FF24@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.4 has been updated via 4201384f1cf1518cecb9008b394f9d3478386033 (commit) from 74a2d3936b89d4d9afa87d054203446239b2c3de (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 4201384f1cf1518cecb9008b394f9d3478386033 Author: Paul Ramsey Date: Wed Jun 10 15:23:49 2026 -0700 Handle 32-bit platform in fromFlatGeobuf diff --git a/postgis/flatgeobuf.c b/postgis/flatgeobuf.c index 048e9fbe0..fcab4850d 100644 --- a/postgis/flatgeobuf.c +++ b/postgis/flatgeobuf.c @@ -360,7 +360,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(uint32_t) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for uint value"); memcpy(&value, data + offset, sizeof(uint32_t)); - values[ci] = UInt32GetDatum(value); + values[ci] = Int64GetDatum((int64_t)(uint64_t) value); offset += sizeof(uint32_t); break; } @@ -387,10 +387,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(float) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for float value"); memcpy(&value, data + offset, sizeof(float)); - if (getBaseType(TupleDescAttr(ctx->tupdesc, ci)->atttypid) == FLOAT8OID) - values[ci] = Float8GetDatum((double) value); - else - values[ci] = Float4GetDatum(value); + values[ci] = Float4GetDatum(value); offset += sizeof(float); break; } diff --git a/postgis/lwgeom_in_flatgeobuf.c b/postgis/lwgeom_in_flatgeobuf.c index 773b50f98..9b8f53874 100644 --- a/postgis/lwgeom_in_flatgeobuf.c +++ b/postgis/lwgeom_in_flatgeobuf.c @@ -88,24 +88,19 @@ flatgeobuf_type_compatible(uint8_t fgb_type, Oid pgtype) { case flatgeobuf_column_type_bool: return pgtype == BOOLOID; - /* small integer types: allow widening into larger signed ints */ case flatgeobuf_column_type_byte: case flatgeobuf_column_type_ubyte: case flatgeobuf_column_type_short: case flatgeobuf_column_type_ushort: - return pgtype == INT2OID || pgtype == INT4OID || pgtype == INT8OID; - /* int32: allow widening to bigint */ + return pgtype == INT2OID; case flatgeobuf_column_type_int: - return pgtype == INT4OID || pgtype == INT8OID; - /* uint32 max exceeds INT4, must land in bigint */ + return pgtype == INT4OID; case flatgeobuf_column_type_uint: - return pgtype == INT8OID; case flatgeobuf_column_type_long: case flatgeobuf_column_type_ulong: return pgtype == INT8OID; - /* float: allow widening to double (explicit conversion handled in decode) */ case flatgeobuf_column_type_float: - return pgtype == FLOAT4OID || pgtype == FLOAT8OID; + return pgtype == FLOAT4OID; case flatgeobuf_column_type_double: return pgtype == FLOAT8OID; case flatgeobuf_column_type_string: ----------------------------------------------------------------------- Summary of changes: postgis/flatgeobuf.c | 7 ++----- postgis/lwgeom_in_flatgeobuf.c | 11 +++-------- 2 files changed, 5 insertions(+), 13 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Wed Jun 10 15:25:51 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Jun 2026 15:25:51 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.3 updated. 3.3.10-11-g856f05042 Message-ID: <20260610222551.B307018F761@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.3 has been updated via 856f0504287b904c9dca0fa8307db152704297ae (commit) from 3d8ea8159afc4a68c54098eac24a1794e360f1aa (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 856f0504287b904c9dca0fa8307db152704297ae Author: Paul Ramsey Date: Wed Jun 10 15:23:49 2026 -0700 Handle 32-bit platform in fromFlatGeobuf diff --git a/postgis/flatgeobuf.c b/postgis/flatgeobuf.c index b4047693d..7eb76701e 100644 --- a/postgis/flatgeobuf.c +++ b/postgis/flatgeobuf.c @@ -361,7 +361,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(uint32_t) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for uint value"); memcpy(&value, data + offset, sizeof(uint32_t)); - values[ci] = UInt32GetDatum(value); + values[ci] = Int64GetDatum((int64_t)(uint64_t) value); offset += sizeof(uint32_t); break; } @@ -388,10 +388,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(float) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for float value"); memcpy(&value, data + offset, sizeof(float)); - if (getBaseType(TupleDescAttr(ctx->tupdesc, ci)->atttypid) == FLOAT8OID) - values[ci] = Float8GetDatum((double) value); - else - values[ci] = Float4GetDatum(value); + values[ci] = Float4GetDatum(value); offset += sizeof(float); break; } diff --git a/postgis/lwgeom_in_flatgeobuf.c b/postgis/lwgeom_in_flatgeobuf.c index 773b50f98..9b8f53874 100644 --- a/postgis/lwgeom_in_flatgeobuf.c +++ b/postgis/lwgeom_in_flatgeobuf.c @@ -88,24 +88,19 @@ flatgeobuf_type_compatible(uint8_t fgb_type, Oid pgtype) { case flatgeobuf_column_type_bool: return pgtype == BOOLOID; - /* small integer types: allow widening into larger signed ints */ case flatgeobuf_column_type_byte: case flatgeobuf_column_type_ubyte: case flatgeobuf_column_type_short: case flatgeobuf_column_type_ushort: - return pgtype == INT2OID || pgtype == INT4OID || pgtype == INT8OID; - /* int32: allow widening to bigint */ + return pgtype == INT2OID; case flatgeobuf_column_type_int: - return pgtype == INT4OID || pgtype == INT8OID; - /* uint32 max exceeds INT4, must land in bigint */ + return pgtype == INT4OID; case flatgeobuf_column_type_uint: - return pgtype == INT8OID; case flatgeobuf_column_type_long: case flatgeobuf_column_type_ulong: return pgtype == INT8OID; - /* float: allow widening to double (explicit conversion handled in decode) */ case flatgeobuf_column_type_float: - return pgtype == FLOAT4OID || pgtype == FLOAT8OID; + return pgtype == FLOAT4OID; case flatgeobuf_column_type_double: return pgtype == FLOAT8OID; case flatgeobuf_column_type_string: ----------------------------------------------------------------------- Summary of changes: postgis/flatgeobuf.c | 7 ++----- postgis/lwgeom_in_flatgeobuf.c | 11 +++-------- 2 files changed, 5 insertions(+), 13 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Wed Jun 10 15:26:06 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 10 Jun 2026 15:26:06 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.2 updated. 3.2.10-9-g3c9ce4ec7 Message-ID: <20260610222606.60A6A18FE9D@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.2 has been updated via 3c9ce4ec7e3dee817ae8a2bc6209f5cebee7aea6 (commit) from 49f46836bd6c55167d60532b5b9b382f4b9a05d6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 3c9ce4ec7e3dee817ae8a2bc6209f5cebee7aea6 Author: Paul Ramsey Date: Wed Jun 10 15:23:49 2026 -0700 Handle 32-bit platform in fromFlatGeobuf diff --git a/postgis/flatgeobuf.c b/postgis/flatgeobuf.c index d8eea1562..6deece699 100644 --- a/postgis/flatgeobuf.c +++ b/postgis/flatgeobuf.c @@ -361,7 +361,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(uint32_t) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for uint value"); memcpy(&value, data + offset, sizeof(uint32_t)); - values[ci] = UInt32GetDatum(value); + values[ci] = Int64GetDatum((int64_t)(uint64_t) value); offset += sizeof(uint32_t); break; } @@ -388,10 +388,7 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, if (offset + sizeof(float) > size) elog(ERROR, "flatgeobuf: decode_properties: Invalid size for float value"); memcpy(&value, data + offset, sizeof(float)); - if (getBaseType(TupleDescAttr(ctx->tupdesc, ci)->atttypid) == FLOAT8OID) - values[ci] = Float8GetDatum((double) value); - else - values[ci] = Float4GetDatum(value); + values[ci] = Float4GetDatum(value); offset += sizeof(float); break; } diff --git a/postgis/lwgeom_in_flatgeobuf.c b/postgis/lwgeom_in_flatgeobuf.c index 773b50f98..9b8f53874 100644 --- a/postgis/lwgeom_in_flatgeobuf.c +++ b/postgis/lwgeom_in_flatgeobuf.c @@ -88,24 +88,19 @@ flatgeobuf_type_compatible(uint8_t fgb_type, Oid pgtype) { case flatgeobuf_column_type_bool: return pgtype == BOOLOID; - /* small integer types: allow widening into larger signed ints */ case flatgeobuf_column_type_byte: case flatgeobuf_column_type_ubyte: case flatgeobuf_column_type_short: case flatgeobuf_column_type_ushort: - return pgtype == INT2OID || pgtype == INT4OID || pgtype == INT8OID; - /* int32: allow widening to bigint */ + return pgtype == INT2OID; case flatgeobuf_column_type_int: - return pgtype == INT4OID || pgtype == INT8OID; - /* uint32 max exceeds INT4, must land in bigint */ + return pgtype == INT4OID; case flatgeobuf_column_type_uint: - return pgtype == INT8OID; case flatgeobuf_column_type_long: case flatgeobuf_column_type_ulong: return pgtype == INT8OID; - /* float: allow widening to double (explicit conversion handled in decode) */ case flatgeobuf_column_type_float: - return pgtype == FLOAT4OID || pgtype == FLOAT8OID; + return pgtype == FLOAT4OID; case flatgeobuf_column_type_double: return pgtype == FLOAT8OID; case flatgeobuf_column_type_string: ----------------------------------------------------------------------- Summary of changes: postgis/flatgeobuf.c | 7 ++----- postgis/lwgeom_in_flatgeobuf.c | 11 +++-------- 2 files changed, 5 insertions(+), 13 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Wed Jun 10 16:20:31 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 23:20:31 -0000 Subject: [PostGIS] #317: Upgrade lwerror() to return file/linenumber information in error messages In-Reply-To: <049.a598507f8a10c83cdbca15998a8d8b86@osgeo.org> References: <049.a598507f8a10c83cdbca15998a8d8b86@osgeo.org> Message-ID: <064.dbb85b385acc0ab4807c234ced97c100@osgeo.org> #317: Upgrade lwerror() to return file/linenumber information in error messages --------------------------+----------------------------- Reporter: pramsey | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: wontfix | Keywords: --------------------------+----------------------------- Changes (by pramsey): * resolution: => wontfix * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 16:23:08 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 23:23:08 -0000 Subject: [PostGIS] #892: Smarter linear location (for ST_Line_Interpolate_Point, ST_Line_Substring, ST_Line_Locate_Point) In-Reply-To: <046.3ffee974a5c0734c30256ddbfa93dac6@osgeo.org> References: <046.3ffee974a5c0734c30256ddbfa93dac6@osgeo.org> Message-ID: <061.34b84ef3b660ac0f726d3ef4658698b9@osgeo.org> #892: Smarter linear location (for ST_Line_Interpolate_Point, ST_Line_Substring, ST_Line_Locate_Point) --------------------------+----------------------------- Reporter: strk | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: wontfix | Keywords: --------------------------+----------------------------- Changes (by pramsey): * resolution: => wontfix * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 16:23:37 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 23:23:37 -0000 Subject: [PostGIS] #656: Cleanup code - deal with Doxygen warnings In-Reply-To: <050.a0742760b34e324cdddf6ba34f5d089a@osgeo.org> References: <050.a0742760b34e324cdddf6ba34f5d089a@osgeo.org> Message-ID: <065.e803ab23b9a74ce6fe95d0d350cace78@osgeo.org> #656: Cleanup code - deal with Doxygen warnings -----------------------+----------------------------- Reporter: kneufeld | Owner: pramsey Type: task | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: -----------------------+----------------------------- Changes (by pramsey): * resolution: => fixed * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 16:24:06 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 10 Jun 2026 23:24:06 -0000 Subject: [PostGIS] #679: shp2pgsql-gui should warn when SRID is not specified In-Reply-To: <048.a12042c8fbcb1f0bc48e9e2d8341f466@osgeo.org> References: <048.a12042c8fbcb1f0bc48e9e2d8341f466@osgeo.org> Message-ID: <063.a91134780f415883554a4b2cebd87bd2@osgeo.org> #679: shp2pgsql-gui should warn when SRID is not specified ----------------------------------+----------------------------- Reporter: bmmpxf | Owner: pramsey Type: enhancement | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: utils/loader-dumper | Version: 1.5.X Resolution: wontfix | Keywords: ----------------------------------+----------------------------- Changes (by pramsey): * resolution: => wontfix * status: new => closed Comment: shp2pgsql-gui is heading for deprecation -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 17:09:29 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 11 Jun 2026 00:09:29 -0000 Subject: [PostGIS] #3655: Infinite line defined by two points In-Reply-To: <054.99ac77b6c18d34c29c913699c09d80b9@osgeo.org> References: <054.99ac77b6c18d34c29c913699c09d80b9@osgeo.org> Message-ID: <069.6f7972a3d4ee035e799db14087649126@osgeo.org> #3655: Infinite line defined by two points ---------------------------+----------------------------- Reporter: stefanpetrea | Owner: pramsey Type: enhancement | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: wontfix | Keywords: infinite,line ---------------------------+----------------------------- Changes (by pramsey): * resolution: => wontfix * status: new => closed Comment: Nope. One can place lines at infinity, LineString(Inf Inf, Inf Inf) but that's not the same as an infinitely long line, which would require a special type all its own. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 17:11:28 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 11 Jun 2026 00:11:28 -0000 Subject: [PostGIS] #1498: ST_CrossProduct ? In-Reply-To: <046.fad97d3d02fd98bfb3eea6a96aa744c3@osgeo.org> References: <046.fad97d3d02fd98bfb3eea6a96aa744c3@osgeo.org> Message-ID: <061.c0f52bf09cd37c187aba6813e5f9b54b@osgeo.org> #1498: ST_CrossProduct ? --------------------------+----------------------------- Reporter: strk | Owner: pramsey Type: enhancement | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: wontfix | Keywords: --------------------------+----------------------------- Changes (by pramsey): * resolution: => wontfix * status: new => closed Comment: Seems like time has passed this by -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 18:47:15 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 11 Jun 2026 01:47:15 -0000 Subject: [PostGIS] #5746: Streamline the release process In-Reply-To: <046.b0ec60d241bdee52abfd8a752ed756cb@osgeo.org> References: <046.b0ec60d241bdee52abfd8a752ed756cb@osgeo.org> Message-ID: <061.3d468a9a1591f3087ca6336402a1a039@osgeo.org> #5746: Streamline the release process -------------------------+----------------------------- Reporter: strk | Owner: strk Type: task | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: management | Version: Resolution: duplicate | Keywords: -------------------------+----------------------------- Changes (by komzpa): * resolution: => duplicate * status: new => closed Comment: Duplicates #2736 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 10 23:31:27 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 11 Jun 2026 06:31:27 -0000 Subject: [PostGIS] #4666: Port shp2pgsql-gui to GTK 4 (was: Port shp2pgsql-gui to GTK 3) In-Reply-To: <050.0bdf2065c9f0e8eb9c89ebcf6fd11877@osgeo.org> References: <050.0bdf2065c9f0e8eb9c89ebcf6fd11877@osgeo.org> Message-ID: <065.ce3a35eb048efa8a33436a43fe6e45b5@osgeo.org> #4666: Port shp2pgsql-gui to GTK 4 ----------------------------------+----------------------------- Reporter: Bas Couwenberg | Owner: robe Type: enhancement | Status: new Priority: medium | Milestone: PostGIS Fund Me Component: utils/loader-dumper | Version: 3.0.x Resolution: | Keywords: ----------------------------------+----------------------------- Changes (by komzpa): * summary: Port shp2pgsql-gui to GTK 3 => Port shp2pgsql-gui to GTK 4 Comment: Now there's GTK4 stable -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 11 00:11:55 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 11 Jun 2026 07:11:55 -0000 Subject: [PostGIS] #4794: ST_3DIntersection does not behave correctly with line strings when no vertex is seen within the intersecion In-Reply-To: <051.4c92cc58f785b100c85003a6a2a4d1a2@osgeo.org> References: <051.4c92cc58f785b100c85003a6a2a4d1a2@osgeo.org> Message-ID: <066.8612b74a1892bb5a2b82b9f54de9b106@osgeo.org> #4794: ST_3DIntersection does not behave correctly with line strings when no vertex is seen within the intersecion ------------------------+----------------------------- Reporter: basilrabi | Owner: Lo?c Bartoletti Type: defect | Status: new Priority: medium | Milestone: PostGIS SFCGAL Component: sfcgal | Version: 3.0.x Resolution: | Keywords: ------------------------+----------------------------- Comment (by Lo?c Bartoletti): I haven't tested with older versions, but it's ok with PostGIS 3.7.0dev and SFCGAL 2.3.0dev. {{{ gis=# WITH solid AS ( SELECT CG_MakeSolid( CG_Extrude( ST_Translate( ST_Force3D( ST_GeomFromText('POLYGON ((-1 1,1 1,1 -1,-1 -1,-1 1))') ), 0, 0, -1 ), 0, 0, 2 ) ) geom ) SELECT ST_AsText(CG_3DIntersection( 'LINESTRING (-2 0 0,2 0 2)'::geometry, solid.geom )), ST_AsText(CG_3DIntersection( 'LINESTRING (-2 0 0,0 0 1,2 0 2)'::geometry, solid.geom )) FROM solid; }}} returns: {{{ st_astext | st_astext -------------------------------+------------------------------- LINESTRING Z (-1 0 0.5,0 0 1) | LINESTRING Z (-1 0 0.5,0 0 1) (1 ligne) }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 11 00:13:53 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 11 Jun 2026 07:13:53 -0000 Subject: [PostGIS] #6068: Alphashape regress failure on berrie64 In-Reply-To: <046.13872e45f711927107c1134ef7683cdf@osgeo.org> References: <046.13872e45f711927107c1134ef7683cdf@osgeo.org> Message-ID: <061.832fd38164e3e226231c6df9dc80b234@osgeo.org> #6068: Alphashape regress failure on berrie64 ----------------------+-------------------------------------- Reporter: robe | Owner: robe Type: defect | Status: new Priority: blocker | Milestone: Website Management, Bots Component: sfcgal | Version: 3.5.x Resolution: | Keywords: ----------------------+-------------------------------------- Comment (by Lo?c Bartoletti): Should be fixed in 0c06ae1dc5dbb4877ef90c79122ca88f6425b465 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 11 10:25:16 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 11 Jun 2026 17:25:16 -0000 Subject: [PostGIS] #4761: Use Github Actions to make big shiny green merge button on Github merge to gitea In-Reply-To: <046.92a2d1caa113285f24b5fcc8e55a9bbc@osgeo.org> References: <046.92a2d1caa113285f24b5fcc8e55a9bbc@osgeo.org> Message-ID: <061.e19d156eb100475331a57730f270777e@osgeo.org> #4761: Use Github Actions to make big shiny green merge button on Github merge to gitea -------------------------+-------------------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: Website Management, Bots Component: management | Version: master Resolution: wontfix | Keywords: -------------------------+-------------------------------------- Changes (by robe): * resolution: => wontfix * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 11 10:26:05 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 11 Jun 2026 17:26:05 -0000 Subject: [PostGIS] #5736: latest releases md5 mismatch In-Reply-To: <046.9bdafdd5d9494003872e9fef65f2bb95@osgeo.org> References: <046.9bdafdd5d9494003872e9fef65f2bb95@osgeo.org> Message-ID: <061.1577f8af5bcd23d0b598c54beeafaf76@osgeo.org> #5736: latest releases md5 mismatch -------------------------+-------------------------------------- Reporter: strk | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: Website Management, Bots Component: management | Version: 3.4.x Resolution: fixed | Keywords: -------------------------+-------------------------------------- Changes (by robe): * resolution: => fixed * status: reopened => closed Comment: I think this was fixed a while ago. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 11 12:15:58 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 11 Jun 2026 19:15:58 -0000 Subject: [PostGIS] #3279: ST_OffsetCurve return wrong result In-Reply-To: <046.f919178b21af65046dbeadd398d5c960@osgeo.org> References: <046.f919178b21af65046dbeadd398d5c960@osgeo.org> Message-ID: <061.fa8f46acfddbb6d4acd26e3cc3c45331@osgeo.org> #3279: ST_OffsetCurve return wrong result ----------------------+---------------------------- Reporter: MaxS | Owner: pramsey Type: defect | Status: closed Priority: low | Milestone: PostGIS GEOS Component: postgis | Version: 2.1.x Resolution: wontfix | Keywords: st_offsetcurve ----------------------+---------------------------- Changes (by pramsey): * resolution: => wontfix * status: new => closed Comment: Well the multiline does cover the whole offset curve, it's just split at one segment, so it's not exactly a deadly problem. More importantly, it's a GEOS/JTS problem, so I am going to close this and point interested parties to this GEOS issue https://github.com/libgeos/geos/issues/1444 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Fri Jun 12 09:58:36 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 12 Jun 2026 09:58:36 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-524-ge1dbdc5ff Message-ID: <20260612165836.E94541306D9@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via e1dbdc5fffeda2d1f32c82c8df0d043524788400 (commit) from 24e75f75b94ce51ce88fad7a4b9fadae12ae3ef3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e1dbdc5fffeda2d1f32c82c8df0d043524788400 Author: Regina Obe Date: Fri Jun 12 12:58:21 2026 -0400 get rid of 3.6 news in release and make room for 3.7 diff --git a/doc/release_notes.xml b/doc/release_notes.xml index 9fa7182f7..34e2034d9 100644 --- a/doc/release_notes.xml +++ b/doc/release_notes.xml @@ -3,57 +3,18 @@ Appendix Release Notes
- PostGIS 3.6.0rc2 - 2025/08/25 - This version requires PostgreSQL 12-18beta3, GEOS 3.8 or higher, and Proj 6.1+. - To take advantage of all features, GEOS 3.14+ is needed. - To take advantage of all SFCGAL features, SFCGAL 2.2+ is needed. - - Many thanks to our translation teams, in particular: - Teramoto Ikuhiro (Japanese Team) - Daniel Nylander (Swedish Team) - Dapeng Wang, Zuo Chenwei from HighGo (Chinese Team) - Denys Kovshun (Ukrainian Team) - - + PostGIS 3.7.0beta1 + 2026/06/xx + This version requires GEOS 3.10 or higher. PostgreSQL 14-19beta1 required. Proj 6.1+ required. +To take advantage of all features postgis extension features, GEOS 3.15+ is needed. +To take advantage of all postgis_sfcgal extension features SFCGAL 2.2+ is needed. Breaking Changes - #5799, make ST_TileEnvelope clips envelopes to tile plane extent (Paul Ramsey) - #5829, remove constraint checking from geometry_columns view (Paul Ramsey) - #3373, GT-255, [topology] Support for upgrading domains (Ayo Adesugba, U.S. Census Bureau) - GT-252, ST_NumGeometries/ST_GeometryN treat TIN and PolyhedralSurface as unitary geometries, - use ST_NumPatches/ST_PatchN for patch access (Lo?c Bartoletti) - #3110, GT-242, [topology] Support for bigint (Ayo Adesugba, U.S. Census Bureau) - #5359, #5897, GT-260 - [tiger_geocoder] Use @extschema:extension@ for PG >= 16 to schema qualify dependent extensions, switch to use typmod for tiger tables (Regina Obe) - - Removed / Deprecate signatures - #3110, GT-242, [topology] Support for bigint (Ayo Adesugba, U.S. Census Bureau) - #5498 Drop st_approxquantile(raster, double precision), wasn't usable as it triggered - is not unique error when used (Regina Obe) New Features - GH-803, [sfcgal] ADD CG_Simplify function (Lo?c Bartoletti) - GH-805, [sfcgal] Add M support for SFCGAL >= 1.5.0 (Lo?c Bartoletti) - GH-801, [sfcgal] ADD CG_3DAlphaWrapping function (Jean Felder) - #5894, [topology] TotalTopologySize (Sandro Santilli) - #5890, [topology] ValidateTopologyPrecision, MakeTopologyPrecise (Sandro Santilli) - #5861, [topology] Add --drop-topology switch to pgtopo_import (Sandro Santilli) - #1247, [raster] ST_AsRasterAgg (Sandro Santilli) - #5784, GT-223 Export circ_tree_distance_tree_internal for mobilitydb use - (Maxime Schoemans) - GT-228 [sfcgal] Add new functions (Scale, Translate, Rotate, Buffer 3D and - Straight Skeleton Partition) from SFCGAL 2 (Lo?c Bartoletti) - [raster] New GUC postgis.gdal_cpl_debug, enables GDAL debugging messages - and routes them into the PostgreSQL logging system. (Paul Ramsey) - #5841, Change interrupt handling to remove use of pqsignal to support PG 18 (Paul Ramsey) - Add ST_CoverageClean to edge match and gap remove polygonal - coverages (Paul Ramsey) from GEOS 3.14 (Martin Davis) - #3110, GT-242 [topology] Support for bigint (Ayo Adesugba, U.S. Census Bureau) - [raster] Add ST_ReclassExact to quickly remap values in raster (Paul Ramsey) - #3110, GT-242, [topology] Support for bigint (Ayo Adesugba, U.S. Census Bureau) +
----------------------------------------------------------------------- Summary of changes: doc/release_notes.xml | 51 ++++++--------------------------------------------- 1 file changed, 6 insertions(+), 45 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Fri Jun 12 10:13:23 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 12 Jun 2026 10:13:23 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-525-gf90aeaf71 Message-ID: <20260612171324.048DA13165B@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via f90aeaf718d1b89865cc4214a18c4e8fe7a7f43c (commit) from e1dbdc5fffeda2d1f32c82c8df0d043524788400 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit f90aeaf718d1b89865cc4214a18c4e8fe7a7f43c Author: Regina Obe Date: Fri Jun 12 13:13:18 2026 -0400 Add a para section to try to fix xml validation diff --git a/doc/release_notes.xml b/doc/release_notes.xml index 34e2034d9..7336bf631 100644 --- a/doc/release_notes.xml +++ b/doc/release_notes.xml @@ -10,11 +10,11 @@ To take advantage of all features postgis extension features, GEOS 3.15+ is need To take advantage of all postgis_sfcgal extension features SFCGAL 2.2+ is needed. Breaking Changes - + Place holder New Features - + Place holder
----------------------------------------------------------------------- Summary of changes: doc/release_notes.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Fri Jun 12 10:47:30 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 12 Jun 2026 17:47:30 -0000 Subject: [PostGIS] #6081: Test failure with SFCGAL 2.3.0 Message-ID: <050.b08fd523cc1124f6fa81d2796cea1787@osgeo.org> #6081: Test failure with SFCGAL 2.3.0 ----------------------------+----------------------------- Reporter: Bas Couwenberg | Owner: Lo?c Bartoletti Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.6.5 Component: sfcgal | Version: 3.6.x Keywords: | ----------------------------+----------------------------- Two tests fail with SFCGAL 2.3.0: {{{ /build/postgis-3.6.4+dfsg/sfcgal/regress/alphashape .. failed (diff expected obtained: /tmp/pgis_reg/test_168_diff) ----------------------------------------------------------------------------- --- ./sfcgal/regress/alphashape_expected 2026-06-08 18:28:56.000000000 +0000 +++ /tmp/pgis_reg/test_168_out 2026-06-12 17:42:48.730767282 +0000 @@ -1,4 +1,4 @@ -CG_AlphaShape_default|POLYGON((8.9 5.3,9.1 5,8.7 4.2,9 3,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,8.3 7.2,8.5 7.1,8.8 5.8,8.9 5.3)) -CG_AlphaShape_hole|POLYGON((8.9 5.3,9.1 5,8.7 4.2,9 3,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,8.3 7.2,8.5 7.1,8.8 5.8,8.9 5.3),(3.6 6.1,3.6 6.8,4 7.5,4.3 8,6 8.1,6.8 7.3,7.7 6.7,8.1 6,8.2 5.4,8.1 4.7,7.8 4.3,7.6 2.7,6.2 2.2,5.4 3.2,4.4 4.2,3.8 4.6,3.6 6.1)) -CG_OptimalAlphaShape_default|POLYGON((8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.3 6.4,8.8 5.8,8.9 5.3)) -CG_OptimalAlphaShape_hole|POLYGON((8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.3 6.4,8.8 5.8,8.9 5.3),(3.6 6.1,3.6 6.8,4 7.5,4.3 8,5 8.6,6 8.1,6.8 7.3,7.7 6.7,8.1 6,8.2 5.4,8.1 4.7,7.8 4.3,8.1 2.9,7.6 2.7,7 2,6.2 2.2,5.5 2.6,5.4 3.2,4.8 3.4,4.4 4.2,3.8 4.6,3.6 6.1)) +CG_AlphaShape_default|MULTIPOLYGON(((8.9 5.3,8.8 5.8,8.5 7.1,8.3 7.2,7.5 8.4,7.6 8.8,7.2 9.5,6.4 9.7,5.7 9.7,5.2 9.8,4.9 9.5,4.5 9,3.9 8.8,3.4 8.6,2.6 8.5,2.4 8.2,2.7 7.7,2.4 6.7,2.3 6,2.7 5.4,2.6 4.4,2.3 3.6,2.8 3.3,3 2.2,3.7 2.3,4.3 1.9,5.3 1.8,6.5 1.6,7.3 1.6,7.8 1.6,8.4 1.9,9 3,8.7 4.2,9.1 5,8.9 5.3))) +CG_AlphaShape_hole|MULTIPOLYGON(((8.9 5.3,8.8 5.8,8.5 7.1,8.3 7.2,7.5 8.4,7.6 8.8,7.2 9.5,6.4 9.7,5.7 9.7,5.2 9.8,4.9 9.5,4.5 9,3.9 8.8,3.4 8.6,2.6 8.5,2.4 8.2,2.7 7.7,2.4 6.7,2.3 6,2.7 5.4,2.6 4.4,2.3 3.6,2.8 3.3,3 2.2,3.7 2.3,4.3 1.9,5.3 1.8,6.5 1.6,7.3 1.6,7.8 1.6,8.4 1.9,9 3,8.7 4.2,9.1 5,8.9 5.3),(3.6 6.8,4 7.5,4.3 8,6 8.1,6.8 7.3,7.7 6.7,8.1 6,8.2 5.4,8.1 4.7,7.8 4.3,7.6 2.7,6.2 2.2,5.4 3.2,4.4 4.2,3.8 4.6,3.6 6.1,3.6 6.8))) +CG_OptimalAlphaShape_default|MULTIPOLYGON(((8.9 5.3,8.8 5.8,8.3 6.4,8.5 7.1,8.3 7.2,7.5 7.7,7.5 8.4,7.6 8.8,7.2 9.5,6.4 9.7,5.7 9.7,5.2 9.8,4.9 9.5,4.5 9,3.9 8.8,3.4 8.6,2.6 8.5,2.4 8.2,2.7 7.7,2.4 6.7,2.3 6,2.7 5.4,2.6 4.4,2.3 3.6,2.8 3.3,3 2.2,3.7 2.3,4.3 1.9,5.3 1.8,6.5 1.6,7.3 1.6,7.8 1.6,8.4 1.9,8.8 2.9,9 3,8.7 4.2,9.1 5,8.9 5.3))) +CG_OptimalAlphaShape_hole|MULTIPOLYGON(((8.9 5.3,8.8 5.8,8.3 6.4,8.5 7.1,8.3 7.2,7.5 7.7,7.5 8.4,7.6 8.8,7.2 9.5,6.4 9.7,5.7 9.7,5.2 9.8,4.9 9.5,4.5 9,3.9 8.8,3.4 8.6,2.6 8.5,2.4 8.2,2.7 7.7,2.4 6.7,2.3 6,2.7 5.4,2.6 4.4,2.3 3.6,2.8 3.3,3 2.2,3.7 2.3,4.3 1.9,5.3 1.8,6.5 1.6,7.3 1.6,7.8 1.6,8.4 1.9,8.8 2.9,9 3,8.7 4.2,9.1 5,8.9 5.3),(3.6 6.8,4 7.5,4.3 8,5 8.6,6 8.1,6.8 7.3,7.7 6.7,8.1 6,8.2 5.4,8.1 4.7,7.8 4.3,8.1 2.9,7.6 2.7,7 2,6.2 2.2,5.5 2.6,5.4 3.2,4.8 3.4,4.4 4.2,3.8 4.6,3.6 6.1,3.6 6.8))) ----------------------------------------------------------------------------- }}} {{{ /build/postgis-3.6.4+dfsg/sfcgal/regress/extrudestraigthskeleton .. failed (diff expected obtained: /tmp/pgis_reg/test_170_diff) ----------------------------------------------------------------------------- --- ./sfcgal/regress/extrudestraigthskeleton_expected 2026-06-08 18:28:56.000000000 +0000 +++ /tmp/pgis_reg/test_170_out 2026-06-12 17:42:49.070768120 +0000 @@ -1,4 +1,4 @@ -Extrude roof|POLYHEDRALSURFACE Z (((4 5 0,5 5 0,4 4 0,4 5 0)),((2 1 0,5 0 0,0 0 0,2 1 0)),((5 5 0,5 0 0,4 4 0,5 5 0)),((2 1 0,0 0 0,1 1 0,2 1 0)),((1 2 0,1 1 0,0 0 0,1 2 0)),((0 4 0,2 2 0,1 2 0,0 4 0)),((0 4 0,1 2 0,0 0 0,0 4 0)),((4 4 0,5 0 0,2 2 0,4 4 0)),((4 4 0,2 2 0,0 4 0,4 4 0)),((2 2 0,5 0 0,2 1 0,2 2 0)),((0.5 2.5 0.5,0 0 0,0.5 0.5 0.5,0.5 2.5 0.5)),((1 3 1,0 4 0,0.5 2.5 0.5,1 3 1)),((0.5 2.5 0.5,0 4 0,0 0 0,0.5 2.5 0.5)),((2.5 0.5 0.5,5 0 0,3.5 1.5 1.5,2.5 0.5 0.5)),((0 0 0,5 0 0,2.5 0.5 0.5,0 0 0)),((0.5 0.5 0.5,0 0 0,2.5 0.5 0.5,0.5 0.5 0.5)),((4.5 3.5 0.5,5 5 0,4.5 4.5 0.5,4.5 3.5 0.5)),((3.5 2.5 1.5,3.5 1.5 1.5,4.5 3.5 0.5,3.5 2.5 1.5)),((4.5 3.5 0.5,5 0 0,5 5 0,4.5 3.5 0.5)),((3.5 1.5 1.5,5 0 0,4.5 3.5 0.5,3.5 1.5 1.5)),((5 5 0,4 5 0,4.5 4.5 0.5,5 5 0)),((4.5 4.5 0.5,4 4 0,4.5 3.5 0.5,4.5 4.5 0.5)),((4.5 4.5 0.5,4 5 0,4 4 0,4.5 4.5 0.5)),((3 3 1,0 4 0,1 3 1,3 3 1)),((3.5 2.5 1.5,4.5 3.5 0.5,3 3 1,3.5 2.5 1.5)),((3 3 1,4 4 0,0 4 0,3 3 1)),((4.5 3.5 0.5,4 4 0,3 3 1,4.5 3.5 0.5)),((2 1 0,1 1 0,0.5 0.5 0.5,2 1 0)),((2.5 0.5 0.5,2 1 0,0.5 0.5 0.5,2.5 0.5 0.5)),((1 1 0,1 2 0,0.5 2.5 0.5,1 1 0)),((0.5 0.5 0.5,1 1 0,0.5 2.5 0.5,0.5 0.5 0.5)),((1 3 1,2 2 0,3 3 1,1 3 1)),((0.5 2.5 0.5,1 2 0,1 3 1,0.5 2.5 0.5)),((1 3 1,1 2 0,2 2 0,1 3 1)),((2 2 0,2 1 0,2.5 0.5 0.5,2 2 0)),((3.5 2.5 1.5,3 3 1,3.5 1.5 1.5,3.5 2.5 1.5)),((3.5 1.5 1.5,2 2 0,2.5 0.5 0.5,3.5 1.5 1.5)),((3 3 1,2 2 0,3.5 1.5 1.5,3 3 1))) -Extrude building and roof|t +Extrude roof|POLYHEDRALSURFACE Z (((4 5 0,5 5 0,5 0 0,0 0 0,0 4 0,4 4 0,4 5 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0)),((0 4 0,0 0 0,0.5 0.5 0.5,0.5 2.5 0.5,1 3 1,0 4 0)),((0 0 0,5 0 0,3.5 1.5 1.5,2.5 0.5 0.5,0.5 0.5 0.5,0 0 0)),((5 0 0,5 5 0,4.5 4.5 0.5,4.5 3.5 0.5,3.5 2.5 1.5,3.5 1.5 1.5,5 0 0)),((5 5 0,4 5 0,4.5 4.5 0.5,5 5 0)),((4 5 0,4 4 0,4.5 3.5 0.5,4.5 4.5 0.5,4 5 0)),((4 4 0,0 4 0,1 3 1,3 3 1,3.5 2.5 1.5,4.5 3.5 0.5,4 4 0)),((2 1 0,1 1 0,0.5 0.5 0.5,2.5 0.5 0.5,2 1 0)),((1 1 0,1 2 0,0.5 2.5 0.5,0.5 0.5 0.5,1 1 0)),((1 2 0,2 2 0,3 3 1,1 3 1,0.5 2.5 0.5,1 2 0)),((2 2 0,2 1 0,2.5 0.5 0.5,3.5 1.5 1.5,3.5 2.5 1.5,3 3 1,2 2 0))) +Extrude building and roof|f Empty building and roof|POLYHEDRALSURFACE EMPTY Empty roof|POLYHEDRALSURFACE EMPTY ----------------------------------------------------------------------------- }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Fri Jun 12 11:29:52 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 12 Jun 2026 11:29:52 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-526-gc7ae53a03 Message-ID: <20260612182954.D3EBF1322DE@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via c7ae53a031b86aaa1a4c57a9affbc8693ea48c6a (commit) from f90aeaf718d1b89865cc4214a18c4e8fe7a7f43c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c7ae53a031b86aaa1a4c57a9affbc8693ea48c6a Author: Sandro Santilli Date: Fri Jun 12 20:29:40 2026 +0200 Add a README about what skills are diff --git a/doc/skills/README.md b/doc/skills/README.md new file mode 100644 index 000000000..7ddb589ca --- /dev/null +++ b/doc/skills/README.md @@ -0,0 +1,6 @@ +# AI Agents skills + +Files in this directory are meant to be used by AI agents. + +Skills are a standardized way to give AI agents new capabilities and +expertise, read more about it on https://agentskills.io ----------------------------------------------------------------------- Summary of changes: doc/skills/README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/skills/README.md hooks/post-receive -- PostGIS From git at osgeo.org Fri Jun 12 16:58:48 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 12 Jun 2026 16:58:48 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-528-gbea3ec551 Message-ID: <20260612235849.1F39F13715D@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via bea3ec551bbf119d2d7663b11b0ab5632c093233 (commit) via 19662fc34a6bc4997a3019da981d27a49e6bf86f (commit) from c7ae53a031b86aaa1a4c57a9affbc8693ea48c6a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit bea3ec551bbf119d2d7663b11b0ab5632c093233 Author: Regina Obe Date: Fri Jun 12 19:58:14 2026 -0400 Update pot for translation diff --git a/doc/po/templates/postgis-manual.pot b/doc/po/templates/postgis-manual.pot index 2cd6f8083..49a8f4e11 100644 --- a/doc/po/templates/postgis-manual.pot +++ b/doc/po/templates/postgis-manual.pot @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n" -"POT-Creation-Date: 2025-11-13 16:23+0000\n" +"POT-Creation-Date: 2026-06-12 20:29+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3156,6 +3156,25 @@ msgstr "" msgid ", , " msgstr "" +#. Tag: refpurpose +#, no-c-format +msgid "" +"Find pairs of topology vertex/segment that are closer than tolerated distance" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Returns a relation in which each tuple is a pair of vertex/segment where the " +"vertex is NOT an endpoint of the segment but the distance between them is " +"below the given tolerance." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "Availability: 3.7" +msgstr "" + #. Tag: title #, no-c-format msgid "Topology Processing" @@ -7591,7 +7610,7 @@ msgstr "" #, no-c-format msgid "" "Return the 1-based Nth element geometry of an input geometry which is a " -"GEOMETRYCOLLECTION, MULTIPOINT, MULTILINESTRING, MULTICURVE, MULTI)POLYGON, " +"GEOMETRYCOLLECTION, MULTIPOINT, MULTILINESTRING, MULTICURVE, MULTIPOLYGON, " "or POLYHEDRALSURFACE. Otherwise, returns NULL." msgstr "" @@ -8234,8 +8253,8 @@ msgstr "" #, no-c-format msgid "" "Index is 1-based as for OGC specs since version 0.8.0. Backward indexing " -"(negative index) is not in OGC Previous versions implemented this as 0-based " -"instead." +"(negative index) is not in OGC. Previous versions implemented this as 0-" +"based instead." msgstr "" #. Tag: para @@ -9245,6 +9264,46 @@ msgid "" "linkend=\"ST_ClusterWithinWin\"/>" msgstr "" +#. Tag: refpurpose +#, no-c-format +msgid "" +"Window function that returns a tree id for each input geometry, clustering " +"input geometries into connected trees using the Minimum Spanning Tree " +"algorithm." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"A window function that builds connected graphs of line strings based on the " +"Minimum Spanning Tree (MST) of the input geometries. The return value is the " +"cluster number that the geometry argument participates in, or zero if it is " +"not part of the minimum tree." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"The Minimum Spanning Tree connects all geometries " +"in the window partition such that the total length of the connecting lines " +"is minimized. If the graph is not fully connected (e.g. infinite distance " +"between some geometries), it produces a Minimum Spanning Forest, and each " +"connected component is assigned a unique tree ID." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "Requires GEOS >= 3.15.0" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +", , " +msgstr "" + #. Tag: refpurpose #, no-c-format msgid "" @@ -10700,6 +10759,52 @@ msgid "" ", , " msgstr "" +#. Tag: refpurpose +#, no-c-format +msgid "Computes the unique edges of a polygonal coverage." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Returns a MultiLineString representing the unique edges of a polygonal " +"coverage. A polygonal coverage is a set of non-overlapping polygons where " +"adjacent polygons have matching vertices along shared edges." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"The edgetype parameter can be used to select which " +"edges are returned:" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "0 (ALL) - all unique edges (default)" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"1 (EXTERIOR) - only exterior edges (non-" +"shared)" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"2 (INTERIOR) - only interior edges " +"(shared)" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +", , " +msgstr "" + #. Tag: refpurpose #, no-c-format msgid "" @@ -14147,6 +14252,36 @@ msgid "" ", , " msgstr "" +#. Tag: refpurpose +#, no-c-format +msgid "" +"Returns the interpolated measure of a geometry closest to a point in 3D." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Returns the interpolated measure value of a linear ZM geometry at the " +"location closest to the given point, using 3D (XYZ) distance for the " +"projection. Use this function when the geometry has significant Z variation, " +"such as flight trajectories, where " +"would give incorrect results by ignoring the Z dimension." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"The line must have both Z and M dimensions. The point should have a Z " +"dimension." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +", , , " +"" +msgstr "" + #. Tag: refpurpose #, no-c-format msgid "Interpolates measures along a linear geometry." @@ -14528,7 +14663,7 @@ msgid "" "Return area square feet and transform to Massachusetts state plane meters " "(EPSG:26986) to get square meters. Note this is in square feet because 2249 " "is Massachusetts State Plane Feet and transformed area is in square meters " -"since EPSG:26986 is state plane Massachusetts meters" +"since EPSG:26986 is state plane Massachusetts meters." msgstr "" #. Tag: para @@ -15255,7 +15390,7 @@ msgstr "" #. Tag: para #, no-c-format msgid "" -"Calculates the length or perimeter of a geometry on an ellipsoid. This is " +"Calculates the length or perimeter of a geometry on a spheroid. This is " "useful if the coordinates of the geometry are in longitude/latitude and a " "length is desired without reprojection. The spheroid is specified by a text " "value as follows:" @@ -18372,14 +18507,15 @@ msgstr "" #. Tag: title #, no-c-format -msgid "Examples: 2.5Dish" +msgid "Examples: 2.5D geometries" msgstr "" #. Tag: para #, no-c-format msgid "" -"Note this is not a true intersection, compare to the same example using " -"." +"Note this is not a true 3D intersection. It uses 2.5D geometries (geometries " +"with Z ordinates, but where calculations are performed in 2D). Compare to " +"the same example using ." msgstr "" #. Tag: para @@ -18861,8 +18997,9 @@ msgstr "" #, no-c-format msgid "" ", , , , , , " +"linkend=\"ST_Collect\"/>, , , , " msgstr "" #. Tag: title @@ -19311,6 +19448,86 @@ msgid "" "linkend=\"ST_SimplifyVW\"/>" msgstr "" +#. Tag: refpurpose +#, no-c-format +msgid "" +"Returns a smoothed version of a geometry, using the Catmull-Rom spline " +"algorithm" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Smoothes a linear or polygonal geometry using the Catmull-Rom " +"spline algorithm. Unlike , " +"this is an interpolating spline: the output curve " +"passes through every original vertex. Between each pair of consecutive " +"original vertices, nSegments - 1 new intermediate points " +"are inserted." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"The nSegments parameter controls the density of the " +"output. With nSegments = 5 (the default), each original " +"span is divided into 5 sub-segments (inserting 4 new points per span). The " +"minimum value is 2." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"At least 4 input vertices are required to apply smoothing; geometries with " +"fewer vertices are returned unchanged. Points and multipoints are always " +"returned unchanged." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"The output vertex count grows as 1 + (N-1) * nSegments " +"for open lines, and 1 + N * nSegments for closed rings, " +"where N is the number of input vertices. For large geometries, use a " +"simplification function on the result to reduce the number of points (see " +", and )." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "Smoothing a 4-point collinear line with default nSegments=5:" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "Smoothing a Polygon using nSegments = 5 and 10:" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "nSegments = 5" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "nSegments = 10" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "Smoothing a LineString using nSegments = 5 and 10:" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +", , , " +msgstr "" + #. Tag: refpurpose #, no-c-format msgid "" @@ -30192,6 +30409,24 @@ msgid "" "CG_StraightSkeleton (slower case)." msgstr "" +#. Tag: para +#, no-c-format +msgid "" +"When projected is true, free endpoints " +"of the medial axis are extended to reach the polygon boundary (projected " +"medial axis). Requires SFCGAL 2.3.0+. When built against an older SFCGAL " +"version, a notice is emitted and the non-projected result is returned " +"instead." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Availability: 3.7.0 - projected parameter. Requires " +"SFCGAL >= 2.3.0 for projected result; falls back to non-projected with a " +"notice on older versions." +msgstr "" + #. Tag: para #, no-c-format msgid "A polygon and its approximate medial axis" @@ -30202,6 +30437,215 @@ msgstr "" msgid ", " msgstr "" +#. Tag: refpurpose +#, no-c-format +msgid "Generate a flat (box) roof from a footprint polygon." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Generate a flat (box-shaped) roof as a 3D PolyhedralSurface Z from a 2D footprint polygon. The roof height above the ground plane " +"is given by height (default 3.0)." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "Availability: 3.7.0 - requires SFCGAL >= 2.3.0." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +", , , " +msgstr "" + +#. Tag: refpurpose +#, no-c-format +msgid "Generate a hipped roof from a footprint polygon." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Generate a hipped roof as a 3D PolyhedralSurface Z from a " +"2D footprint polygon. All sides slope upward to meet at a ridge or apex. The " +"roof height is given by height (default 3.0)." +msgstr "" + +#. Tag: refpurpose +#, no-c-format +msgid "Generate a gable roof from a footprint polygon." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Generate a gable roof as a 3D PolyhedralSurface Z from a " +"2D footprint polygon. Two opposite sides are vertical gable ends; the other " +"two sides slope to a horizontal ridge. height sets the " +"ridge height above the ground (default 3.0) and slope_angle controls the pitch in degrees (default 30.0). The SRID of the input " +"geometry is preserved." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +", , , " +msgstr "" + +#. Tag: refpurpose +#, no-c-format +msgid "Generate a skillion (single-slope) roof from a footprint polygon." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Generate a skillion (single-slope, shed-style) roof as a 3D " +"PolyhedralSurface Z from a 2D footprint polygon. The " +"entire roof surface slopes in one direction. height sets " +"the maximum ridge height (default 3.0), slope_angle sets " +"the pitch in degrees (default 30.0), and primary_edge_index selects which polygon edge defines the high side (0-based, default " +"0)." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"When the combination of height and slope_angle would cause a side wall to vanish (the slope reaches the far edge " +"before the full height is achieved), that face is omitted from the result. " +"This means the number of output patches can vary depending on the parameters " +"? a lower height relative to the footprint depth produces more faces than a " +"taller, steeper configuration." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Height 2.0 produces 6 faces (all walls present); height 4.0 produces 5 faces " +"(one side wall is filtered out because the slope reaches the far edge before " +"the full height)." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +", , , " +msgstr "" + +#. Tag: refpurpose +#, no-c-format +msgid "Generate a roof of the requested type from a footprint polygon." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Generate a roof as a 3D PolyhedralSurface Z from a 2D " +"footprint polygon. The roof_type parameter selects the " +"roof style (default 'HIPPED'):" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "FLAT ? flat box roof." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "HIPPED ? hipped roof (all sides slope to apex)." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"GABLE ? gable roof (two sloping sides, two vertical ends)." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "SKILLION ? single-slope (shed) roof." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"height sets the roof height (default 3.0), " +"slope_angle sets the pitch in degrees (default 30.0), and " +"primary_edge_index selects the reference edge for " +"skillion roofs (default 0)." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +", , , " +msgstr "" + +#. Tag: refpurpose +#, no-c-format +msgid "Repair an invalid polygon or multipolygon." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"Repair an invalid polygon or multipolygon using CGAL's 2D Polygon Repair " +"algorithm. Returns a MultiPolygon." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "The rule parameter controls the repair strategy:" +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"EVEN_ODD (default) ? areas covered an odd number of times " +"are kept. Available with CGAL 6.0+." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"NON_ZERO ? areas with non-zero winding number are kept. " +"Requires CGAL 6.1+." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"UNION ? union of all input polygons. Requires CGAL 6.1+." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "" +"INTERSECTION ? intersection of all input polygons. " +"Requires CGAL 6.1+." +msgstr "" + +#. Tag: para +#, no-c-format +msgid "Availability: 3.7.0 - requires SFCGAL >= 2.3.0 and CGAL >= 6.0." +msgstr "" + +#. Tag: para +#, no-c-format +msgid ", " +msgstr "" + #. Tag: refpurpose #, no-c-format msgid "" @@ -32882,45 +33326,21 @@ msgstr "" #. Tag: title #, no-c-format -msgid "PostGIS 3.6.0rc2" +msgid "PostGIS 3.7.0beta1" msgstr "" #. Tag: para #, no-c-format -msgid "2025/08/25" +msgid "2026/06/xx" msgstr "" #. Tag: para #, no-c-format msgid "" -"This version requires PostgreSQL 12-18beta3, GEOS 3.8 or higher, and Proj " -"6.1+. To take advantage of all features, GEOS 3.14+ is needed. To take " -"advantage of all SFCGAL features, SFCGAL 2.2+ is needed." -msgstr "" - -#. Tag: para -#, no-c-format -msgid "Many thanks to our translation teams, in particular:" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "Teramoto Ikuhiro (Japanese Team)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "Daniel Nylander (Swedish Team)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "Dapeng Wang, Zuo Chenwei from HighGo (Chinese Team)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "Denys Kovshun (Ukrainian Team)" +"This version requires GEOS 3.10 or higher. PostgreSQL 14-19beta1 required. " +"Proj 6.1+ required. To take advantage of all features postgis extension " +"features, GEOS 3.15+ is needed. To take advantage of all postgis_sfcgal " +"extension features SFCGAL 2.2+ is needed." msgstr "" #. Tag: title @@ -32930,68 +33350,7 @@ msgstr "" #. Tag: para #, no-c-format -msgid "" -"#5799, make ST_TileEnvelope clips envelopes to tile plane extent (Paul " -"Ramsey)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#5829, remove constraint checking from geometry_columns view (Paul Ramsey)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#3373, GT-255, [topology] Support for upgrading domains (Ayo " -"Adesugba, U.S. Census Bureau)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"GT-252, ST_NumGeometries/ST_GeometryN treat TIN and " -"PolyhedralSurface as unitary geometries, use ST_NumPatches/ST_PatchN for " -"patch access (Lo?c Bartoletti)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#3110, GT-242, [topology] Support for bigint (Ayo Adesugba, U.S. " -"Census Bureau)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#5359, #5897, GT-260 [tiger_geocoder] Use @extschema:" -"extension@ for PG >= 16 to schema qualify dependent extensions, switch to " -"use typmod for tiger tables (Regina Obe)" -msgstr "" - -#. Tag: title -#, no-c-format -msgid "Removed / Deprecate signatures" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#5498 " -"Drop st_approxquantile(raster, double precision), wasn't usable as it " -"triggered is not unique error when used (Regina Obe)" +msgid "Place holder" msgstr "" #. Tag: title @@ -32999,112 +33358,6 @@ msgstr "" msgid "New Features" msgstr "" -#. Tag: para -#, no-c-format -msgid "" -"GH-803, [sfcgal] ADD CG_Simplify function (Lo?c Bartoletti)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"GH-805, [sfcgal] Add M support for SFCGAL >= 1.5.0 (Lo?c Bartoletti)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"GH-801, [sfcgal] ADD CG_3DAlphaWrapping function (Jean Felder)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#5894, [topology] TotalTopologySize (Sandro Santilli)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#5890, [topology] ValidateTopologyPrecision, MakeTopologyPrecise (Sandro " -"Santilli)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#5861, [topology] Add --drop-topology switch to pgtopo_import (Sandro " -"Santilli)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#1247, [raster] ST_AsRasterAgg (Sandro Santilli)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#5784, GT-223 Export circ_tree_distance_tree_internal for " -"mobilitydb use (Maxime Schoemans)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"GT-228 [sfcgal] Add new functions (Scale, Translate, " -"Rotate, Buffer 3D and Straight Skeleton Partition) from SFCGAL 2 (Lo?c " -"Bartoletti)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"[raster] New GUC postgis.gdal_cpl_debug, enables GDAL debugging messages and " -"routes them into the PostgreSQL logging system. (Paul Ramsey)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#5841, Change interrupt handling to remove use of pqsignal to support PG 18 " -"(Paul Ramsey)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"Add ST_CoverageClean to edge match and gap remove polygonal coverages (Paul " -"Ramsey) from GEOS 3.14 (Martin Davis)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"#3110, GT-242 [topology] Support for bigint (Ayo Adesugba, U.S. " -"Census Bureau)" -msgstr "" - -#. Tag: para -#, no-c-format -msgid "" -"[raster] Add ST_ReclassExact to quickly remap values in raster (Paul Ramsey)" -msgstr "" - #. Tag: title #, no-c-format msgid "Reporting Problems" @@ -33298,7 +33551,8 @@ msgid "" "geometry value, they must be defined for each point in the geometry. If a " "geometry has Z or M ordinates the coordinate " "dimension is 3D; if it has both Z and M the coordinate dimension " -"is 4D." +"is 4D. The coordinate dimension is at least 2, because every geometry has at " +"least X and Y coordinates." msgstr "" #. Tag: para @@ -33320,8 +33574,8 @@ msgstr "" msgid "" "The geometry dimension is a property of " "geometry types. Point types have dimension 0, linear types have dimension 1, " -"and polygonal types have dimension 2. Collections have the dimension of the " -"maximum element dimension." +"polygonal types have dimension 2, and solid types have dimension 3. " +"Collections have the dimension of the maximum element dimension." msgstr "" #. Tag: para @@ -33352,7 +33606,9 @@ msgid "" "role=\"bold\">boundary and exterior are defined for each geometry type. Geometries are topologically " "closed, so they always contain their boundary. The boundary is a geometry of " -"dimension one less than that of the geometry itself." +"dimension one less than that of the geometry itself. For example, the " +"boundary of a Polygon is its rings (LineStrings), the boundary of a " +"LineString is its endpoints (Points), and the boundary of a Point is empty." msgstr "" #. Tag: para @@ -33360,7 +33616,7 @@ msgstr "" msgid "" "The OGC geometry model defines validity rules for each geometry type. These " "rules ensure that geometry values represents realistic situations (e.g. it " -"is possible to specify a polygon with a hole lying outside the shell, but " +"is possible to specify a polygon with a hole lying outside its shell, but " "this makes no sense geometrically and is thus invalid). PostGIS also allows " "storing and manipulating invalid geometry values. This allows detecting and " "fixing them if needed. See " @@ -33452,7 +33708,10 @@ msgstr "" #, no-c-format msgid "" "A MultiPolygon is a collection of non-overlapping, non-adjacent Polygons. " -"Polygons in the collection may touch only at a finite number of points." +"Polygons in the collection may touch only at a finite number of points. (Two " +"polygons are adjacent if they share an edge. They touch if they share only " +"points or edges on their boundaries). For more details on MultiPolygon " +"validity, see ." msgstr "" #. Tag: title @@ -33781,7 +34040,7 @@ msgid "" "The geometry data type is opaque, " "which means that all access is done via invoking functions on geometry " "values. Functions allow creating geometry objects, accessing or updating all " -"internal fields, and compute new geometry values. PostGIS supports all the " +"internal fields, and computing new geometry values. PostGIS supports all the " "functions specified in the OGC Simple feature access - Part 2: SQL " "option (SFS) specification, as well many others. See does not provide the necessary spatial " -"filter, since for linear features it returns true only " -"where they cross at a point." +"point, but in a line (perhaps to validate a business rule such as ensuring " +"that no two different roads share a common segment). In this case does not provide the necessary spatial filter, " +"since for linear features it returns true only where they " +"cross at a point." msgstr "" #. Tag: para @@ -37830,9 +38094,9 @@ msgstr "" #, no-c-format msgid "" "If the optional gridSize parameter is given (GEOS-3.9.0 or " -"higher required), all result vertices are guaranteed to fall on a grid of " -"the specified size. For the operation to give predictable results all the " -"input vertices must fall already on the specified grid, see ." msgstr "" commit 19662fc34a6bc4997a3019da981d27a49e6bf86f Author: Regina Obe Date: Fri Jun 12 13:22:11 2026 -0400 Flip winnie to by default build with sfcgal 2.3.0 diff --git a/ci/winnie/winnie_common.sh b/ci/winnie/winnie_common.sh index 49f4050b9..1739cd7d7 100644 --- a/ci/winnie/winnie_common.sh +++ b/ci/winnie/winnie_common.sh @@ -15,7 +15,7 @@ if [[ "${OVERRIDE}" == '' ]] ; then export GEOS_VER=3.13.1 export GDAL_VER=3.9.2 export PROJ_VER=8.2.1 - export SFCGAL_VER=2.1.0 + export SFCGAL_VER=2.3.0 export CGAL_VER=6.0.1 export ICON_VER=1.17 export ZLIB_VER=1.2.13 ----------------------------------------------------------------------- Summary of changes: ci/winnie/winnie_common.sh | 2 +- doc/po/templates/postgis-manual.pot | 716 ++++++++++++++++++++++++------------ 2 files changed, 491 insertions(+), 227 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Fri Jun 12 20:53:21 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 12 Jun 2026 20:53:21 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-530-g73a463b19 Message-ID: <20260613035321.52A6C13AE8B@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 73a463b191c7f15134aa54478dc652fff87acdfb (commit) from 7ebe64f2707eb62bf00a366d91b67c8aa8642d00 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 73a463b191c7f15134aa54478dc652fff87acdfb Author: Sandro Santilli Date: Sat Jun 13 05:53:05 2026 +0200 Add a note about libgmp new requirement diff --git a/NEWS b/NEWS index 17b07b97f..f3ba00e0f 100644 --- a/NEWS +++ b/NEWS @@ -7,15 +7,17 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.2+ is needed * Breaking Changes * + - The GNU multiprecision arithmetic library ( https://gmplib.org/ ) + is now required at build-time and for using PostGIS Topology. - #5688, [topology] topology building functions now interpret tolerance 0 (old default) to really mean 0 and want -1 (new default) to mean "use topology precision" (Sandro Santilli) - #6024, Remove support for PostgreSQL 12 and 13 (Regina Obe) - #6040, ST_GeoHash round trip through ST_GeomFromGeoHash (Paul Ramsey) - #6053, [address_standardizer] Extension removed and moved to - https://github.com/postgis/address_standardizer (Paul Ramsey) + https://github.com/postgis/address_standardizer (Paul Ramsey) - #6052, [tiger_geocoder] Extension removed and moved to - https://git.osgeo.org/postgis/postgis_tiger_geocoder (Regina Obe) + https://git.osgeo.org/postgis/postgis_tiger_geocoder (Regina Obe) - #6079, Remove support for GEOS < 3.10 (Sandro Santilli) * New Features * ----------------------------------------------------------------------- Summary of changes: NEWS | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Fri Jun 12 21:00:48 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 12 Jun 2026 21:00:48 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-531-g5e470c937 Message-ID: <20260613040049.54D3613B78F@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 5e470c937da451dc022ad68c0a462a5068336a89 (commit) from 73a463b191c7f15134aa54478dc652fff87acdfb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5e470c937da451dc022ad68c0a462a5068336a89 Author: Sandro Santilli Date: Sat Jun 13 06:00:10 2026 +0200 Put the gmp requirements higher, be more concise in that line diff --git a/NEWS b/NEWS index f3ba00e0f..8013bf298 100644 --- a/NEWS +++ b/NEWS @@ -1,14 +1,12 @@ PostGIS 3.7.0beta1 2026/06/xx -This version requires GEOS 3.10 or higher. PostgreSQL 14-19beta1 required. Proj 6.1+ required. +This version requires GEOS 3.10+, PostgreSQL 14-19beta1, Proj 6.1+, libgmp. To take advantage of all features postgis extension features, GEOS 3.15+ is needed. To take advantage of all postgis_sfcgal extension features SFCGAL 2.2+ is needed. * Breaking Changes * - - The GNU multiprecision arithmetic library ( https://gmplib.org/ ) - is now required at build-time and for using PostGIS Topology. - #5688, [topology] topology building functions now interpret tolerance 0 (old default) to really mean 0 and want -1 (new default) to mean "use topology precision" (Sandro Santilli) ----------------------------------------------------------------------- Summary of changes: NEWS | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Fri Jun 12 21:03:44 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 12 Jun 2026 21:03:44 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-532-gfe42b211b Message-ID: <20260613040345.2AE3413BE2F@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via fe42b211b8d4fa6aff42f7908f3f16e1aaceda8a (commit) from 5e470c937da451dc022ad68c0a462a5068336a89 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit fe42b211b8d4fa6aff42f7908f3f16e1aaceda8a Author: Sandro Santilli Date: Sat Jun 13 06:03:30 2026 +0200 Add GMP dependency in docs diff --git a/doc/installation.xml b/doc/installation.xml index 954c0d61a..02cda543a 100644 --- a/doc/installation.xml +++ b/doc/installation.xml @@ -205,6 +205,14 @@ sh autogen.sh + + + The GNU Multiple Precision Arithmetic Library (libgmp). Used to control precision of math operations in PostGIS Topology. + GMP is available for download from + https://gmplib.org/. + + + GDAL, version 3+ is preferred. This is required for raster ----------------------------------------------------------------------- Summary of changes: doc/installation.xml | 8 ++++++++ 1 file changed, 8 insertions(+) hooks/post-receive -- PostGIS From git at osgeo.org Fri Jun 12 21:13:44 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 12 Jun 2026 21:13:44 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-533-gb4fcfb694 Message-ID: <20260613041344.C15C713BA44@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via b4fcfb694122e060fadfadb02e5b32711773a0ae (commit) from fe42b211b8d4fa6aff42f7908f3f16e1aaceda8a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b4fcfb694122e060fadfadb02e5b32711773a0ae Author: Sandro Santilli Date: Sat Jun 13 06:13:21 2026 +0200 Update SFGAL dep information diff --git a/NEWS b/NEWS index 8013bf298..443712616 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,7 @@ PostGIS 3.7.0beta1 This version requires GEOS 3.10+, PostgreSQL 14-19beta1, Proj 6.1+, libgmp. To take advantage of all features postgis extension features, GEOS 3.15+ is needed. -To take advantage of all postgis_sfcgal extension features SFCGAL 2.2+ is needed. +To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed. * Breaking Changes * diff --git a/doc/installation.xml b/doc/installation.xml index 02cda543a..e337ae3ad 100644 --- a/doc/installation.xml +++ b/doc/installation.xml @@ -254,9 +254,12 @@ sh autogen.sh - SFCGAL, 1.4.1 or higher is required and 2.1+ is needed to be able to use all functionality. SFCGAL can be used to provide additional 2D and 3D advanced analysis functions to PostGIS cf . And also allow to use SFCGAL rather than GEOS for some 2D functions provided by both backends (like ST_Intersection or ST_Area, for instance). A PostgreSQL configuration variable postgis.backend allow end user to control which backend he want to use if SFCGAL is installed (GEOS by default). Nota: SFCGAL 1.2 require at least CGAL 4.3 and Boost 1.54 (cf: https://sfcgal.org) + SFCGAL, 1.4.1 or higher is required, + 2.3+ is needed to be able to use all functionality. + SFCGAL can be used to provide additional 2D and 3D advanced + analysis functions to PostGIS cf . - https://gitlab.com/sfcgal/SFCGAL/. + https://gitlab.com/sfcgal/SFCGAL/. ----------------------------------------------------------------------- Summary of changes: NEWS | 2 +- doc/installation.xml | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Fri Jun 12 23:28:44 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 12 Jun 2026 23:28:44 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-534-g2259dee51 Message-ID: <20260613062844.9685813E73F@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 2259dee51e88ca4cd9301b529dd5334f681d9f8a (commit) from b4fcfb694122e060fadfadb02e5b32711773a0ae (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 2259dee51e88ca4cd9301b529dd5334f681d9f8a Author: Sandro Santilli Date: Sat Jun 13 08:27:45 2026 +0200 Official SFCGAL page is https://sfcgal.gitlab.io/sfcgal diff --git a/README.postgis b/README.postgis index e7f0f9543..6817356cf 100644 --- a/README.postgis +++ b/README.postgis @@ -103,7 +103,7 @@ For apt-based systems you can run this command to install the below dependencies * CGAL 5+ and SFCGAL 1.4+ (Optional) needed for advanced 3D support * SFCGAL 2.1.0 is required for additional functionality. - https://gitlab.com/sfcgal/SFCGAL + https://sfcgal.gitlab.io/sfcgal * protobuf-c (Optional, Version 1.1.0 or higher) diff --git a/doc/installation.xml b/doc/installation.xml index e337ae3ad..0dc8668b3 100644 --- a/doc/installation.xml +++ b/doc/installation.xml @@ -259,7 +259,7 @@ sh autogen.sh SFCGAL can be used to provide additional 2D and 3D advanced analysis functions to PostGIS cf . - https://gitlab.com/sfcgal/SFCGAL/. + https://sfcgal.gitlab.io/sfcgal/. ----------------------------------------------------------------------- Summary of changes: README.postgis | 2 +- doc/installation.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 14 02:30:29 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 14 Jun 2026 09:30:29 -0000 Subject: [PostGIS] #6082: Debbie failing on docbook ja building Message-ID: <046.b68f8faa448a912ac9cacf070f6f6403@osgeo.org> #6082: Debbie failing on docbook ja building ---------------------------+--------------------------- Reporter: robe | Owner: robe Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.7.0 Component: documentation | Version: master Keywords: | ---------------------------+--------------------------- https://debbie.postgis.net/job/PostGIS_Make_Dist/label=debbie/7462/consoleFull {{{ 02:58:39 Build postgis-out.pdf 02:59:28 xelatex failed 02:59:28 postgis-out.tex:30067: Undefined control sequence. 02:59:28 postgis-out.tex:30067: leading text: } 02:59:28 postgis-out.tex:30067: Undefined control sequence. 02:59:28 postgis-out.tex:30067: leading text: } 02:59:29 02:59:29 A possible reason for transformation failure is invalid DocBook 02:59:29 (as reported by xmllint) 02:59:29 02:59:29 Error: xelatex compilation failed 02:59:29 make[1]: *** [../../Makefile:428: postgis-3.7.0dev-ja.pdf] Error 1 02:59:29 make[1]: Leaving directory '/var/lib/jenkins/workspace/PostGIS_Make_Dist/label/debbie/2259dee51e88ca4cd9301b529dd5334f681d9f8a/doc/po/ja' 02:59:29 make: *** [../Makefile.local:18: local-pdf-install] Error 2 02:59:29 make: Leaving directory '/var/lib/jenkins/workspace/PostGIS_Make_Dist/label/debbie/2259dee51e88ca4cd9301b529dd5334f681d9f8a/doc/po/ja' 02:59:29 Build step 'Execute shell' marked build as failure }}} Woodie hasn't registered any errors though and also tests translations. This started happening after I wiped out the old 3.6 release notes and also did an update of template. But I think the template happened after, so maybe it was the NEWS change. The english pdf is fine though so maybe it's just an out-of-sync issue with weblate. [e1dbdc5ff/git] -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Sun Jun 14 02:34:23 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 14 Jun 2026 09:34:23 -0000 Subject: [PostGIS] #6068: Alphashape regress failure on berrie64 In-Reply-To: <046.13872e45f711927107c1134ef7683cdf@osgeo.org> References: <046.13872e45f711927107c1134ef7683cdf@osgeo.org> Message-ID: <061.96fef4f746536059f8f4448d26816d59@osgeo.org> #6068: Alphashape regress failure on berrie64 ----------------------+-------------------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: blocker | Milestone: Website Management, Bots Component: sfcgal | Version: 3.5.x Resolution: fixed | Keywords: ----------------------+-------------------------------------- Changes (by robe): * resolution: => fixed * status: new => closed Comment: Yap looks good now. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Sun Jun 14 02:36:47 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 14 Jun 2026 09:36:47 -0000 Subject: [PostGIS] #6081: Test failure with SFCGAL 2.3.0 In-Reply-To: <050.b08fd523cc1124f6fa81d2796cea1787@osgeo.org> References: <050.b08fd523cc1124f6fa81d2796cea1787@osgeo.org> Message-ID: <065.a88dfeeb1b3c4d01b239b83517961678@osgeo.org> #6081: Test failure with SFCGAL 2.3.0 -----------------------------+----------------------------- Reporter: Bas Couwenberg | Owner: Lo?c Bartoletti Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.6.5 Component: sfcgal | Version: 3.6.x Resolution: | Keywords: -----------------------------+----------------------------- Comment (by robe): Did you get a chance to test this with 3.7.0dev. I think I was running into same issue with our raspberry pi ci but that seems all clear now. See #6068 So perhaps we need to backport some fixes. Although in that case, it was only failing on the CG_OpitmalAlphaShape, but we mind have fixed the other issues earlier on. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 15 00:31:56 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 15 Jun 2026 07:31:56 -0000 Subject: [PostGIS] #6081: Test failure with SFCGAL 2.3.0 In-Reply-To: <050.b08fd523cc1124f6fa81d2796cea1787@osgeo.org> References: <050.b08fd523cc1124f6fa81d2796cea1787@osgeo.org> Message-ID: <065.2f4e3d3ac224d9ff05a28fab11ff618e@osgeo.org> #6081: Test failure with SFCGAL 2.3.0 -----------------------------+----------------------------- Reporter: Bas Couwenberg | Owner: Lo?c Bartoletti Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.6.5 Component: sfcgal | Version: 3.6.x Resolution: | Keywords: -----------------------------+----------------------------- Comment (by Bas Couwenberg): Replying to [comment:1 robe]: > Did you get a chance to test this with 3.7.0dev. No, that's not in Debian. With the changes from master the build still fails: {{{ ----------------------------------------------------------------------------- --- ./sfcgal/regress/alphashape_expected 2026-06-15 07:12:23.000000000 +0000 +++ /tmp/pgis_reg/test_172_out 2026-06-15 07:15:17.155198743 +0000 @@ -1,4 +1,4 @@ CG_AlphaShape_default|MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,8.3 7.2,8.5 7.1,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6))) CG_AlphaShape_hole|MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,8.3 7.2,8.5 7.1,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6),(3.6 6.1,3.8 4.6,4.4 4.2,5.4 3.2,6.2 2.2,7.6 2.7,7.8 4.3,8.1 4.7,8.2 5.4,8.1 6,7.7 6.7,6.8 7.3,6 8.1,4.3 8,4 7.5,3.6 6.8,3.6 6.1))) -CG_OptimalAlphaShape_default|MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.3 6.4,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6))) -CG_OptimalAlphaShape_hole|MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.3 6.4,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6),(3.6 6.1,3.8 4.6,4.4 4.2,4.8 3.4,5.4 3.2,5.5 2.6,6.2 2.2,7 2,7.6 2.7,8.1 2.9,7.8 4.3,8.1 4.7,8.2 5.4,8.1 6,7.7 6.7,6.8 7.3,6 8.1,5 8.6,4.3 8,4 7.5,3.6 6.8,3.6 6.1))) +CG_OptimalAlphaShape_default|MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6))) +CG_OptimalAlphaShape_hole|MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6),(3.6 6.1,3.8 4.6,4.4 4.2,4.8 3.4,5.4 3.2,5.5 2.6,6.2 2.2,7 2,7.6 2.7,8.1 2.9,7.8 4.3,8.1 4.7,8.2 5.4,8.1 6,7.7 6.7,6.8 7.3,6 8.1,5 8.6,4.3 8,4 7.5,3.6 6.8,3.6 6.1))) ----------------------------------------------------------------------------- }}} > I think I was running into same issue with our raspberry pi ci but that seems all clear now. > > See #6068 That doesn't apply to 3.6.4 because it changes `sfcgal/regress/alphashape_components*` which doesn't exist in 3.6.x which has `sfcgal/regress/alphashape*`. > So perhaps we need to backport some fixes. Although in that case, it was only failing on the CG_OpitmalAlphaShape, but we mind have fixed the other issues earlier on. You may need to build your SFCGAL 2.3.0 with CGAL 6.2 as is the case in Debian unstable. Note that is broken on i386: https://gitlab.com/sfcgal/SFCGAL/-/work_items/326 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Tue Jun 16 10:37:51 2026 From: trac at osgeo.org (PostGIS) Date: Tue, 16 Jun 2026 17:37:51 -0000 Subject: [PostGIS] #6079: Remove support for GEOS < 3.10 In-Reply-To: <046.1ee3eb60a1909f23f10dbaa3ab1f4c0c@osgeo.org> References: <046.1ee3eb60a1909f23f10dbaa3ab1f4c0c@osgeo.org> Message-ID: <061.3426f7bb868a89429c5a25459591b752@osgeo.org> #6079: Remove support for GEOS < 3.10 ----------------------+--------------------------- Reporter: robe | Owner: strk Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.6.x Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by robe): * resolution: => fixed * status: assigned => closed Comment: No I think they are fine. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 16 11:51:50 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 16 Jun 2026 11:51:50 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-535-gc8ea8a68f Message-ID: <20260616185152.04B9C1A1E97@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via c8ea8a68f1b56b142988a8d1e61656a73f5084f5 (commit) from 2259dee51e88ca4cd9301b529dd5334f681d9f8a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c8ea8a68f1b56b142988a8d1e61656a73f5084f5 Author: Darafei Praliaskouski Date: Tue Jun 16 18:35:05 2026 +0400 Fix SFCGAL 2.3 alphashape regression output diff --git a/sfcgal/regress/alphashape.sql b/sfcgal/regress/alphashape.sql index 6f3d18fc3..15b5e47c1 100644 --- a/sfcgal/regress/alphashape.sql +++ b/sfcgal/regress/alphashape.sql @@ -4,6 +4,6 @@ SELECT 'CG_AlphaShape_hole', ST_AsText(ST_Normalize(ST_Multi(CG_AlphaShape('MultiPoint ((6.3 8.4),(7.6 8.8),(6.8 7.3),(5.3 1.8),(9.1 5),(8.1 7),(8.8 2.9),(2.4 8.2),(3.2 5.1),(3.7 2.3),(2.7 5.4),(8.4 1.9),(7.5 8.7),(4.4 4.2),(7.7 6.7),(9 3),(3.6 6.1),(3.2 6.5),(8.1 4.7),(8.8 5.8),(6.8 7.3),(4.9 9.5),(8.1 6),(8.7 5),(7.8 1.6),(7.9 2.1),(3 2.2),(7.8 4.3),(2.6 8.5),(4.8 3.4),(3.5 3.5),(3.6 4),(3.1 7.9),(8.3 2.9),(2.7 8.4),(5.2 9.8),(7.2 9.5),(8.5 7.1),(7.5 8.4),(7.5 7.7),(8.1 2.9),(7.7 7.3),(4.1 4.2),(8.3 7.2),(2.3 3.6),(8.9 5.3),(2.7 5.7),(5.7 9.7),(2.7 7.7),(3.9 8.8),(6 8.1),(8 7.2),(5.4 3.2),(5.5 2.6),(6.2 2.2),(7 2),(7.6 2.7),(8.4 3.5),(8.7 4.2),(8.2 5.4),(8.3 6.4),(6.9 8.6),(6 9),(5 8.6),(4.3 8),(3.6 7.3),(3.6 6.8),(4 7.5),(2.4 6.7),(2.3 6),(2.6 4.4),(2.8 3.3),(4 3.2),(4.3 1.9),(6.5 1.6),(7.3 1.6),(3.8 4.6),(3.1 5.9),(3.4 8.6),(4.5 9),(6.4 9.7))', allow_holes => true))),2); SELECT 'CG_OptimalAlphaShape_default', - ST_AsText(ST_Normalize(ST_Multi(CG_OptimalAlphaShape('MultiPoint ((6.3 8.4),(7.6 8.8),(6.8 7.3),(5.3 1.8),(9.1 5),(8.1 7),(8.8 2.9),(2.4 8.2),(3.2 5.1),(3.7 2.3),(2.7 5.4),(8.4 1.9),(7.5 8.7),(4.4 4.2),(7.7 6.7),(9 3),(3.6 6.1),(3.2 6.5),(8.1 4.7),(8.8 5.8),(6.8 7.3),(4.9 9.5),(8.1 6),(8.7 5),(7.8 1.6),(7.9 2.1),(3 2.2),(7.8 4.3),(2.6 8.5),(4.8 3.4),(3.5 3.5),(3.6 4),(3.1 7.9),(8.3 2.9),(2.7 8.4),(5.2 9.8),(7.2 9.5),(8.5 7.1),(7.5 8.4),(7.5 7.7),(8.1 2.9),(7.7 7.3),(4.1 4.2),(8.3 7.2),(2.3 3.6),(8.9 5.3),(2.7 5.7),(5.7 9.7),(2.7 7.7),(3.9 8.8),(6 8.1),(8 7.2),(5.4 3.2),(5.5 2.6),(6.2 2.2),(7 2),(7.6 2.7),(8.4 3.5),(8.7 4.2),(8.2 5.4),(8.3 6.4),(6.9 8.6),(6 9),(5 8.6),(4.3 8),(3.6 7.3),(3.6 6.8),(4 7.5),(2.4 6.7),(2.3 6),(2.6 4.4),(2.8 3.3),(4 3.2),(4.3 1.9),(6.5 1.6),(7.3 1.6),(3.8 4.6),(3.1 5.9),(3.4 8.6),(4.5 9),(6.4 9.7))'))),2); + ST_AsText(ST_Normalize(ST_Multi(CG_OptimalAlphaShape('MultiPoint ((6.3 8.4),(7.6 8.8),(6.8 7.3),(5.3 1.8),(9.1 5),(8.1 7),(8.8 2.9),(2.4 8.2),(3.2 5.1),(3.7 2.3),(2.7 5.4),(8.4 1.9),(7.5 8.7),(4.4 4.2),(7.7 6.7),(9 3),(3.6 6.1),(3.2 6.5),(8.1 4.7),(8.8 5.8),(6.8 7.3),(4.9 9.5),(8.1 6),(8.7 5),(7.8 1.6),(7.9 2.1),(3 2.2),(7.8 4.3),(2.6 8.5),(4.8 3.4),(3.5 3.5),(3.6 4),(3.1 7.9),(8.3 2.9),(2.7 8.4),(5.2 9.8),(7.2 9.5),(8.5 7.1),(7.5 8.4),(7.5 7.7),(8.1 2.9),(7.7 7.3),(4.1 4.2),(8.3 7.2),(2.3 3.6),(8.9 5.3),(2.7 5.7),(5.7 9.7),(2.7 7.7),(3.9 8.8),(6 8.1),(8 7.2),(5.4 3.2),(5.5 2.6),(6.2 2.2),(7 2),(7.6 2.7),(8.4 3.5),(8.7 4.2),(8.2 5.4),(8.3 6.4),(6.9 8.6),(6 9),(5 8.6),(4.3 8),(3.6 7.3),(3.6 6.8),(4 7.5),(2.4 6.7),(2.3 6),(2.6 4.4),(2.8 3.3),(4 3.2),(4.3 1.9),(6.5 1.6),(7.3 1.6),(3.8 4.6),(3.1 5.9),(3.4 8.6),(4.5 9),(6.4 9.7))'))),2) IN ('MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8, 7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6)))', 'MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.3 6.4,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6)))'); SELECT 'CG_OptimalAlphaShape_hole', - ST_AsText(ST_Normalize(ST_Multi(CG_OptimalAlphaShape('MultiPoint ((6.3 8.4),(7.6 8.8),(6.8 7.3),(5.3 1.8),(9.1 5),(8.1 7),(8.8 2.9),(2.4 8.2),(3.2 5.1),(3.7 2.3),(2.7 5.4),(8.4 1.9),(7.5 8.7),(4.4 4.2),(7.7 6.7),(9 3),(3.6 6.1),(3.2 6.5),(8.1 4.7),(8.8 5.8),(6.8 7.3),(4.9 9.5),(8.1 6),(8.7 5),(7.8 1.6),(7.9 2.1),(3 2.2),(7.8 4.3),(2.6 8.5),(4.8 3.4),(3.5 3.5),(3.6 4),(3.1 7.9),(8.3 2.9),(2.7 8.4),(5.2 9.8),(7.2 9.5),(8.5 7.1),(7.5 8.4),(7.5 7.7),(8.1 2.9),(7.7 7.3),(4.1 4.2),(8.3 7.2),(2.3 3.6),(8.9 5.3),(2.7 5.7),(5.7 9.7),(2.7 7.7),(3.9 8.8),(6 8.1),(8 7.2),(5.4 3.2),(5.5 2.6),(6.2 2.2),(7 2),(7.6 2.7),(8.4 3.5),(8.7 4.2),(8.2 5.4),(8.3 6.4),(6.9 8.6),(6 9),(5 8.6),(4.3 8),(3.6 7.3),(3.6 6.8),(4 7.5),(2.4 6.7),(2.3 6),(2.6 4.4),(2.8 3.3),(4 3.2),(4.3 1.9),(6.5 1.6),(7.3 1.6),(3.8 4.6),(3.1 5.9),(3.4 8.6),(4.5 9),(6.4 9.7))', allow_holes => true))),2); + ST_AsText(ST_Normalize(ST_Multi(CG_OptimalAlphaShape('MultiPoint ((6.3 8.4),(7.6 8.8),(6.8 7.3),(5.3 1.8),(9.1 5),(8.1 7),(8.8 2.9),(2.4 8.2),(3.2 5.1),(3.7 2.3),(2.7 5.4),(8.4 1.9),(7.5 8.7),(4.4 4.2),(7.7 6.7),(9 3),(3.6 6.1),(3.2 6.5),(8.1 4.7),(8.8 5.8),(6.8 7.3),(4.9 9.5),(8.1 6),(8.7 5),(7.8 1.6),(7.9 2.1),(3 2.2),(7.8 4.3),(2.6 8.5),(4.8 3.4),(3.5 3.5),(3.6 4),(3.1 7.9),(8.3 2.9),(2.7 8.4),(5.2 9.8),(7.2 9.5),(8.5 7.1),(7.5 8.4),(7.5 7.7),(8.1 2.9),(7.7 7.3),(4.1 4.2),(8.3 7.2),(2.3 3.6),(8.9 5.3),(2.7 5.7),(5.7 9.7),(2.7 7.7),(3.9 8.8),(6 8.1),(8 7.2),(5.4 3.2),(5.5 2.6),(6.2 2.2),(7 2),(7.6 2.7),(8.4 3.5),(8.7 4.2),(8.2 5.4),(8.3 6.4),(6.9 8.6),(6 9),(5 8.6),(4.3 8),(3.6 7.3),(3.6 6.8),(4 7.5),(2.4 6.7),(2.3 6),(2.6 4.4),(2.8 3.3),(4 3.2),(4.3 1.9),(6.5 1.6),(7.3 1.6),(3.8 4.6),(3.1 5.9),(3.4 8.6),(4.5 9),(6.4 9.7))', allow_holes => true))),2) IN ('MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6),(3.6 6.1,3.8 4.6,4.4 4.2,4.8 3.4,5.4 3.2,5.5 2.6,6.2 2.2,7 2,7.6 2.7,8.1 2.9,7.8 4.3,8.1 4.7,8.2 5.4,8.1 6,7.7 6.7,6.8 7.3,6 8.1,5 8.6,4.3 8,4 7.5,3.6 6.8,3.6 6.1)))', 'MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.3 6.4,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6),(3.6 6.1,3.8 4.6,4.4 4.2,4.8 3.4,5.4 3.2,5.5 2.6,6.2 2.2,7 2,7.6 2.7,8.1 2.9,7.8 4.3,8.1 4.7,8.2 5.4,8.1 6,7.7 6.7,6.8 7.3,6 8.1,5 8.6,4.3 8,4 7.5,3.6 6.8,3.6 6.1)))'); diff --git a/sfcgal/regress/alphashape_expected b/sfcgal/regress/alphashape_expected index 6f24a3db0..4361c47ee 100644 --- a/sfcgal/regress/alphashape_expected +++ b/sfcgal/regress/alphashape_expected @@ -1,4 +1,4 @@ CG_AlphaShape_default|MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,8.3 7.2,8.5 7.1,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6))) CG_AlphaShape_hole|MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,8.3 7.2,8.5 7.1,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6),(3.6 6.1,3.8 4.6,4.4 4.2,5.4 3.2,6.2 2.2,7.6 2.7,7.8 4.3,8.1 4.7,8.2 5.4,8.1 6,7.7 6.7,6.8 7.3,6 8.1,4.3 8,4 7.5,3.6 6.8,3.6 6.1))) -CG_OptimalAlphaShape_default|MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.3 6.4,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6))) -CG_OptimalAlphaShape_hole|MULTIPOLYGON(((2.3 3.6,2.6 4.4,2.7 5.4,2.3 6,2.4 6.7,2.7 7.7,2.4 8.2,2.6 8.5,3.4 8.6,3.9 8.8,4.5 9,4.9 9.5,5.2 9.8,5.7 9.7,6.4 9.7,7.2 9.5,7.6 8.8,7.5 8.4,7.5 7.7,8.3 7.2,8.5 7.1,8.3 6.4,8.8 5.8,8.9 5.3,9.1 5,8.7 4.2,9 3,8.8 2.9,8.4 1.9,7.8 1.6,7.3 1.6,6.5 1.6,5.3 1.8,4.3 1.9,3.7 2.3,3 2.2,2.8 3.3,2.3 3.6),(3.6 6.1,3.8 4.6,4.4 4.2,4.8 3.4,5.4 3.2,5.5 2.6,6.2 2.2,7 2,7.6 2.7,8.1 2.9,7.8 4.3,8.1 4.7,8.2 5.4,8.1 6,7.7 6.7,6.8 7.3,6 8.1,5 8.6,4.3 8,4 7.5,3.6 6.8,3.6 6.1))) +CG_OptimalAlphaShape_default|t +CG_OptimalAlphaShape_hole|t ----------------------------------------------------------------------- Summary of changes: sfcgal/regress/alphashape.sql | 4 ++-- sfcgal/regress/alphashape_expected | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Tue Jun 16 12:00:01 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 16 Jun 2026 12:00:01 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-537-gadef2f6bd Message-ID: <20260616190001.C625C1A15B3@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via adef2f6bde7696bdb7f02198e02c02916b3a6da7 (commit) via 974f241e4eec1c37f23ac9a8eae4a915f36d0b66 (commit) from c8ea8a68f1b56b142988a8d1e61656a73f5084f5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit adef2f6bde7696bdb7f02198e02c02916b3a6da7 Merge: c8ea8a68f 974f241e4 Author: Darafei Praliaskouski Date: Tue Jun 16 22:57:58 2026 +0400 Merge pull request #879 from ProjectMutilation/fix-string-allocation-size raster: Fix memory overallocation commit 974f241e4eec1c37f23ac9a8eae4a915f36d0b66 Author: Maksim Korotkov Date: Mon Jun 15 18:16:13 2026 +0300 raster: Fix memory overallocation Replace sizeof(char *) with strlen()+1 for string allocation, eliminating 8x memory overallocation on 64-bit platforms. Found by PostgresPro Signed-off-by: Maksim Korotkov diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c index 5bfd62ad9..6a006f5f2 100644 --- a/raster/rt_pg/rtpg_geometry.c +++ b/raster/rt_pg/rtpg_geometry.c @@ -1534,7 +1534,7 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS) options = (char **) repalloc(options, sizeof(char *) * options_len); } - options[options_len - 1] = palloc(sizeof(char*) * (strlen("ALL_TOUCHED=TRUE") + 1)); + options[options_len - 1] = palloc(sizeof(char) * (strlen("ALL_TOUCHED=TRUE") + 1)); strcpy(options[options_len - 1], "ALL_TOUCHED=TRUE"); } diff --git a/raster/rt_pg/rtpg_mapalgebra.c b/raster/rt_pg/rtpg_mapalgebra.c index 57ce89a52..865fb3a55 100644 --- a/raster/rt_pg/rtpg_mapalgebra.c +++ b/raster/rt_pg/rtpg_mapalgebra.c @@ -3300,7 +3300,7 @@ Datum RASTER_clip(PG_FUNCTION_ARGS) if (!PG_ARGISNULL(5) && PG_GETARG_BOOL(5) == TRUE){ options_len = options_len + 1; options = (char **) palloc(sizeof(char *) * options_len); - options[options_len - 1] = palloc(sizeof(char*) * (strlen("ALL_TOUCHED=TRUE") + 1)); + options[options_len - 1] = palloc(sizeof(char) * (strlen("ALL_TOUCHED=TRUE") + 1)); strcpy(options[options_len - 1], "ALL_TOUCHED=TRUE"); } ----------------------------------------------------------------------- Summary of changes: raster/rt_pg/rtpg_geometry.c | 2 +- raster/rt_pg/rtpg_mapalgebra.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Tue Jun 16 13:28:12 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 16 Jun 2026 13:28:12 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-539-ga283c9ff4 Message-ID: <20260616202813.30B7C1A2E63@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via a283c9ff4cf3fc9ec60d1961b313f54c64000b0f (commit) via b746a8ce774f4bf178e6e4b08ac84209746fc8bc (commit) from adef2f6bde7696bdb7f02198e02c02916b3a6da7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a283c9ff4cf3fc9ec60d1961b313f54c64000b0f Merge: adef2f6bd b746a8ce7 Author: Darafei Praliaskouski Date: Tue Jun 16 23:01:48 2026 +0400 Merge pull request #880 from ProjectMutilation/fix-potential-overlap-memcpy liblwgeom: fix potential overlapping memory copying commit b746a8ce774f4bf178e6e4b08ac84209746fc8bc Author: Maksim Korotkov Date: Tue Jun 16 15:27:33 2026 +0300 liblwgeom: fix potential overlapping memory copying Using memcpy with overlapping memory regions is undefined behavior per C standard. Replace with memmove to safely handle the case when src and dst point to the same location Signed-off-by: Maksim Korotkov diff --git a/liblwgeom/ptarray.c b/liblwgeom/ptarray.c index 5c6796e75..7631081bc 100644 --- a/liblwgeom/ptarray.c +++ b/liblwgeom/ptarray.c @@ -1852,7 +1852,7 @@ ptarray_simplify_in_place(POINTARRAY *pa, double tolerance, uint32_t minpts) { /* If there are 2 points remaining, it has to be first and last as * we added those at the start */ - memcpy(pa->serialized_pointlist + pt_size * kept_it, + memmove(pa->serialized_pointlist + pt_size * kept_it, pa->serialized_pointlist + pt_size * (pa->npoints - 1), pt_size); } ----------------------------------------------------------------------- Summary of changes: liblwgeom/ptarray.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- PostGIS From trac at osgeo.org Tue Jun 16 23:12:19 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 17 Jun 2026 06:12:19 -0000 Subject: [PostGIS] #6081: Test failure with SFCGAL 2.3.0 In-Reply-To: <050.b08fd523cc1124f6fa81d2796cea1787@osgeo.org> References: <050.b08fd523cc1124f6fa81d2796cea1787@osgeo.org> Message-ID: <065.734ef982a82019da1848f661f69a1497@osgeo.org> #6081: Test failure with SFCGAL 2.3.0 -----------------------------+----------------------------- Reporter: Bas Couwenberg | Owner: Lo?c Bartoletti Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.6.5 Component: sfcgal | Version: 3.6.x Resolution: | Keywords: -----------------------------+----------------------------- Comment (by robe): Ah okay I was building with 6.0 I think so I'll try that later this week. Darafei just committed work today at [c8ea8a68/git] which hopefully should fix the issue. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Wed Jun 17 02:09:15 2026 From: trac at osgeo.org (PostGIS) Date: Wed, 17 Jun 2026 09:09:15 -0000 Subject: [PostGIS] #6081: Test failure with SFCGAL 2.3.0 In-Reply-To: <050.b08fd523cc1124f6fa81d2796cea1787@osgeo.org> References: <050.b08fd523cc1124f6fa81d2796cea1787@osgeo.org> Message-ID: <065.40d18ffcc3dc5b831d4f12c400f75616@osgeo.org> #6081: Test failure with SFCGAL 2.3.0 -----------------------------+----------------------------- Reporter: Bas Couwenberg | Owner: Lo?c Bartoletti Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.6.5 Component: sfcgal | Version: 3.6.x Resolution: | Keywords: -----------------------------+----------------------------- Comment (by Bas Couwenberg): The Debian package now build successfully with the changes from master up to [changeset:a283c9ff4cf3fc9ec60d1961b313f54c64000b0f/git]. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Wed Jun 17 10:42:41 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 17 Jun 2026 10:42:41 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-540-gd622df606 Message-ID: <20260617174242.3EB7A1B0B34@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via d622df60655e5c4ba4cd77dcfdf07b76c47b4016 (commit) from a283c9ff4cf3fc9ec60d1961b313f54c64000b0f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit d622df60655e5c4ba4cd77dcfdf07b76c47b4016 Author: Sandro Santilli Date: Wed Jun 17 19:42:32 2026 +0200 Translate one string diff --git a/doc/po/it_IT/postgis-manual.po b/doc/po/it_IT/postgis-manual.po index d597c32fe..ef842431f 100644 --- a/doc/po/it_IT/postgis-manual.po +++ b/doc/po/it_IT/postgis-manual.po @@ -143,6 +143,8 @@ msgid "" "If you have compiled and installed the extensions/postgis modules, you can " "turn a database into a spatial one using the EXTENSION mechanism." msgstr "" +"Se hai compilato ed installato il modulo extensions/postgis, puoi aggiungere " +"il supporto spaziale in un database usando il meccanismo per le estensioni (EXTENSION)" #. Tag: para #, no-c-format ----------------------------------------------------------------------- Summary of changes: doc/po/it_IT/postgis-manual.po | 2 ++ 1 file changed, 2 insertions(+) hooks/post-receive -- PostGIS From git at osgeo.org Wed Jun 17 11:45:59 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 17 Jun 2026 11:45:59 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-545-g5ec62d698 Message-ID: <20260617184600.811201B176B@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 5ec62d6985632cc603289b2e7af5efa693d683ca (commit) via 435ad25bf7d4e27e1fe4f583a7bdaf19d4cb3f32 (commit) via d0a4c994ad7291cf4bf85ee556a43a8c3af43b64 (commit) via d01c6a3d91ab6018daf086cde59e0e23faaa9389 (commit) via 52eb39e6c6fea9ae4aef600f171f6d9aa38ee561 (commit) from d622df60655e5c4ba4cd77dcfdf07b76c47b4016 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5ec62d6985632cc603289b2e7af5efa693d683ca Merge: d622df606 435ad25bf Author: Darafei Praliaskouski Date: Wed Jun 17 22:43:02 2026 +0400 Merge remote-tracking branch 'gh/pr/885/head' commit 435ad25bf7d4e27e1fe4f583a7bdaf19d4cb3f32 Author: Darafei Praliaskouski Date: Wed Jun 17 01:22:25 2026 +0400 test: place GMP libs after liblwgeom diff --git a/NEWS b/NEWS index 443712616..54811e708 100644 --- a/NEWS +++ b/NEWS @@ -50,6 +50,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Bug Fixes * + - GH-885, [topology] Avoid GMP overflow in ring orientation for very large + finite coordinates (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/liblwgeom/cunit/Makefile.in b/liblwgeom/cunit/Makefile.in index 6a206e9b2..3999c5523 100644 --- a/liblwgeom/cunit/Makefile.in +++ b/liblwgeom/cunit/Makefile.in @@ -22,7 +22,8 @@ LIBTOOL = @LIBTOOL@ CUNIT_LDFLAGS=@CUNIT_LDFLAGS@ CUNIT_CPPFLAGS = -I$(srcdir)/.. -I$(builddir)/.. @CUNIT_CPPFLAGS@ @CPPFLAGS@ CFLAGS=$(CUNIT_CPPFLAGS) @CFLAGS@ -LDFLAGS = @GEOS_LDFLAGS@ @PROJ_LDFLAGS@ @GMP_LIBS@ $(CUNIT_LDFLAGS) +LDFLAGS = @GEOS_LDFLAGS@ @PROJ_LDFLAGS@ $(CUNIT_LDFLAGS) +LIBLWGEOM_LDFLAGS = @GMP_LIBS@ VPATH = $(srcdir) @@ -108,7 +109,7 @@ endif # Build the main unit test executable cu_tester: ../liblwgeom.la $(OBJS) cu_tester.h - $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) -static ../liblwgeom.la + $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) -static ../liblwgeom.la $(LIBLWGEOM_LDFLAGS) # Command to build each of the .o files $(OBJS): %.o: %.c commit d0a4c994ad7291cf4bf85ee556a43a8c3af43b64 Author: Darafei Praliaskouski Date: Wed Jun 17 00:36:20 2026 +0400 test: link CUnit GMP libs through LDFLAGS diff --git a/liblwgeom/cunit/Makefile.in b/liblwgeom/cunit/Makefile.in index 65c05d890..6a206e9b2 100644 --- a/liblwgeom/cunit/Makefile.in +++ b/liblwgeom/cunit/Makefile.in @@ -22,7 +22,7 @@ LIBTOOL = @LIBTOOL@ CUNIT_LDFLAGS=@CUNIT_LDFLAGS@ CUNIT_CPPFLAGS = -I$(srcdir)/.. -I$(builddir)/.. @CUNIT_CPPFLAGS@ @CPPFLAGS@ CFLAGS=$(CUNIT_CPPFLAGS) @CFLAGS@ -LDFLAGS = @GEOS_LDFLAGS@ @PROJ_LDFLAGS@ $(CUNIT_LDFLAGS) +LDFLAGS = @GEOS_LDFLAGS@ @PROJ_LDFLAGS@ @GMP_LIBS@ $(CUNIT_LDFLAGS) VPATH = $(srcdir) @@ -108,7 +108,7 @@ endif # Build the main unit test executable cu_tester: ../liblwgeom.la $(OBJS) cu_tester.h - $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) -static ../liblwgeom.la @GMP_LIBS@ + $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) -static ../liblwgeom.la # Command to build each of the .o files $(OBJS): %.o: %.c commit d01c6a3d91ab6018daf086cde59e0e23faaa9389 Author: Darafei Praliaskouski Date: Wed Jun 17 00:10:33 2026 +0400 liblwgeom: link CUnit tester with GMP diff --git a/liblwgeom/cunit/Makefile.in b/liblwgeom/cunit/Makefile.in index 14e41aed3..65c05d890 100644 --- a/liblwgeom/cunit/Makefile.in +++ b/liblwgeom/cunit/Makefile.in @@ -108,7 +108,7 @@ endif # Build the main unit test executable cu_tester: ../liblwgeom.la $(OBJS) cu_tester.h - $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) -static ../liblwgeom.la + $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) -static ../liblwgeom.la @GMP_LIBS@ # Command to build each of the .o files $(OBJS): %.o: %.c commit 52eb39e6c6fea9ae4aef600f171f6d9aa38ee561 Author: Darafei Praliaskouski Date: Thu Jun 11 07:43:43 2026 +0400 Avoid GMP overflow in topology ring orientation diff --git a/liblwgeom/cunit/Makefile.in b/liblwgeom/cunit/Makefile.in index 791be060e..14e41aed3 100644 --- a/liblwgeom/cunit/Makefile.in +++ b/liblwgeom/cunit/Makefile.in @@ -58,6 +58,7 @@ OBJS= \ cu_split.o \ cu_stringbuffer.o \ cu_triangulate.o \ + cu_topo.o \ cu_homogenize.o \ cu_force_dims.o \ cu_force_sfs.o \ diff --git a/liblwgeom/cunit/cu_tester.c b/liblwgeom/cunit/cu_tester.c index a32c3f41a..33c1aa26f 100644 --- a/liblwgeom/cunit/cu_tester.c +++ b/liblwgeom/cunit/cu_tester.c @@ -72,6 +72,7 @@ extern void sfcgal_suite_setup(void); extern void split_suite_setup(void); extern void stringbuffer_suite_setup(void); extern void tree_suite_setup(void); +extern void topo_suite_setup(void); extern void triangulate_suite_setup(void); extern void varint_suite_setup(void); extern void wkt_out_suite_setup(void); @@ -128,6 +129,7 @@ PG_SuiteSetup setupfuncs[] = {algorithms_suite_setup, stringbuffer_suite_setup, surface_suite_setup, tree_suite_setup, + topo_suite_setup, triangulate_suite_setup, twkb_out_suite_setup, varint_suite_setup, diff --git a/liblwgeom/cunit/cu_topo.c b/liblwgeom/cunit/cu_topo.c new file mode 100644 index 000000000..490b95058 --- /dev/null +++ b/liblwgeom/cunit/cu_topo.c @@ -0,0 +1,55 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.net + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU General Public Licence. See the COPYING file. + * + **********************************************************************/ + +#include "CUnit/Basic.h" +#include "CUnit/CUnit.h" + +#include "liblwgeom_internal.h" +#include "topo/liblwgeom_topo.h" +#include "cu_tester.h" + +static LWGEOM * +lwgeom_from_text(const char *str) +{ + LWGEOM_PARSER_RESULT r; + if (LW_FAILURE == lwgeom_parse_wkt(&r, (char *)str, LW_PARSER_CHECK_NONE)) + return NULL; + return r.geom; +} + +static void +test_lwt_IsTopoRingCCW_large_finite_coordinates(void) +{ + LWGEOM *geom = lwgeom_from_text("POLYGON((0 1e308,1e308 0,0 0,0 1e308))"); + LWPOLY *poly; + + CU_ASSERT_PTR_NOT_NULL(geom); + if (!geom) + return; + + poly = lwgeom_as_lwpoly(geom); + CU_ASSERT_PTR_NOT_NULL(poly); + if (!poly) + { + lwgeom_free(geom); + return; + } + + CU_ASSERT_EQUAL(lwt_IsTopoRingCCW(poly->rings[0]), LW_FALSE); + + lwgeom_free(geom); +} + +void +topo_suite_setup(void) +{ + CU_pSuite suite = CU_add_suite("topology", NULL, NULL); + PG_ADD_TEST(suite, test_lwt_IsTopoRingCCW_large_finite_coordinates); +} diff --git a/liblwgeom/topo/lwgeom_topo.c b/liblwgeom/topo/lwgeom_topo.c index 6d0144bb9..c7bfe1cee 100644 --- a/liblwgeom/topo/lwgeom_topo.c +++ b/liblwgeom/topo/lwgeom_topo.c @@ -38,6 +38,7 @@ #include #include +#include static bool _lwt_describe_point(const LWPOINT *pt, char *buf, size_t bufsize) @@ -1888,27 +1889,49 @@ lwt_IsTopoRingCCW(const POINTARRAY *pa) const POINT2D *P3; mpf_t sum; mpf_t tmp; - double x0, x, y1, y2; + mpf_t x0; + mpf_t x; + mpf_t dy; uint32_t i; int ret; if (! pa || pa->npoints < 3 ) return 0; - mpf_init2(sum, 64); - mpf_init2(tmp, 64); - mpf_set_d(sum, 0.0); - P1 = getPoint2d_cp(pa, 0); P2 = getPoint2d_cp(pa, 1); - x0 = P1->x; + + if (!isfinite(P1->x) || !isfinite(P1->y) || !isfinite(P2->x) || !isfinite(P2->y)) + return ptarray_isccw(pa); + + mpf_init2(sum, 64); + mpf_init2(tmp, 64); + mpf_init2(x0, 64); + mpf_init2(x, 64); + mpf_init2(dy, 64); + mpf_set_d(sum, 0.0); + mpf_set_d(x0, P1->x); + for ( i = 2; i < pa->npoints; i++ ) { P3 = getPoint2d_cp(pa, i); - x = P2->x - x0; - y1 = P3->y; - y2 = P1->y; - mpf_set_d(tmp, x * (y2-y1)); + + if (!isfinite(P3->x) || !isfinite(P3->y)) + { + mpf_clear(dy); + mpf_clear(x); + mpf_clear(x0); + mpf_clear(tmp); + mpf_clear(sum); + return ptarray_isccw(pa); + } + + mpf_set_d(x, P2->x); + mpf_sub(x, x, x0); + mpf_set_d(dy, P1->y); + mpf_set_d(tmp, P3->y); + mpf_sub(dy, dy, tmp); + mpf_mul(tmp, x, dy); mpf_add(sum, sum, tmp); P1 = P2; P2 = P3; @@ -1916,6 +1939,9 @@ lwt_IsTopoRingCCW(const POINTARRAY *pa) ret = mpf_cmp_ui(sum, 0) < 0; + mpf_clear(dy); + mpf_clear(x); + mpf_clear(x0); mpf_clear(tmp); mpf_clear(sum); ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ liblwgeom/cunit/Makefile.in | 4 +++- liblwgeom/cunit/cu_tester.c | 2 ++ liblwgeom/cunit/cu_topo.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ liblwgeom/topo/lwgeom_topo.c | 42 ++++++++++++++++++++++++++------- 5 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 liblwgeom/cunit/cu_topo.c hooks/post-receive -- PostGIS From git at osgeo.org Wed Jun 17 15:06:46 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 17 Jun 2026 15:06:46 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-547-g6f66e39d8 Message-ID: <20260617220646.A92511B3E44@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 6f66e39d8aaf7261bcf4f5b7ce10c9b727fc7168 (commit) via 73871012be232126e6fcb6eb22009842e9b6d9a7 (commit) from 5ec62d6985632cc603289b2e7af5efa693d683ca (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6f66e39d8aaf7261bcf4f5b7ce10c9b727fc7168 Merge: 5ec62d698 73871012b Author: Darafei Praliaskouski Date: Thu Jun 18 02:03:07 2026 +0400 Merge PR #892: add TWKB and raster OSS-Fuzz targets Adds OSS-Fuzz harnesses for TWKB import and serialized raster deserialization, shared fuzzer allocation/error handling helpers, checked-in seed corpus archives, and build wiring for raster-enabled fuzz targets. Also hardens TWKB truncation, overlong varint, and impossible element-count handling covered by the new fuzzer and CUnit regression inputs. commit 73871012be232126e6fcb6eb22009842e9b6d9a7 Author: Darafei Praliaskouski Date: Wed Jun 17 23:43:11 2026 +0400 fuzzers: add TWKB and raster input targets diff --git a/GNUmakefile.in b/GNUmakefile.in index 8b007271c..e65fd23e4 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -83,6 +83,9 @@ check: check-unit docs-check check-lint check-spell ifeq (@SUPPORT_POSTGRESQL@,yes) check: check-regress endif +ifeq (@RASTER@,raster) +check: check-fuzzers +endif # The "lint" tests do not depend on specific code configurations # but solely on the source code state @@ -95,6 +98,16 @@ check-news: $(top_srcdir)/utils/check_news.sh $(top_srcdir) check-unit check-regress: all +ifeq (@RASTER@,raster) +check-fuzzers: all + mkdir -p fuzzers + fuzzer_out=`mktemp -d "$${TMPDIR:-/tmp}/postgis-fuzzer-check.XXXXXX"`; \ + trap 'rm -rf "$${fuzzer_out}"' EXIT HUP INT TERM; \ + $(MAKE) -C fuzzers -f $(abspath $(top_srcdir))/fuzzers/Makefile \ + POSTGIS_BUILD_DIR="$(CURDIR)" \ + FUZZER_OUT="$${fuzzer_out}" \ + check +endif check-regress: export POSTGIS_REGRESS_DB ?= postgis_reg-$(POSTGIS_MAJOR_VERSION).$(POSTGIS_MINOR_VERSION) diff --git a/NEWS b/NEWS index 54811e708..4cd72746a 100644 --- a/NEWS +++ b/NEWS @@ -52,6 +52,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - GH-885, [topology] Avoid GMP overflow in ring orientation for very large finite coordinates (Darafei Praliaskouski) + - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, + including guards for malformed TWKB reads and counts (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/fuzzers/Makefile b/fuzzers/Makefile index 5eeb2438e..01b324312 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -1,10 +1,81 @@ +FUZZER_SRC_DIR ?= $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +POSTGIS_BUILD_DIR ?= $(abspath ..) +FUZZER_OUT ?= /tmp +FUZZER_WORK ?= $(FUZZER_OUT)/postgis-fuzzer-check +FUZZER_SOURCES := $(notdir $(wildcard $(FUZZER_SRC_DIR)/*_fuzzer.cpp $(FUZZER_SRC_DIR)/*_fuzzer.c)) +FUZZER_NAMES := $(basename $(FUZZER_SOURCES)) +SEED_CORPORA := $(wildcard $(FUZZER_SRC_DIR)/*_seed_corpus.zip) +POSTGIS_CONFIGURED_LDFLAGS := $(shell sed -n 's/^LDFLAGS = //p' $(POSTGIS_BUILD_DIR)/liblwgeom/Makefile 2>/dev/null | sed 1q) +POSTGIS_FUZZER_LDFLAGS = $(POSTGIS_CONFIGURED_LDFLAGS) $(LDFLAGS) + +.PHONY: clean dummyfuzzers check check-corpus + clean: $(RM) -f *.o *.a -fuzzingengine.o: fuzzingengine.c +fuzzingengine.o: $(FUZZER_SRC_DIR)/fuzzingengine.c $(CC) $(CFLAGS) -c -o $@ $< dummyfuzzers: fuzzingengine.o + mkdir -p "$(FUZZER_OUT)" $(AR) r libFuzzingEngine.a fuzzingengine.o - CXX="${CXX}" CXXFLAGS="-L. ${CXXFLAGS}" SRC=/tmp OUT=/tmp ./build_google_oss_fuzzers.sh - OUT=/tmp ./build_seed_corpus.sh + CC="${CC}" CXX="${CXX}" CXXFLAGS="-L$(CURDIR) ${CXXFLAGS}" LDFLAGS="$(POSTGIS_FUZZER_LDFLAGS)" POSTGIS_BUILD_DIR="$(POSTGIS_BUILD_DIR)" SRC="$(FUZZER_SRC_DIR)" OUT="$(FUZZER_OUT)" $(FUZZER_SRC_DIR)/build_google_oss_fuzzers.sh + OUT="$(FUZZER_OUT)" $(FUZZER_SRC_DIR)/build_seed_corpus.sh + +check: + @cxx="$${CXX:-$(CXX)}"; \ + set -- $${cxx}; \ + if [ "$$#" -eq 0 ] || ! command -v "$$1" >/dev/null 2>&1 || ! "$$@" --version >/dev/null 2>&1; then \ + echo "C++ compiler '$${cxx}' not available; skipping fuzzer smoke check."; \ + elif ! command -v pkg-config >/dev/null 2>&1 || ! pkg-config --exists json-c proj libxml-2.0; then \ + echo "pkg-config metadata for fuzzer dependencies not found; skipping fuzzer smoke check."; \ + elif ! command -v geos-config >/dev/null 2>&1 || ! command -v gdal-config >/dev/null 2>&1; then \ + echo "GEOS/GDAL fuzzer dependency helpers not found; skipping fuzzer smoke check."; \ + else \ + set -e; \ + if { command -v python3 >/dev/null 2>&1 && python3 -m zipfile --help >/dev/null 2>&1; } || \ + { command -v unzip >/dev/null 2>&1 && unzip -v >/dev/null 2>&1; }; then \ + $(MAKE) check-corpus; \ + else \ + echo "No seed corpus zip extractor found; running fuzzer smoke check without corpus replay."; \ + $(MAKE) dummyfuzzers; \ + for fuzzer in $(FUZZER_NAMES); do \ + "$(FUZZER_OUT)/$${fuzzer}"; \ + done; \ + fi; \ + fi + +check-corpus: dummyfuzzers + @set -e; \ + for fuzzer in $(FUZZER_NAMES); do \ + "$(FUZZER_OUT)/$${fuzzer}"; \ + done + @set -e; \ + if command -v python3 >/dev/null 2>&1 && python3 -m zipfile --help >/dev/null 2>&1; then \ + extract_zip=python3; \ + elif command -v unzip >/dev/null 2>&1 && unzip -v >/dev/null 2>&1; then \ + extract_zip=unzip; \ + else \ + echo "No seed corpus zip extractor found. Install python3 or unzip, then rerun check-corpus."; \ + exit 1; \ + fi; \ + rm -rf "$(FUZZER_WORK)"; \ + mkdir -p "$(FUZZER_WORK)"; \ + trap 'rm -rf "$(FUZZER_WORK)"' EXIT HUP INT TERM; \ + for corpus in $(SEED_CORPORA) __none__; do \ + if [ "$${corpus}" = "__none__" ]; then \ + continue; \ + fi; \ + corpus_name=$$(basename "$${corpus}"); \ + fuzzer=$${corpus_name%_seed_corpus.zip}; \ + corpus_dir="$(FUZZER_WORK)/$${fuzzer}"; \ + mkdir -p "$${corpus_dir}"; \ + if [ "$${extract_zip}" = "python3" ]; then \ + python3 -m zipfile -e "$${corpus}" "$${corpus_dir}"; \ + else \ + unzip -qq "$${corpus}" -d "$${corpus_dir}"; \ + fi; \ + find "$${corpus_dir}" -type f -print | while IFS= read -r seed; do \ + "$(FUZZER_OUT)/$${fuzzer}" "$${seed}"; \ + done; \ + done diff --git a/fuzzers/README.md b/fuzzers/README.md index 0c167e4f3..738b91d5b 100644 --- a/fuzzers/README.md +++ b/fuzzers/README.md @@ -27,12 +27,16 @@ The `oss-fuzz` project `Dockerfile` should call this script during image build. ## Local Workflow -### Simulate Dummy Fuzzer Build +### Simulate Dummy Fuzzer Build And Check ```bash -make dummyfuzzers +make check ``` +When `python3` or `unzip` is available, this also replays the checked-in seed +corpus archives. Hosts without an archive extractor still run a no-input smoke +check for each fuzzer. + Artifacts are created in `/tmp`: - `/tmp/*_fuzzer` @@ -45,6 +49,12 @@ Run one fuzzer locally: /tmp/wkt_import_fuzzer a_file_name ``` +Require checked-in seed corpus replay: + +```bash +make check-corpus +``` + ### Run OSS-Fuzz Locally ```bash diff --git a/fuzzers/build_google_oss_fuzzers.sh b/fuzzers/build_google_oss_fuzzers.sh index 4f1435c24..1cc825413 100755 --- a/fuzzers/build_google_oss_fuzzers.sh +++ b/fuzzers/build_google_oss_fuzzers.sh @@ -17,23 +17,65 @@ if [ "$CXX" == "" ]; then exit 1 fi -SRC_DIR=$(dirname $0)/.. +if [ "$CC" == "" ]; then + echo "CC env var not defined" + exit 1 +fi + +POSTGIS_SOURCE_DIR="${POSTGIS_SOURCE_DIR:-$(cd "$(dirname "$0")/.." && pwd)}" +POSTGIS_BUILD_DIR="${POSTGIS_BUILD_DIR:-$POSTGIS_SOURCE_DIR}" +FUZZERS_DIR="$POSTGIS_SOURCE_DIR/fuzzers" JSON_C_LIBS=$(pkg-config --libs json-c) GEOS_LIBS=$(geos-config --clibs) PROJ_XML2_LIBS=$(pkg-config --libs proj libxml-2.0) +GDAL_CFLAGS=$(gdal-config --cflags) +GDAL_LIBS=$(gdal-config --libs) POSTGIS_FUZZER_LIBS="$JSON_C_LIBS $GEOS_LIBS $PROJ_XML2_LIBS" POSTGIS_PACKAGE_RUNTIME_LIBS="${POSTGIS_PACKAGE_RUNTIME_LIBS:-1}" +target_cflags() +{ + case "$1" in + raster_deserialize_fuzzer) + echo "-I$POSTGIS_SOURCE_DIR/raster/rt_core -I$POSTGIS_BUILD_DIR/raster/rt_core -I$POSTGIS_SOURCE_DIR/raster -I$POSTGIS_BUILD_DIR/raster -I$POSTGIS_SOURCE_DIR -I$POSTGIS_BUILD_DIR $GDAL_CFLAGS" + ;; + esac +} + +target_libs() +{ + case "$1" in + raster_deserialize_fuzzer) + echo "$POSTGIS_BUILD_DIR/raster/rt_core/librtcore.a $GDAL_LIBS" + ;; + esac +} + build_fuzzer() { fuzzerName=$1 sourceFilename=$2 - shift - shift + extension=${sourceFilename##*.} + objectFile="" + echo "Building fuzzer $fuzzerName" - $CXX $CXXFLAGS -std=c++11 -I$SRC_DIR/liblwgeom \ - $sourceFilename $* -o $OUT/$fuzzerName \ - -lFuzzingEngine -lstdc++ $SRC_DIR/liblwgeom/.libs/liblwgeom.a $POSTGIS_FUZZER_LIBS + + if [ "$extension" = "c" ]; then + objectFile=$(mktemp) + "$CC" $CFLAGS -I"$POSTGIS_SOURCE_DIR/liblwgeom" -I"$POSTGIS_BUILD_DIR/liblwgeom" $(target_cflags "$fuzzerName") \ + -c "$sourceFilename" -o "$objectFile" + sourceFilename=$objectFile + fi + + "$CXX" $CXXFLAGS -std=c++11 -I"$POSTGIS_SOURCE_DIR/liblwgeom" -I"$POSTGIS_BUILD_DIR/liblwgeom" \ + "$sourceFilename" -o "$OUT/$fuzzerName" \ + $LDFLAGS \ + -lFuzzingEngine -lstdc++ $(target_libs "$fuzzerName") \ + "$POSTGIS_BUILD_DIR/liblwgeom/.libs/liblwgeom.a" $POSTGIS_FUZZER_LIBS + + if [ "$objectFile" != "" ]; then + rm -f "$objectFile" + fi } package_runtime_libs() @@ -66,13 +108,22 @@ package_runtime_libs() fi } -fuzzerFiles=$(dirname $0)/*.cpp -for F in $fuzzerFiles; do - fuzzerName=$(basename $F .cpp) - build_fuzzer $fuzzerName $F +for F in "$FUZZERS_DIR"/*.cpp; do + [ -e "$F" ] || continue + fuzzerName=$(basename "$F" .cpp) + build_fuzzer "$fuzzerName" "$F" done -cp $(dirname $0)/*.dict $(dirname $0)/*.options $(dirname $0)/*.zip $OUT/ +for F in "$FUZZERS_DIR"/*_fuzzer.c; do + [ -e "$F" ] || continue + fuzzerName=$(basename "$F" .c) + build_fuzzer "$fuzzerName" "$F" +done + +for artifact in "$FUZZERS_DIR"/*.dict "$FUZZERS_DIR"/*.options "$FUZZERS_DIR"/*.zip; do + [ -e "$artifact" ] || continue + cp "$artifact" "$OUT/" +done if [ "$POSTGIS_PACKAGE_RUNTIME_LIBS" != "0" ]; then package_runtime_libs diff --git a/fuzzers/build_oss_fuzz.sh b/fuzzers/build_oss_fuzz.sh index 5b65ddcda..b733bf1a8 100755 --- a/fuzzers/build_oss_fuzz.sh +++ b/fuzzers/build_oss_fuzz.sh @@ -28,7 +28,7 @@ fi export CXXFLAGS="$CXXFLAGS -std=c++11" POSTGIS_OSS_FUZZ_CONFIGURE_FLAGS=( --enable-static - --without-raster + --with-raster --without-protobuf --enable-debug ) @@ -36,10 +36,8 @@ POSTGIS_OSS_FUZZ_CONFIGURE_FLAGS=( cd "$SRC_DIR" ./autogen.sh ./configure CC="$CC" CXX="$CXX" "${POSTGIS_OSS_FUZZ_CONFIGURE_FLAGS[@]}" -cd liblwgeom -make clean -s -make -j"$(nproc)" -s -cd .. +make -C liblwgeom -j"$(nproc)" -s +make -C raster corelib -j"$(nproc)" -s bash ./fuzzers/build_google_oss_fuzzers.sh bash ./fuzzers/build_seed_corpus.sh diff --git a/fuzzers/install_oss_fuzz_build_deps.sh b/fuzzers/install_oss_fuzz_build_deps.sh index dd3475745..2740687f4 100755 --- a/fuzzers/install_oss_fuzz_build_deps.sh +++ b/fuzzers/install_oss_fuzz_build_deps.sh @@ -17,7 +17,7 @@ export DEBIAN_FRONTEND="${DEBIAN_FRONTEND:-noninteractive}" apt-get update apt-get install -y --no-install-recommends \ make autoconf automake libtool bison flex g++ postgresql-server-dev-all \ - libgeos-dev libproj-dev libxml2-dev pkg-config libjson-c-dev \ - libc++-dev libc++abi-dev patchelf + libgeos-dev libproj-dev libxml2-dev pkg-config libjson-c-dev libgmp-dev \ + libgdal-dev libc++-dev libc++abi-dev patchelf rm -rf /var/lib/apt/lists/* diff --git a/fuzzers/liblwgeom_fuzzer.hpp b/fuzzers/liblwgeom_fuzzer.hpp new file mode 100644 index 000000000..c44f6e526 --- /dev/null +++ b/fuzzers/liblwgeom_fuzzer.hpp @@ -0,0 +1,164 @@ +/****************************************************************************** + * + * Project: PostGIS + * Purpose: Shared liblwgeom fuzzer support + * + ****************************************************************************** + * Copyright (C) 2026 Darafei Praliaskouski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + ****************************************************************************/ + +#ifndef POSTGIS_LIBLWGEOM_FUZZER_HPP +#define POSTGIS_LIBLWGEOM_FUZZER_HPP + +#include +#include +#include +#include + +extern "C" { +#include "liblwgeom.h" +} + +static jmp_buf postgis_lwgeom_fuzzer_jmp_buf; +static void **postgis_lwgeom_fuzzer_ptrs = NULL; +static size_t postgis_lwgeom_fuzzer_count = 0; +static size_t postgis_lwgeom_fuzzer_capacity = 0; + +#define POSTGIS_LWGEOM_FUZZER_SETJMP() setjmp(postgis_lwgeom_fuzzer_jmp_buf) + +static int +postgis_lwgeom_fuzzer_track_add(void *ptr) +{ + void **new_ptrs; + size_t new_capacity; + + if (postgis_lwgeom_fuzzer_count == postgis_lwgeom_fuzzer_capacity) + { + new_capacity = postgis_lwgeom_fuzzer_capacity ? postgis_lwgeom_fuzzer_capacity * 2 : 64; + new_ptrs = (void **)realloc(postgis_lwgeom_fuzzer_ptrs, new_capacity * sizeof(void *)); + if (new_ptrs == NULL) + return 0; + postgis_lwgeom_fuzzer_ptrs = new_ptrs; + postgis_lwgeom_fuzzer_capacity = new_capacity; + } + + postgis_lwgeom_fuzzer_ptrs[postgis_lwgeom_fuzzer_count++] = ptr; + return 1; +} + +static void +postgis_lwgeom_fuzzer_track_remove(void *ptr) +{ + for (size_t i = 0; i < postgis_lwgeom_fuzzer_count; i++) + { + if (postgis_lwgeom_fuzzer_ptrs[i] == ptr) + { + postgis_lwgeom_fuzzer_ptrs[i] = postgis_lwgeom_fuzzer_ptrs[--postgis_lwgeom_fuzzer_count]; + return; + } + } +} + +static void +postgis_lwgeom_fuzzer_cleanup_allocations(void) +{ + for (size_t i = 0; i < postgis_lwgeom_fuzzer_count; i++) + free(postgis_lwgeom_fuzzer_ptrs[i]); + postgis_lwgeom_fuzzer_count = 0; +} + +static void * +postgis_lwgeom_fuzzer_malloc(size_t size) +{ + void *ptr = malloc(size); + if (ptr != NULL && !postgis_lwgeom_fuzzer_track_add(ptr)) + { + free(ptr); + return NULL; + } + return ptr; +} + +static void * +postgis_lwgeom_fuzzer_realloc(void *ptr, size_t size) +{ + void *new_ptr; + + if (ptr == NULL) + return postgis_lwgeom_fuzzer_malloc(size); + if (size == 0) + { + postgis_lwgeom_fuzzer_track_remove(ptr); + free(ptr); + return NULL; + } + + new_ptr = realloc(ptr, size); + if (new_ptr == NULL) + return NULL; + + for (size_t i = 0; i < postgis_lwgeom_fuzzer_count; i++) + { + if (postgis_lwgeom_fuzzer_ptrs[i] == ptr) + { + postgis_lwgeom_fuzzer_ptrs[i] = new_ptr; + return new_ptr; + } + } + + if (!postgis_lwgeom_fuzzer_track_add(new_ptr)) + { + free(new_ptr); + return NULL; + } + return new_ptr; +} + +static void +postgis_lwgeom_fuzzer_free(void *ptr) +{ + if (ptr == NULL) + return; + postgis_lwgeom_fuzzer_track_remove(ptr); + free(ptr); +} + +extern "C" { +static void +postgis_lwgeom_fuzzer_noticereporter(const char *, va_list) +{} + +static void +postgis_lwgeom_fuzzer_errorreporter(const char *, va_list) +{ + postgis_lwgeom_fuzzer_cleanup_allocations(); + longjmp(postgis_lwgeom_fuzzer_jmp_buf, 1); +} + +static void +postgis_lwgeom_fuzzer_debuglogger(int, const char *, va_list) +{} +} + +static void +postgis_lwgeom_fuzzer_initialize(void) +{ + /* liblwgeom reports parser errors through the configured error reporter. + * Track liblwgeom allocations so longjmp error paths release allocations + * made before the jump. + */ + lwgeom_set_handlers(postgis_lwgeom_fuzzer_malloc, + postgis_lwgeom_fuzzer_realloc, + postgis_lwgeom_fuzzer_free, + postgis_lwgeom_fuzzer_errorreporter, + postgis_lwgeom_fuzzer_noticereporter); + lwgeom_set_debuglogger(postgis_lwgeom_fuzzer_debuglogger); +} + +#endif diff --git a/fuzzers/raster_deserialize_fuzzer.c b/fuzzers/raster_deserialize_fuzzer.c new file mode 100644 index 000000000..cb69254f0 --- /dev/null +++ b/fuzzers/raster_deserialize_fuzzer.c @@ -0,0 +1,185 @@ +/****************************************************************************** + * + * Project: PostGIS + * Purpose: Raster serialized input fuzzer + * + ****************************************************************************** + * Copyright (C) 2026 Darafei Praliaskouski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "librtcore.h" +#include "rt_serialize.h" + +static jmp_buf jmpBuf; +static void *current_serialized = NULL; + +static void +cleanup_serialized(void) +{ + free(current_serialized); + current_serialized = NULL; +} + +static void +rt_message_handler_noop(const char *fmt, va_list ap) +{ + (void)fmt; + (void)ap; +} + +static void +rt_error_handler(const char *fmt, va_list ap) +{ + (void)fmt; + (void)ap; + cleanup_serialized(); + longjmp(jmpBuf, 1); +} + +int +LLVMFuzzerInitialize(int *argc, char ***argv) +{ + (void)argc; + (void)argv; + rt_set_handlers(malloc, realloc, free, rt_error_handler, rt_message_handler_noop, rt_message_handler_noop); + return 0; +} + +static int +checked_add(size_t *total, size_t value, size_t limit) +{ + if (value > limit || *total > limit - value) + return 0; + *total += value; + return 1; +} + +static int +has_complete_serialized_raster(const uint8_t *buf, size_t len) +{ + struct rt_raster_serialized_t header; + size_t pos = sizeof(header); + + /* rt_raster_deserialize() accepts a pointer but no buffer length. Before + * calling it, walk the serialized layout far enough to prove each band, + * nodata value, optional out-db path, pixel payload, and 8-byte padding byte + * is inside the fuzzer-provided buffer. + */ + if (len < sizeof(header)) + return 0; + + memcpy(&header, buf, sizeof(header)); + + if (header.numBands > 256) + return 0; + + for (uint16_t i = 0; i < header.numBands; i++) + { + if (pos >= len) + return 0; + + const uint8_t band_type = buf[pos]; + const rt_pixtype pixtype = (rt_pixtype)(band_type & BANDTYPE_PIXTYPE_MASK); + const int pixbytes = rt_pixtype_size(pixtype); + if (pixbytes <= 0) + return 0; + + /* Band type byte, nodata padding bytes, and nodata value. */ + if (!checked_add(&pos, 1, len)) + return 0; + if (!checked_add(&pos, (size_t)(pixbytes - 1), len)) + return 0; + if (!checked_add(&pos, (size_t)pixbytes, len)) + return 0; + + if (BANDTYPE_IS_OFFDB(band_type)) + { + /* Out-db band number plus NUL-terminated path. */ + if (!checked_add(&pos, 1, len)) + return 0; + + const void *nul = memchr(buf + pos, '\0', len - pos); + if (nul == NULL) + return 0; + + const size_t path_len = (const uint8_t *)nul - (buf + pos); + if (!checked_add(&pos, path_len + 1, len)) + return 0; + } + else + { + /* Inline raster data is width * height pixels in this band's + * pixel type. + */ + const size_t pixels = (size_t)header.width * (size_t)header.height; + if (header.width != 0 && pixels / header.width != header.height) + return 0; + if (pixbytes > 0 && pixels > len / (size_t)pixbytes) + return 0; + if (!checked_add(&pos, pixels * (size_t)pixbytes, len)) + return 0; + } + + while (pos % 8 != 0) + { + if (!checked_add(&pos, 1, len)) + return 0; + } + } + + return 1; +} + +static void +destroy_raster_with_bands(rt_raster raster) +{ + uint16_t num_bands; + + if (raster == NULL) + return; + + num_bands = rt_raster_get_num_bands(raster); + for (uint16_t i = 0; i < num_bands; i++) + { + rt_band band = rt_raster_get_band(raster, i); + if (band != NULL) + rt_band_destroy(band); + } + + rt_raster_destroy(raster); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) +{ + if (setjmp(jmpBuf)) + { + cleanup_serialized(); + return 0; + } + + if (!has_complete_serialized_raster(buf, len)) + return 0; + + current_serialized = malloc(len); + if (current_serialized == NULL) + return 0; + + memcpy(current_serialized, buf, len); + rt_raster raster = rt_raster_deserialize(current_serialized, 0); + destroy_raster_with_bands(raster); + cleanup_serialized(); + return 0; +} diff --git a/fuzzers/raster_deserialize_fuzzer.options b/fuzzers/raster_deserialize_fuzzer.options new file mode 100644 index 000000000..60a51fcba --- /dev/null +++ b/fuzzers/raster_deserialize_fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 100000 diff --git a/fuzzers/raster_deserialize_fuzzer_seed_corpus.zip b/fuzzers/raster_deserialize_fuzzer_seed_corpus.zip new file mode 100644 index 000000000..92e3dd60d Binary files /dev/null and b/fuzzers/raster_deserialize_fuzzer_seed_corpus.zip differ diff --git a/fuzzers/twkb_import_fuzzer.cpp b/fuzzers/twkb_import_fuzzer.cpp new file mode 100644 index 000000000..d662667b2 --- /dev/null +++ b/fuzzers/twkb_import_fuzzer.cpp @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Project: PostGIS + * Purpose: TWKB input fuzzer + * + ****************************************************************************** + * Copyright (C) 2026 Darafei Praliaskouski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + ****************************************************************************/ + +#include +#include + +extern "C" { +#include "geos_stub.h" +#include "proj_stub.h" +} + +#include "liblwgeom_fuzzer.hpp" + +extern "C" int +LLVMFuzzerInitialize(int * /*argc*/, char *** /*argv*/) +{ + postgis_lwgeom_fuzzer_initialize(); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len); + +int +LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) +{ + /* Avoid inputs too short to contain TWKB metadata. If the metadata says an + * extended precision byte follows, make sure that byte exists too. + */ + if (len < 2) + return 0; + if ((buf[1] & 0x08) && len < 3) + return 0; + + if (POSTGIS_LWGEOM_FUZZER_SETJMP()) + { + postgis_lwgeom_fuzzer_cleanup_allocations(); + return 0; + } + + LWGEOM *lwgeom = lwgeom_from_twkb(buf, len, LW_PARSER_CHECK_NONE); + lwgeom_free(lwgeom); + postgis_lwgeom_fuzzer_cleanup_allocations(); + return 0; +} diff --git a/fuzzers/twkb_import_fuzzer.options b/fuzzers/twkb_import_fuzzer.options new file mode 100644 index 000000000..60a51fcba --- /dev/null +++ b/fuzzers/twkb_import_fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 100000 diff --git a/fuzzers/twkb_import_fuzzer_seed_corpus.zip b/fuzzers/twkb_import_fuzzer_seed_corpus.zip new file mode 100644 index 000000000..3c26fad6e Binary files /dev/null and b/fuzzers/twkb_import_fuzzer_seed_corpus.zip differ diff --git a/fuzzers/wkb_import_fuzzer.cpp b/fuzzers/wkb_import_fuzzer.cpp index 48ff539ad..f1d1c7eb9 100644 --- a/fuzzers/wkb_import_fuzzer.cpp +++ b/fuzzers/wkb_import_fuzzer.cpp @@ -26,95 +26,33 @@ * DEALINGS IN THE SOFTWARE. ****************************************************************************/ -#include #include #include -#include -#include -#include -#include - -extern "C" -{ -#include "liblwgeom.h" +extern "C" { #include "geos_stub.h" #include "proj_stub.h" } -extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv); +#include "liblwgeom_fuzzer.hpp" -// Keep active heap allocated memory corresponding to returns of allocator() -// and reallocator() -std::set oSetPointers; -jmp_buf jmpBuf; - -extern "C" +extern "C" int +LLVMFuzzerInitialize(int * /*argc*/, char *** /*argv*/) { - static void * - allocator(size_t size) - { - void *mem = malloc(size); - oSetPointers.insert(mem); - return mem; - } - - static void - freeor(void *mem) - { - oSetPointers.erase(mem); - free(mem); - } - - static void * - reallocator(void *mem, size_t size) - { - oSetPointers.erase(mem); - void *ret = realloc(mem, size); - oSetPointers.insert(ret); - return ret; - } - - static void - noticereporter(const char *, va_list ) - { - } - - static void - errorreporter(const char *, va_list ) - { - // Cleanup any heap-allocated memory still active - for(std::set::iterator oIter = oSetPointers.begin(); - oIter != oSetPointers.end(); ++oIter ) - { - free(*oIter); - } - oSetPointers.clear(); - // Abort everything to jump to setjmp() call - longjmp(jmpBuf, 1); - } - - static void - debuglogger(int, const char *, va_list) - { - } - -} - -int LLVMFuzzerInitialize(int* /*argc*/, char*** /*argv*/) -{ - lwgeom_set_handlers(malloc, realloc, free, noticereporter, noticereporter); - lwgeom_set_debuglogger(debuglogger); + postgis_lwgeom_fuzzer_initialize(); return 0; } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len); int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { - if( setjmp(jmpBuf) ) - return 0; - LWGEOM* lwgeom = lwgeom_from_wkb(buf, len, LW_PARSER_CHECK_NONE); - lwgeom_free(lwgeom); - //assert( oSetPointers.empty() ); - return 0; + if (POSTGIS_LWGEOM_FUZZER_SETJMP()) + { + postgis_lwgeom_fuzzer_cleanup_allocations(); + return 0; + } + LWGEOM *lwgeom = lwgeom_from_wkb(buf, len, LW_PARSER_CHECK_NONE); + lwgeom_free(lwgeom); + postgis_lwgeom_fuzzer_cleanup_allocations(); + return 0; } diff --git a/fuzzers/wkt_import_fuzzer.cpp b/fuzzers/wkt_import_fuzzer.cpp index 46b514818..79c2dd49b 100644 --- a/fuzzers/wkt_import_fuzzer.cpp +++ b/fuzzers/wkt_import_fuzzer.cpp @@ -26,85 +26,22 @@ * DEALINGS IN THE SOFTWARE. ****************************************************************************/ -#include #include #include #include #include -#include -#include - -extern "C" -{ -#include "liblwgeom.h" +extern "C" { #include "geos_stub.h" #include "proj_stub.h" } -extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv); +#include "liblwgeom_fuzzer.hpp" -// Keep active heap allocated memory corresponding to returns of allocator() -// and reallocator() -std::set oSetPointers; -jmp_buf jmpBuf; - -extern "C" +extern "C" int +LLVMFuzzerInitialize(int * /*argc*/, char *** /*argv*/) { - static void * - allocator(size_t size) - { - void *mem = malloc(size); - oSetPointers.insert(mem); - return mem; - } - - static void - freeor(void *mem) - { - oSetPointers.erase(mem); - free(mem); - } - - static void * - reallocator(void *mem, size_t size) - { - oSetPointers.erase(mem); - void *ret = realloc(mem, size); - oSetPointers.insert(ret); - return ret; - } - - static void - noticereporter(const char *, va_list ) - { - } - - static void - errorreporter(const char *, va_list ) - { - // Cleanup any heap-allocated memory still active - for(std::set::iterator oIter = oSetPointers.begin(); - oIter != oSetPointers.end(); ++oIter ) - { - free(*oIter); - } - oSetPointers.clear(); - // Abort everything to jump to setjmp() call - longjmp(jmpBuf, 1); - } - - static void - debuglogger(int, const char *, va_list) - { - } - -} - -int LLVMFuzzerInitialize(int* /*argc*/, char*** /*argv*/) -{ - lwgeom_set_handlers(malloc, realloc, free, noticereporter, noticereporter); - lwgeom_set_debuglogger(debuglogger); + postgis_lwgeom_fuzzer_initialize(); return 0; } @@ -112,15 +49,18 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len); int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { - char* pszWKT = static_cast(malloc( len + 1 )); - memcpy(pszWKT, buf, len); - pszWKT[len] = '\0'; - if( !setjmp(jmpBuf) ) - { - LWGEOM* lwgeom = lwgeom_from_wkt(pszWKT, LW_PARSER_CHECK_NONE); - lwgeom_free(lwgeom); - //assert( oSetPointers.empty() ); - } - free(pszWKT); - return 0; + char *pszWKT = static_cast(malloc(len + 1)); + if (pszWKT == NULL) + return 0; + + memcpy(pszWKT, buf, len); + pszWKT[len] = '\0'; + if (!POSTGIS_LWGEOM_FUZZER_SETJMP()) + { + LWGEOM *lwgeom = lwgeom_from_wkt(pszWKT, LW_PARSER_CHECK_NONE); + lwgeom_free(lwgeom); + } + postgis_lwgeom_fuzzer_cleanup_allocations(); + free(pszWKT); + return 0; } diff --git a/liblwgeom/cunit/cu_in_twkb.c b/liblwgeom/cunit/cu_in_twkb.c index 02d2db374..5fb4197f0 100644 --- a/liblwgeom/cunit/cu_in_twkb.c +++ b/liblwgeom/cunit/cu_in_twkb.c @@ -3,6 +3,7 @@ * PostGIS - Spatial Types for PostgreSQL * http://postgis.net * Copyright 2010 Paul Ramsey + * Copyright 2026 Darafei Praliaskouski * * This is free software; you can redistribute and/or modify it under * the terms of the GNU General Public Licence. See the COPYING file. @@ -222,7 +223,88 @@ static void test_twkb_in_precision(void) precision = 0; } +static void +test_twkb_in_truncated_extended_dims(void) +{ + const uint8_t twkb[] = { + 0x01, /* POINT with default precision. */ + 0x18 /* Empty geometry plus extended-dimension byte follows. */ + }; + LWGEOM *geom; + cu_error_msg_reset(); + + geom = lwgeom_from_twkb(twkb, sizeof(twkb), LW_PARSER_CHECK_NONE); + + /* Truncated extended-dimension metadata used to be read before the bounds + * check. The expected contract is an ordinary TWKB size error, not an + * out-of-buffer read while constructing the header. + */ + ASSERT_STRING_EQUAL(cu_error_msg, "twkb_parse_state_advance: TWKB structure does not match expected size!"); + CU_ASSERT_PTR_NOT_NULL(geom); + if (geom != NULL) + lwgeom_free(geom); + cu_error_msg_reset(); +} + +static void +test_twkb_in_overlong_varint(void) +{ + const uint8_t twkb[] = {0x02, + 0x00, /* LINESTRING with default precision. */ + 0x80, + 0x80, + 0x80, + 0x80, + 0x80, + 0x80, /* Overlong point-count varint. */ + 0x80, + 0x80, + 0x80, + 0x80, + 0x00}; + LWGEOM *geom; + + cu_error_msg_reset(); + + geom = lwgeom_from_twkb(twkb, sizeof(twkb), LW_PARSER_CHECK_NONE); + + /* Varints longer than the uint64_t encoding space used to shift by more + * than the C type width before the parser could report malformed input. + */ + ASSERT_STRING_EQUAL(cu_error_msg, "varint_u64_decode: varint exceeds 64 bits"); + if (geom != NULL) + lwgeom_free(geom); + cu_error_msg_reset(); +} + +static void +test_twkb_in_count_exceeds_payload(void) +{ + const uint8_t twkb[] = {0x02, + 0x00, /* LINESTRING with default precision. */ + 0xff, + 0xff, + 0xff, + 0xff, + 0x0f, /* UINT32_MAX points. */ + 0x00, + 0x00}; + LWGEOM *geom; + + cu_error_msg_reset(); + + geom = lwgeom_from_twkb(twkb, sizeof(twkb), LW_PARSER_CHECK_NONE); + + /* Count fields are allocation sizes. Reject impossible counts before + * constructing point arrays from a buffer that cannot contain them. + */ + ASSERT_STRING_EQUAL(cu_error_msg, + "twkb_parse_state_has_min_bytes: TWKB element count exceeds remaining payload"); + if (geom != NULL) + lwgeom_free(geom); + cu_error_msg_reset(); +} /* ** Used by test harness to register the tests in this file. @@ -239,4 +321,7 @@ void twkb_in_suite_setup(void) PG_ADD_TEST(suite, test_twkb_in_multipolygon); PG_ADD_TEST(suite, test_twkb_in_collection); PG_ADD_TEST(suite, test_twkb_in_precision); + PG_ADD_TEST(suite, test_twkb_in_truncated_extended_dims); + PG_ADD_TEST(suite, test_twkb_in_overlong_varint); + PG_ADD_TEST(suite, test_twkb_in_count_exceeds_payload); } diff --git a/liblwgeom/lwin_twkb.c b/liblwgeom/lwin_twkb.c index 72fc53306..1262dd999 100644 --- a/liblwgeom/lwin_twkb.c +++ b/liblwgeom/lwin_twkb.c @@ -2,6 +2,7 @@ * * PostGIS - Spatial Types for PostgreSQL * http://postgis.net + * Copyright (C) 2026 Darafei Praliaskouski * * PostGIS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +23,6 @@ * **********************************************************************/ - #include #include "liblwgeom_internal.h" #include "lwgeom_log.h" @@ -81,7 +81,7 @@ LWGEOM* lwgeom_from_twkb_state(twkb_parse_state *s); */ static inline void twkb_parse_state_advance(twkb_parse_state *s, size_t next) { - if( (s->pos + next) > s->twkb_end) + if (next > (size_t)(s->twkb_end - s->pos)) { lwerror("%s: TWKB structure does not match expected size!", __func__); // lwnotice("TWKB structure does not match expected size!"); @@ -125,7 +125,37 @@ static inline void twkb_parse_state_varint_skip(twkb_parse_state *s) return; } +static inline uint32_t +twkb_parse_state_uvarint32(twkb_parse_state *s) +{ + uint64_t val = twkb_parse_state_uvarint(s); + if (val > UINT32_MAX) + { + lwerror("%s: TWKB count exceeds uint32_t", __func__); + return 0; + } + + return (uint32_t)val; +} + +static inline int +twkb_parse_state_has_min_bytes(twkb_parse_state *s, uint32_t count, size_t min_bytes) +{ + const size_t remaining = (size_t)(s->twkb_end - s->pos); + + /* TWKB counts are trusted only after proving that the remaining buffer can + * hold the smallest possible payload for that many elements. This rejects + * impossible allocation requests before constructors size their arrays. + */ + if (min_bytes != 0 && count > remaining / min_bytes) + { + lwerror("%s: TWKB element count exceeds remaining payload", __func__); + return LW_FALSE; + } + + return LW_TRUE; +} static uint32_t lwtype_from_twkb_type(uint8_t twkb_type) { @@ -159,7 +189,14 @@ static uint32_t lwtype_from_twkb_type(uint8_t twkb_type) */ static uint8_t byte_from_twkb_state(twkb_parse_state *s) { - uint8_t val = *(s->pos); + uint8_t val = 0; + + /* CUnit records lwerror and continues, while PostgreSQL and the fuzzers + * abort through their error handlers. Keep the bounds check local so this + * byte helper is safe under both execution models. + */ + if ((s->twkb_end - s->pos) >= WKB_BYTE_SIZE) + val = *(s->pos); twkb_parse_state_advance(s, WKB_BYTE_SIZE); return val; } @@ -183,6 +220,9 @@ static POINTARRAY* ptarray_from_twkb_state(twkb_parse_state *s, uint32_t npoints if( npoints == 0 ) return ptarray_construct_empty(s->has_z, s->has_m, 0); + if (!twkb_parse_state_has_min_bytes(s, npoints, s->ndims)) + return NULL; + pa = ptarray_construct(s->has_z, s->has_m, npoints); dlist = (double*)(pa->serialized_pointlist); for( i = 0; i < npoints; i++ ) @@ -246,7 +286,7 @@ static LWLINE* lwline_from_twkb_state(twkb_parse_state *s) return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); /* Read number of points */ - npoints = twkb_parse_state_uvarint(s); + npoints = twkb_parse_state_uvarint32(s); if ( npoints == 0 ) return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); @@ -281,7 +321,7 @@ static LWPOLY* lwpoly_from_twkb_state(twkb_parse_state *s) return lwpoly_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); /* Read number of rings */ - nrings = twkb_parse_state_uvarint(s); + nrings = twkb_parse_state_uvarint32(s); /* Start w/ empty polygon */ poly = lwpoly_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); @@ -292,10 +332,13 @@ static LWPOLY* lwpoly_from_twkb_state(twkb_parse_state *s) if( nrings == 0 ) return poly; + if (!twkb_parse_state_has_min_bytes(s, nrings, 1)) + return poly; + for( i = 0; i < nrings; i++ ) { /* Ret number of points */ - uint32_t npoints = twkb_parse_state_uvarint(s); + uint32_t npoints = twkb_parse_state_uvarint32(s); POINTARRAY *pa = ptarray_from_twkb_state(s, npoints); /* Skip empty rings */ @@ -335,7 +378,7 @@ static LWPOLY* lwpoly_from_twkb_state(twkb_parse_state *s) */ static LWCOLLECTION* lwmultipoint_from_twkb_state(twkb_parse_state *s) { - int ngeoms, i; + uint32_t ngeoms, i; LWGEOM *geom = NULL; LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m); @@ -345,9 +388,12 @@ static LWCOLLECTION* lwmultipoint_from_twkb_state(twkb_parse_state *s) return col; /* Read number of geometries */ - ngeoms = twkb_parse_state_uvarint(s); + ngeoms = twkb_parse_state_uvarint32(s); LWDEBUGF(4,"Number of geometries %d", ngeoms); + if (s->has_idlist && !twkb_parse_state_has_min_bytes(s, ngeoms, 1)) + return col; + /* It has an idlist, we need to skip that */ if ( s->has_idlist ) { @@ -355,6 +401,9 @@ static LWCOLLECTION* lwmultipoint_from_twkb_state(twkb_parse_state *s) twkb_parse_state_varint_skip(s); } + if (!twkb_parse_state_has_min_bytes(s, ngeoms, s->ndims)) + return col; + for ( i = 0; i < ngeoms; i++ ) { geom = lwpoint_as_lwgeom(lwpoint_from_twkb_state(s)); @@ -373,7 +422,7 @@ static LWCOLLECTION* lwmultipoint_from_twkb_state(twkb_parse_state *s) */ static LWCOLLECTION* lwmultiline_from_twkb_state(twkb_parse_state *s) { - int ngeoms, i; + uint32_t ngeoms, i; LWGEOM *geom = NULL; LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m); @@ -383,10 +432,13 @@ static LWCOLLECTION* lwmultiline_from_twkb_state(twkb_parse_state *s) return col; /* Read number of geometries */ - ngeoms = twkb_parse_state_uvarint(s); + ngeoms = twkb_parse_state_uvarint32(s); LWDEBUGF(4,"Number of geometries %d",ngeoms); + if (s->has_idlist && !twkb_parse_state_has_min_bytes(s, ngeoms, 1)) + return col; + /* It has an idlist, we need to skip that */ if ( s->has_idlist ) { @@ -394,6 +446,9 @@ static LWCOLLECTION* lwmultiline_from_twkb_state(twkb_parse_state *s) twkb_parse_state_varint_skip(s); } + if (!twkb_parse_state_has_min_bytes(s, ngeoms, 1)) + return col; + for ( i = 0; i < ngeoms; i++ ) { geom = lwline_as_lwgeom(lwline_from_twkb_state(s)); @@ -412,7 +467,7 @@ static LWCOLLECTION* lwmultiline_from_twkb_state(twkb_parse_state *s) */ static LWCOLLECTION* lwmultipoly_from_twkb_state(twkb_parse_state *s) { - int ngeoms, i; + uint32_t ngeoms, i; LWGEOM *geom = NULL; LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m); @@ -422,9 +477,12 @@ static LWCOLLECTION* lwmultipoly_from_twkb_state(twkb_parse_state *s) return col; /* Read number of geometries */ - ngeoms = twkb_parse_state_uvarint(s); + ngeoms = twkb_parse_state_uvarint32(s); LWDEBUGF(4,"Number of geometries %d",ngeoms); + if (s->has_idlist && !twkb_parse_state_has_min_bytes(s, ngeoms, 1)) + return col; + /* It has an idlist, we need to skip that */ if ( s->has_idlist ) { @@ -432,6 +490,9 @@ static LWCOLLECTION* lwmultipoly_from_twkb_state(twkb_parse_state *s) twkb_parse_state_varint_skip(s); } + if (!twkb_parse_state_has_min_bytes(s, ngeoms, 1)) + return col; + for ( i = 0; i < ngeoms; i++ ) { geom = lwpoly_as_lwgeom(lwpoly_from_twkb_state(s)); @@ -451,7 +512,7 @@ static LWCOLLECTION* lwmultipoly_from_twkb_state(twkb_parse_state *s) **/ static LWCOLLECTION* lwcollection_from_twkb_state(twkb_parse_state *s) { - int ngeoms, i; + uint32_t ngeoms, i; LWGEOM *geom = NULL; LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m); @@ -461,10 +522,13 @@ static LWCOLLECTION* lwcollection_from_twkb_state(twkb_parse_state *s) return col; /* Read number of geometries */ - ngeoms = twkb_parse_state_uvarint(s); + ngeoms = twkb_parse_state_uvarint32(s); LWDEBUGF(4,"Number of geometries %d",ngeoms); + if (s->has_idlist && !twkb_parse_state_has_min_bytes(s, ngeoms, 1)) + return col; + /* It has an idlist, we need to skip that */ if ( s->has_idlist ) { @@ -472,6 +536,9 @@ static LWCOLLECTION* lwcollection_from_twkb_state(twkb_parse_state *s) twkb_parse_state_varint_skip(s); } + if (!twkb_parse_state_has_min_bytes(s, ngeoms, 2)) + return col; + for ( i = 0; i < ngeoms; i++ ) { geom = lwgeom_from_twkb_state(s); diff --git a/liblwgeom/varint.c b/liblwgeom/varint.c index fca005364..5e62579e7 100644 --- a/liblwgeom/varint.c +++ b/liblwgeom/varint.c @@ -20,10 +20,10 @@ * * Copyright (C) 2014 Sandro Santilli * Copyright (C) 2013 Nicklas Av?n + * Copyright (C) 2026 Darafei Praliaskouski * **********************************************************************/ - #include "varint.h" #include "lwgeom_log.h" #include "liblwgeom.h" @@ -120,6 +120,12 @@ varint_u64_decode(const uint8_t *the_start, const uint8_t *the_end, size_t *size /* Hibit is set, so this isn't the last byte */ if (nByte & 0x80) { + if (nShift >= 63) + { + *size = 0; + lwerror("%s: varint exceeds 64 bits", __func__); + return 0; + } /* We get here when there is more to read in the input varInt */ /* Here we take the least significant 7 bits of the read */ /* byte and put it in the most significant place in the result variable. */ @@ -131,6 +137,12 @@ varint_u64_decode(const uint8_t *the_start, const uint8_t *the_end, size_t *size } else { + if (nShift >= 64 || (nShift == 63 && nByte > 1)) + { + *size = 0; + lwerror("%s: varint exceeds 64 bits", __func__); + return 0; + } /* move the "cursor" one step */ ptr++; /* Move the last read byte to the most significant */ @@ -207,5 +219,3 @@ int8_t unzigzag8(uint8_t val) ((int8_t)(val >> 1)) : (-1 * (int8_t)((val+1) >> 1)); } - - ----------------------------------------------------------------------- Summary of changes: GNUmakefile.in | 13 ++ NEWS | 2 + fuzzers/Makefile | 77 ++++++++- fuzzers/README.md | 14 +- fuzzers/build_google_oss_fuzzers.sh | 73 ++++++-- fuzzers/build_oss_fuzz.sh | 8 +- fuzzers/install_oss_fuzz_build_deps.sh | 4 +- fuzzers/liblwgeom_fuzzer.hpp | 164 ++++++++++++++++++ fuzzers/raster_deserialize_fuzzer.c | 185 +++++++++++++++++++++ ...r.options => raster_deserialize_fuzzer.options} | 0 fuzzers/raster_deserialize_fuzzer_seed_corpus.zip | Bin 0 -> 586 bytes fuzzers/twkb_import_fuzzer.cpp | 56 +++++++ ...t_fuzzer.options => twkb_import_fuzzer.options} | 0 fuzzers/twkb_import_fuzzer_seed_corpus.zip | Bin 0 -> 680 bytes fuzzers/wkb_import_fuzzer.cpp | 90 ++-------- fuzzers/wkt_import_fuzzer.cpp | 98 +++-------- liblwgeom/cunit/cu_in_twkb.c | 85 ++++++++++ liblwgeom/lwin_twkb.c | 95 +++++++++-- liblwgeom/varint.c | 16 +- 19 files changed, 785 insertions(+), 195 deletions(-) create mode 100644 fuzzers/liblwgeom_fuzzer.hpp create mode 100644 fuzzers/raster_deserialize_fuzzer.c copy fuzzers/{geojson_import_fuzzer.options => raster_deserialize_fuzzer.options} (100%) create mode 100644 fuzzers/raster_deserialize_fuzzer_seed_corpus.zip create mode 100644 fuzzers/twkb_import_fuzzer.cpp copy fuzzers/{geojson_import_fuzzer.options => twkb_import_fuzzer.options} (100%) create mode 100644 fuzzers/twkb_import_fuzzer_seed_corpus.zip hooks/post-receive -- PostGIS From git at osgeo.org Wed Jun 17 22:03:58 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 17 Jun 2026 22:03:58 -0700 (PDT) Subject: [SCM] postgis.net branch website updated. clarity-final-187-g59afecf Message-ID: <20260618050358.A0A781B7836@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "postgis.net". The branch, website has been updated via 59afecfb5f09b9ef4cf53049a1a87ae86d4c3f8d (commit) from ade329e6cc06842f4ccb2d36a408f834afc0ac46 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 59afecfb5f09b9ef4cf53049a1a87ae86d4c3f8d Author: Regina Obe Date: Thu Jun 18 01:02:11 2026 -0400 Add maumap and snowflake, remove crunchydata and kontur from sponsors list diff --git a/content/community/support.md b/content/community/support.md index e268669..ec71224 100644 --- a/content/community/support.md +++ b/content/community/support.md @@ -24,10 +24,10 @@ The PostGIS community historically holds a small development meeting once a year The most direct support the PostGIS development community gets is via governments, companies, and NGOs that directly fund the work of a contributor to make the software or the supporting materials better. The following organizations have employed a contributor over the past year. - + - + diff --git a/static/sponsors/logo_snowflake.png b/static/sponsors/logo_snowflake.png new file mode 100644 index 0000000..96c9e04 Binary files /dev/null and b/static/sponsors/logo_snowflake.png differ diff --git a/static/sponsors/maumap_logo_inline_with_background_2000.webp b/static/sponsors/maumap_logo_inline_with_background_2000.webp new file mode 100644 index 0000000..84f506c Binary files /dev/null and b/static/sponsors/maumap_logo_inline_with_background_2000.webp differ ----------------------------------------------------------------------- Summary of changes: content/community/support.md | 4 ++-- static/sponsors/logo_snowflake.png | Bin 0 -> 29077 bytes .../maumap_logo_inline_with_background_2000.webp | Bin 0 -> 7620 bytes 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 static/sponsors/logo_snowflake.png create mode 100644 static/sponsors/maumap_logo_inline_with_background_2000.webp hooks/post-receive -- postgis.net From git at osgeo.org Wed Jun 17 23:42:49 2026 From: git at osgeo.org (git at osgeo.org) Date: Wed, 17 Jun 2026 23:42:49 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-582-ge788f6f41 Message-ID: <20260618064249.711801B9BA3@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via e788f6f418b687bdc81e2f37e306d74b38eba651 (commit) from c741f2c2394db10053941c0034dfbb64d16f3af7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e788f6f418b687bdc81e2f37e306d74b38eba651 Author: Sandro Santilli Date: Thu Jun 18 08:25:16 2026 +0200 Expand CODE_OF_CONDUCT to be nice with those who don't have a browser diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index a700c99b6..0133ab680 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,17 @@ Code of Conduct =============== -See [the PostGIS Code of Conduct](https://postgis.net/community/conduct/). +We expect every partecipant in the PostGIS community to honour the PostGIS +Code of Conduct as published on https://postgis.net/community/conduct/ + +If you don't have a web browser handy but are happy to clone a git repository +you can find the Code of Conduct in the website repository: + + # clone + git clone https://gitea.osgeo.org/postgis/postgis.net + + # read + less postgis.net/content/community/conduct.md + + # dig history + git -C postgis.net log content/community/conduct.md ----------------------------------------------------------------------- Summary of changes: CODE_OF_CONDUCT.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 18 01:39:16 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 01:39:16 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-583-g857652e24 Message-ID: <20260618083916.5F0C31BAB7A@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 857652e24926f169f74f0caf921e674bb65f5d8b (commit) from e788f6f418b687bdc81e2f37e306d74b38eba651 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 857652e24926f169f74f0caf921e674bb65f5d8b Author: Teramoto Ikuhiro Date: Thu Jun 18 07:42:49 2026 +0000 Translated PostGIS Manual using Weblate (Japanese) Currently translated at 98.4% (5495 of 5579 strings) Translation: postgis/PostGIS Manual Translate-URL: https://weblate.osgeo.org/projects/postgis/postgis-manual/ja/ diff --git a/doc/po/ja/postgis-manual.po b/doc/po/ja/postgis-manual.po index 5ffd852fe..38219613e 100644 --- a/doc/po/ja/postgis-manual.po +++ b/doc/po/ja/postgis-manual.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: postgis 3.5\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n" "POT-Creation-Date: 2026-06-12 20:29+0000\n" -"PO-Revision-Date: 2026-05-27 03:39+0000\n" +"PO-Revision-Date: 2026-06-18 08:39+0000\n" "Last-Translator: Teramoto Ikuhiro \n" "Language-Team: Japanese \n" @@ -2370,7 +2370,7 @@ msgid "" "check to the area specified by the bbox parameter." msgstr "" "????????????gridSize?????????????" -"?????????????????????bbox??????" +"?????????????????????bbox??????" "???????????????" #. Tag: para @@ -4037,7 +4037,7 @@ msgstr "" #. Tag: para #, no-c-format msgid "Availability: 3.7" -msgstr "" +msgstr "Availability: 3.7" #. Tag: title #, no-c-format @@ -9437,6 +9437,9 @@ msgid "" "GEOMETRYCOLLECTION, MULTIPOINT, MULTILINESTRING, MULTICURVE, MULTIPOLYGON, " "or POLYHEDRALSURFACE. Otherwise, returns NULL." msgstr "" +"?????????GEOMETRYCOLLECTION, MULTIPOINT, MULTILINESTRING, " +"MULTICURVE, MULTIPOLYGON, POLYHEDRALSURFACE??????1????N??????" +"???????????????????????NULL??????" #. Tag: para #, no-c-format @@ -10199,12 +10202,14 @@ msgstr "" "?????????????NULL??????" #. Tag: para -#, no-c-format +#, fuzzy, no-c-format msgid "" "Index is 1-based as for OGC specs since version 0.8.0. Backward indexing " "(negative index) is not in OGC. Previous versions implemented this as 0-" "based instead." msgstr "" +"OGC????0.8.0????????1????????????? (??????)?" +"OGC???????????????0?????????????" #. Tag: para #, no-c-format @@ -11454,6 +11459,8 @@ msgid "" "input geometries into connected trees using the Minimum Spanning Tree " "algorithm." msgstr "" +"??????????????????????????????????????" +"????????????????ID?????????????" #. Tag: para #, no-c-format @@ -11463,6 +11470,10 @@ msgid "" "cluster number that the geometry argument participates in, or zero if it is " "not part of the minimum tree." msgstr "" +"????????????? (Minimum Spanning Tree, MST)?????" +"?????????????????????????????????????" +"??????????????????????????????????????0" +"??????" #. Tag: para #, no-c-format ----------------------------------------------------------------------- Summary of changes: doc/po/ja/postgis-manual.po | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 18 05:23:33 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 05:23:33 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-585-g014d02c42 Message-ID: <20260618122333.484B81BFAE9@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 014d02c42befac740f904b1cceca52391b671097 (commit) via cff529aa81f12c0dc12b2b273a0e836e38c3f122 (commit) from 857652e24926f169f74f0caf921e674bb65f5d8b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 014d02c42befac740f904b1cceca52391b671097 Merge: 857652e24 cff529aa8 Author: Darafei Praliaskouski Date: Thu Jun 18 16:18:43 2026 +0400 Merge PR #959: Stabilize NURBS approximation regression output Apply explicit two-decimal ST_AsText output for the high-tolerance NURBS approximation regression so SFCGAL/CGAL precision drift does not fail otherwise unrelated CI runs. Validation: GitHub CI green on cff529aa81f12c0dc12b2b273a0e836e38c3f122; local git diff --check upstream/master..HEAD passed; local make -C sfcgal/regress check RUNTESTFLAGS='--verbose --extension' TESTS="/home/kom/proj/osgeo/postgis/sfcgal/regress/nurbs.sql" passed, including automatic upgrade rerun. commit cff529aa81f12c0dc12b2b273a0e836e38c3f122 Author: Darafei Praliaskouski Date: Thu Jun 18 11:23:12 2026 +0400 Stabilize NURBS approximation regression output diff --git a/sfcgal/regress/nurbs.sql b/sfcgal/regress/nurbs.sql index a71fc9f54..bed1a0361 100644 --- a/sfcgal/regress/nurbs.sql +++ b/sfcgal/regress/nurbs.sql @@ -96,7 +96,7 @@ SELECT 'approximate_high_tol', ST_AsText(CG_NurbsCurveApproximate( 'LINESTRING(0 0, 1 2.1, 2 1.9, 3 3.2, 4 2.8, 5 1)'::geometry, 2, 0.5 -)); +), 2); -- Test approximation with 3D points SELECT 'approximate_3d', ST_AsText(CG_NurbsCurveApproximate( diff --git a/sfcgal/regress/nurbs_expected b/sfcgal/regress/nurbs_expected index a7e2856fb..9ccee264f 100644 --- a/sfcgal/regress/nurbs_expected +++ b/sfcgal/regress/nurbs_expected @@ -10,6 +10,6 @@ ERROR: Data points must be a LINESTRING ERROR: Need at least 4 data points for degree 3 interpolation approximate_default|NURBSCURVE(DEGREE 3,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(0.18 -0.15),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(1.49 4.36),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(3.33 1.33),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(4.34 0.83),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 0),WEIGHT 1)),KNOTS (KNOT(0,4),KNOT(0.46,1),KNOT(0.64,1),KNOT(1,4))) approximate_max_ctrl|NURBSCURVE(DEGREE 3,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(3.3 6.18),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(6.48 40.13),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(8.84 73.32),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(10 100),WEIGHT 1)),KNOTS (KNOT(0,4),KNOT(0.21,1),KNOT(1,4))) -approximate_high_tol|NURBSCURVE(DEGREE 2,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(-0.048424154393691 2.640915492953116),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.237552942255657 1.646186724700419),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.786598026195684 3.476253776863865),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(4.840573182610214 2.429625830321494),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 1),WEIGHT 1)),KNOTS (KNOT(0,3),KNOT(0.349154606588781,1),KNOT(0.512902297757245,1),KNOT(0.680173066921787,1),KNOT(1,3))) +approximate_high_tol|NURBSCURVE(DEGREE 2,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(-0.05 2.64),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.24 1.65),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.79 3.48),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(4.84 2.43),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 1),WEIGHT 1)),KNOTS (KNOT(0,3),KNOT(0.35,1),KNOT(0.51,1),KNOT(0.68,1),KNOT(1,3))) approximate_3d|NURBSCURVE Z (DEGREE 3,CONTROLPOINTS Z (NURBSPOINT(WEIGHTEDPOINT Z (0 0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (0.18 -0.15 -1.29),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (1.49 4.36 3.35),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (3.33 1.33 0.38),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (4.34 0.83 -0.44),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (5 0 0),WEIGHT 1)),KNOTS (KNOT(0,4),KNOT(0.46,1),KNOT(0.64,1),KNOT(1,4))) ERROR: Need at least 4 data points for degree 3 approximation ----------------------------------------------------------------------- Summary of changes: sfcgal/regress/nurbs.sql | 2 +- sfcgal/regress/nurbs_expected | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 18 05:36:18 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 05:36:18 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-587-g9b9950de1 Message-ID: <20260618123618.4AAC21C02AC@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 9b9950de1262a24c41e9e4d647627b1816a6ac52 (commit) via 9cc6dac3d6d9c119667a438118cb4b5b6bb21c3b (commit) from 014d02c42befac740f904b1cceca52391b671097 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 9b9950de1262a24c41e9e4d647627b1816a6ac52 Merge: 014d02c42 9cc6dac3d Author: Darafei Praliaskouski Date: Thu Jun 18 16:27:57 2026 +0400 Merge PR #888: Fix SFCGAL visibility empty input handling Avoid stale detoasted geometry access in CG_Visibility empty-input compatibility handling for builds against SFCGAL before 2.2, while preserving the empty polygon result for empty inputs. commit 9cc6dac3d6d9c119667a438118cb4b5b6bb21c3b Author: Darafei Praliaskouski Date: Tue Jun 16 17:15:54 2026 +0400 Fix SFCGAL visibility empty input handling diff --git a/NEWS b/NEWS index 4cd72746a..cf06261d4 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,9 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - GH-888, [sfcgal] Avoid stale detoasted geometry access in + CG_Visibility empty-input handling for SFCGAL < 2.2 + (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/sfcgal/lwgeom_sfcgal.c b/sfcgal/lwgeom_sfcgal.c index 5ee90f878..0289ccb21 100644 --- a/sfcgal/lwgeom_sfcgal.c +++ b/sfcgal/lwgeom_sfcgal.c @@ -19,6 +19,7 @@ ********************************************************************** * * Copyright 2012-2020 Oslandia + * Copyright 2026 Darafei Praliaskouski * **********************************************************************/ @@ -1232,22 +1233,30 @@ sfcgal_visibility_point(PG_FUNCTION_ARGS) input0 = PG_GETARG_GSERIALIZED_P(0); srid = gserialized_get_srid(input0); input1 = PG_GETARG_GSERIALIZED_P(1); - polygon = POSTGIS2SFCGALGeometry(input0); - PG_FREE_IF_COPY(input0, 0); - point = POSTGIS2SFCGALGeometry(input1); - PG_FREE_IF_COPY(input1, 1); #if POSTGIS_SFCGAL_VERSION < 20200 + /* + * SFCGAL < 2.2 needs PostGIS to preserve the empty-input result. + * Check this before converting and freeing detoasted inputs, because + * gserialized_is_empty() must not inspect a freed copy. + */ if (gserialized_is_empty(input0) || gserialized_is_empty(input1)) { result = sfcgal_polygon_create(); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); + PG_FREE_IF_COPY(input0, 0); + PG_FREE_IF_COPY(input1, 1); PG_RETURN_POINTER(output); } #endif + polygon = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + point = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + result = sfcgal_geometry_visibility_point(polygon, point); sfcgal_geometry_delete(polygon); sfcgal_geometry_delete(point); @@ -1282,24 +1291,33 @@ sfcgal_visibility_segment(PG_FUNCTION_ARGS) srid = gserialized_get_srid(input0); input1 = PG_GETARG_GSERIALIZED_P(1); input2 = PG_GETARG_GSERIALIZED_P(2); - polygon = POSTGIS2SFCGALGeometry(input0); - PG_FREE_IF_COPY(input0, 0); - pointA = POSTGIS2SFCGALGeometry(input1); - PG_FREE_IF_COPY(input1, 1); - pointB = POSTGIS2SFCGALGeometry(input2); - PG_FREE_IF_COPY(input2, 2); #if POSTGIS_SFCGAL_VERSION < 20200 + /* + * SFCGAL < 2.2 needs PostGIS to preserve the empty-input result. + * Check this before converting and freeing detoasted inputs, because + * gserialized_is_empty() must not inspect a freed copy. + */ if (gserialized_is_empty(input0) || gserialized_is_empty(input1) || gserialized_is_empty(input2)) { result = sfcgal_polygon_create(); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); + PG_FREE_IF_COPY(input0, 0); + PG_FREE_IF_COPY(input1, 1); + PG_FREE_IF_COPY(input2, 2); PG_RETURN_POINTER(output); } #endif + polygon = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + pointA = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + pointB = POSTGIS2SFCGALGeometry(input2); + PG_FREE_IF_COPY(input2, 2); + result = sfcgal_geometry_visibility_segment(polygon, pointA, pointB); sfcgal_geometry_delete(polygon); sfcgal_geometry_delete(pointA); ----------------------------------------------------------------------- Summary of changes: NEWS | 3 +++ sfcgal/lwgeom_sfcgal.c | 38 ++++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 18 05:40:20 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 05:40:20 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-589-gea9c759b0 Message-ID: <20260618124020.7AD561C03D8@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via ea9c759b0b8d6c9b27fa5e12c5bb0be8b3405c66 (commit) via 8c034d0faef7819f920cb4d921068217f679c1cd (commit) from 9b9950de1262a24c41e9e4d647627b1816a6ac52 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit ea9c759b0b8d6c9b27fa5e12c5bb0be8b3405c66 Merge: 9b9950de1 8c034d0fa Author: Darafei Praliaskouski Date: Thu Jun 18 16:37:46 2026 +0400 Merge PR #900: Fix SFCGAL regression gating and roof checks Gate polygon-repair regression tests on the CGAL version that provides the exercised behavior, keep SFCGAL 2.3-only regression selection together, and add generic roof-generation checks against the specialized wrappers. commit 8c034d0faef7819f920cb4d921068217f679c1cd Author: Darafei Praliaskouski Date: Tue Jun 16 23:37:32 2026 +0400 sfcgal: fix regression gating and roof checks diff --git a/sfcgal/regress/roofgeneration.sql b/sfcgal/regress/roofgeneration.sql index 106f5105e..50b11ab16 100644 --- a/sfcgal/regress/roofgeneration.sql +++ b/sfcgal/regress/roofgeneration.sql @@ -13,4 +13,10 @@ SELECT 'generic_hipped', ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0 SELECT 'generic_flat', ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'FLAT', 2.0, 30.0, 0)); SELECT 'generic_gable_3d', ST_CoordDim(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'GABLE', 2.0, 30.0, 0)); SELECT 'generic_skillion_3d', ST_CoordDim(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'SKILLION', 2.0, 30.0, 0)); +SELECT 'generic_gable_matches_specialized', + ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'GABLE', 5.0, 15.0, 0)) = + ST_AsText(CG_GenerateGableRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 5.0, 15.0)); +SELECT 'generic_skillion_matches_specialized', + ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'SKILLION', 5.0, 15.0, 0)) = + ST_AsText(CG_GenerateSkillionRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 5.0, 15.0, 0)); SELECT 'invalid_type', CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'DOME', 2.0, 30.0, 0); diff --git a/sfcgal/regress/roofgeneration_expected b/sfcgal/regress/roofgeneration_expected index d67b1e24d..d90fef96f 100644 --- a/sfcgal/regress/roofgeneration_expected +++ b/sfcgal/regress/roofgeneration_expected @@ -8,4 +8,6 @@ generic_hipped|POLYHEDRALSURFACE Z (((0 4 0,4 4 0,4 0 0,0 0 0,0 4 0)),((0 4 0,0 generic_flat|POLYHEDRALSURFACE Z (((0 0 0,0 4 0,4 4 0,4 0 0,0 0 0)),((0 0 2,4 0 2,4 4 2,0 4 2,0 0 2)),((0 0 0,0 0 2,0 4 2,0 4 0,0 0 0)),((0 4 0,0 4 2,4 4 2,4 4 0,0 4 0)),((4 4 0,4 4 2,4 0 2,4 0 0,4 4 0)),((4 0 0,4 0 2,0 0 2,0 0 0,4 0 0))) generic_gable_3d|3 generic_skillion_3d|3 +generic_gable_matches_specialized|t +generic_skillion_matches_specialized|t ERROR: CG_GenerateRoof: unknown roof type 'DOME', expected FLAT, HIPPED, GABLE or SKILLION diff --git a/sfcgal/regress/tests.mk.in b/sfcgal/regress/tests.mk.in index 89b2e4627..c1c39d069 100644 --- a/sfcgal/regress/tests.mk.in +++ b/sfcgal/regress/tests.mk.in @@ -49,13 +49,15 @@ ifeq ($(shell expr "$(POSTGIS_SFCGAL_VERSION)" ">=" 20300),1) TESTS += \ $(top_srcdir)/sfcgal/regress/alphashape_components.sql \ $(top_srcdir)/sfcgal/regress/roofgeneration.sql \ - $(top_srcdir)/sfcgal/regress/polygonrepair.sql \ $(top_srcdir)/sfcgal/regress/approximatemedialaxis_projected.sql \ $(top_srcdir)/sfcgal/regress/nurbs.sql - ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 601),1) - TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union.sql - else - TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union_pre61.sql + ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 600),1) + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair.sql + ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 601),1) + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union.sql + else + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union_pre61.sql + endif endif else TESTS += \ ----------------------------------------------------------------------- Summary of changes: sfcgal/regress/roofgeneration.sql | 6 ++++++ sfcgal/regress/roofgeneration_expected | 2 ++ sfcgal/regress/tests.mk.in | 12 +++++++----- 3 files changed, 15 insertions(+), 5 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 18 05:48:00 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 05:48:00 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-591-gb90c3dbb1 Message-ID: <20260618124800.5FF071C0DFA@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via b90c3dbb175c92ea3c113c38cacc6a3617a51695 (commit) via 67d6df38c343a8be4605061e330587d9aafaffaf (commit) from ea9c759b0b8d6c9b27fa5e12c5bb0be8b3405c66 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b90c3dbb175c92ea3c113c38cacc6a3617a51695 Merge: ea9c759b0 67d6df38c Author: Darafei Praliaskouski Date: Thu Jun 18 16:46:19 2026 +0400 Merge PR #932: Mark truncated PostgreSQL messages Make libpgcommon append a truncation marker when fixed-size PostgreSQL message formatting overflows, so error, warning, notice, and debug messages no longer lose their tail silently. diff --cc NEWS index a314e2be7,2910943b4..5ca8c2631 --- a/NEWS +++ b/NEWS @@@ -55,9 -54,8 +55,11 @@@ To take advantage of all postgis_sfcga finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - GH-888, [sfcgal] Avoid stale detoasted geometry access in + CG_Visibility empty-input handling for SFCGAL < 2.2 + (Darafei Praliaskouski) + - #3179, Mark truncated libpgcommon PostgreSQL messages instead of silently + dropping the tail (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in commit 67d6df38c343a8be4605061e330587d9aafaffaf Author: Darafei Praliaskouski Date: Wed Jun 17 09:57:39 2026 +0400 libpgcommon: mark truncated PostgreSQL messages diff --git a/NEWS b/NEWS index 4cd72746a..2910943b4 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - #3179, Mark truncated libpgcommon PostgreSQL messages instead of silently + dropping the tail (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/libpgcommon/lwgeom_pg.c b/libpgcommon/lwgeom_pg.c index fbbe5b73b..d2e2fd061 100644 --- a/libpgcommon/lwgeom_pg.c +++ b/libpgcommon/lwgeom_pg.c @@ -43,8 +43,10 @@ #include #include #include +#include #define PGC_ERRMSG_MAXLEN 2048 //256 +#define PGC_ERRMSG_TRUNCATED " [truncated]" /****************************************************************************************/ /* Global to hold all the run-time constants */ @@ -350,6 +352,28 @@ pg_free(void *ptr) pfree(ptr); } +static void +pg_format_message(char *errmsg, size_t errmsg_size, const char *fmt, va_list ap) +{ + int written = vsnprintf(errmsg, errmsg_size, fmt, ap); + + if (written < 0) + { + strlcpy(errmsg, "[error formatting PostGIS message]", errmsg_size); + return; + } + + if ((size_t)written >= errmsg_size) + { + const size_t suffix_size = strlen(PGC_ERRMSG_TRUNCATED); + + if (errmsg_size > suffix_size) + memcpy(errmsg + errmsg_size - suffix_size - 1, + PGC_ERRMSG_TRUNCATED, + suffix_size + 1); + } +} + static void pg_error(const char *fmt, va_list ap) __attribute__ (( format(printf, 1, 0) )); static void @@ -357,9 +381,7 @@ pg_error(const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); ereport(ERROR, (errmsg_internal("%s", errmsg))); } @@ -370,9 +392,7 @@ pg_warning(const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); ereport(WARNING, (errmsg_internal("%s", errmsg))); } @@ -383,9 +403,7 @@ pg_notice(const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); ereport(NOTICE, (errmsg_internal("%s", errmsg))); } @@ -395,8 +413,7 @@ static void pg_debug(int level, const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); int pglevel[6] = {NOTICE, DEBUG1, DEBUG2, DEBUG3, DEBUG4, DEBUG5}; if ( level >= 0 && level <= 5 ) ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ libpgcommon/lwgeom_pg.c | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 11 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 18 05:57:26 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 05:57:26 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-593-gc3004485c Message-ID: <20260618125726.529911C1683@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via c3004485c01808aaedefbf75d6b8de9090739811 (commit) via d078fd9e158e18640e901eed329dca1f0cbc0133 (commit) from b90c3dbb175c92ea3c113c38cacc6a3617a51695 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c3004485c01808aaedefbf75d6b8de9090739811 Merge: b90c3dbb1 d078fd9e1 Author: Darafei Praliaskouski Date: Thu Jun 18 16:55:30 2026 +0400 Merge PR #903: Avoid size_t log formats for MinGW Replace size_t formatting in liblwgeom logging and error messages with unsigned-long casts so MinGW builds do not warn on unsupported %zu format specifiers. diff --cc NEWS index 5ca8c2631,1aa7f0626..6f57e1a8c --- a/NEWS +++ b/NEWS @@@ -55,11 -54,8 +55,13 @@@ To take advantage of all postgis_sfcga finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - GH-888, [sfcgal] Avoid stale detoasted geometry access in + CG_Visibility empty-input handling for SFCGAL < 2.2 + (Darafei Praliaskouski) + - #3179, Mark truncated libpgcommon PostgreSQL messages instead of silently + dropping the tail (Darafei Praliaskouski) + - #6003, Avoid size_t formats in liblwgeom logging/error wrappers for + MinGW builds (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in commit d078fd9e158e18640e901eed329dca1f0cbc0133 Author: Darafei Praliaskouski Date: Wed Jun 17 01:19:03 2026 +0400 Avoid size_t formats in lwgeom logs diff --git a/NEWS b/NEWS index 4cd72746a..1aa7f0626 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - #6003, Avoid size_t formats in liblwgeom logging/error wrappers for + MinGW builds (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/liblwgeom/lwgeom_api.c b/liblwgeom/lwgeom_api.c index 99e51b0ca..bda927801 100644 --- a/liblwgeom/lwgeom_api.c +++ b/liblwgeom/lwgeom_api.c @@ -19,12 +19,10 @@ ********************************************************************** * * Copyright 2001-2006 Refractions Research Inc. - * Copyright 2017 Darafei Praliaskouski + * Copyright 2017-2026 Darafei Praliaskouski * **********************************************************************/ - - #include "liblwgeom_internal.h" #include "lwgeom_log.h" @@ -452,8 +450,8 @@ void printPA(POINTARRAY *pa) else mflag = ""; lwnotice(" POINTARRAY%s{", mflag); - lwnotice(" ndims=%i, ptsize=%zu", - FLAGS_NDIMS(pa->flags), ptarray_point_size(pa)); + lwnotice( + " ndims=%i, ptsize=%lu", FLAGS_NDIMS(pa->flags), (unsigned long)ptarray_point_size(pa)); lwnotice(" npoints = %u", pa->npoints); for (t = 0; t < pa->npoints; t++) diff --git a/liblwgeom/ptarray.c b/liblwgeom/ptarray.c index 7631081bc..3baae4da6 100644 --- a/liblwgeom/ptarray.c +++ b/liblwgeom/ptarray.c @@ -20,10 +20,10 @@ * * Copyright (C) 2012-2021 Sandro Santilli * Copyright (C) 2001-2006 Refractions Research Inc. + * Copyright 2026 Darafei Praliaskouski * **********************************************************************/ - #include #include #include @@ -533,13 +533,11 @@ ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where) POINT4D pbuf; size_t ptsize = ptarray_point_size(pa); - LWDEBUGF(3, "pa %p p %p size %zu where %u", - pa, p, pdims, where); + LWDEBUGF(3, "pa %p p %p size %lu where %u", pa, p, (unsigned long)pdims, where); if ( pdims < 2 || pdims > 4 ) { - lwerror("ptarray_addPoint: point dimension out of range (%zu)", - pdims); + lwerror("ptarray_addPoint: point dimension out of range (%lu)", (unsigned long)pdims); return NULL; } ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ liblwgeom/lwgeom_api.c | 8 +++----- liblwgeom/ptarray.c | 8 +++----- 3 files changed, 8 insertions(+), 10 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 18 06:20:06 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 06:20:06 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-589-g07e64e5f0 Message-ID: <20260618132007.563711C1B3E@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated discards c3004485c01808aaedefbf75d6b8de9090739811 (commit) discards b90c3dbb175c92ea3c113c38cacc6a3617a51695 (commit) discards ea9c759b0b8d6c9b27fa5e12c5bb0be8b3405c66 (commit) discards 9b9950de1262a24c41e9e4d647627b1816a6ac52 (commit) discards 014d02c42befac740f904b1cceca52391b671097 (commit) discards cff529aa81f12c0dc12b2b273a0e836e38c3f122 (commit) discards 8c034d0faef7819f920cb4d921068217f679c1cd (commit) discards 9cc6dac3d6d9c119667a438118cb4b5b6bb21c3b (commit) discards d078fd9e158e18640e901eed329dca1f0cbc0133 (commit) discards 67d6df38c343a8be4605061e330587d9aafaffaf (commit) via 07e64e5f0f1361abec66940c45b951d835c5bd1f (commit) via 8c5ead8c7e0c3b152929189b8f5e4f00f23525af (commit) via ab211fe67c97b239ff2943e4ead65a71fa0fb012 (commit) via 0edc31efc4d80c30801755b91c82297281a35e21 (commit) via 5673ac9fdedc6cd309a8b3b6fca0f1a0ad5cc737 (commit) via f1330c340b2d84e93738ea042ee582b003e4d028 (commit) This update added new revisions after undoing existing revisions. That is to say, the old revision is not a strict subset of the new revision. This situation occurs when you --force push a change and generate a repository containing something like this: * -- * -- B -- O -- O -- O (c3004485c01808aaedefbf75d6b8de9090739811) \ N -- N -- N (07e64e5f0f1361abec66940c45b951d835c5bd1f) When this happens we assume that you've already had alert emails for all of the O revisions, and so we here report only the revisions in the N branch from the common base, B. Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 07e64e5f0f1361abec66940c45b951d835c5bd1f Author: Darafei Praliaskouski Date: Wed Jun 17 01:16:48 2026 +0400 Fix signed hex WKB lookup Cast hex input bytes to uint8_t before indexing the liblwgeom hex lookup table, and cover malformed high-bit WKB input in CUnit. Closes https://github.com/postgis/postgis/pull/902 Closes #6080 diff --git a/NEWS b/NEWS index 6f57e1a8c..6ad9ec024 100644 --- a/NEWS +++ b/NEWS @@ -74,6 +74,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #5948, [topology] Prevent MakeTopologyPrecise from erasing edges when grid size exceeds their extent (Darafei Praliaskouski) - #5959, Prevent histogram target overflow when analysing massive tables (Darafei Praliaskouski) + - #6080, Avoid out-of-bounds hex WKB lookup for high-bit input bytes + (Darafei Praliaskouski) - #4828, geometry_columns handles NOT VALID SRID checks without errors (Darafei Praliaskouski) - #6048, [raster] ST_Clip no longer crashes when clipping sparse band selections (Darafei Praliaskouski) diff --git a/liblwgeom/cunit/cu_in_wkb.c b/liblwgeom/cunit/cu_in_wkb.c index 213c44a2e..c855dccf3 100644 --- a/liblwgeom/cunit/cu_in_wkb.c +++ b/liblwgeom/cunit/cu_in_wkb.c @@ -212,6 +212,10 @@ static void test_wkb_in_multisurface(void) {} static void test_wkb_in_malformed(void) { + char highbit_hex[3] = {(char)0xff, '0', '\0'}; + + cu_wkb_malformed_in(highbit_hex); + /* OSSFUXX */ cu_wkb_malformed_in("0000000008200000002020202020202020"); diff --git a/liblwgeom/lwin_wkb.c b/liblwgeom/lwin_wkb.c index a957e16c6..762d5cd3a 100644 --- a/liblwgeom/lwin_wkb.c +++ b/liblwgeom/lwin_wkb.c @@ -105,8 +105,8 @@ uint8_t* bytes_from_hexbytes(const char *hexbuf, size_t hexsize) for( i = 0; i < hexsize/2; i++ ) { - h1 = hex2char[(int)hexbuf[2*i]]; - h2 = hex2char[(int)hexbuf[2*i+1]]; + h1 = hex2char[(uint8_t)hexbuf[2*i]]; + h2 = hex2char[(uint8_t)hexbuf[2*i+1]]; if( h1 > 15 ) lwerror("Invalid hex character (%c) encountered", hexbuf[2*i]); if( h2 > 15 ) commit 8c5ead8c7e0c3b152929189b8f5e4f00f23525af Author: Darafei Praliaskouski Date: Wed Jun 17 01:19:03 2026 +0400 Avoid size_t formats in lwgeom logs Replace size_t formatting in liblwgeom logging and error messages with unsigned-long casts so MinGW builds do not warn on unsupported %zu format specifiers. Closes https://github.com/postgis/postgis/pull/903 Closes #6003 diff --git a/NEWS b/NEWS index 5ca8c2631..6f57e1a8c 100644 --- a/NEWS +++ b/NEWS @@ -60,6 +60,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed (Darafei Praliaskouski) - #3179, Mark truncated libpgcommon PostgreSQL messages instead of silently dropping the tail (Darafei Praliaskouski) + - #6003, Avoid size_t formats in liblwgeom logging/error wrappers for + MinGW builds (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/liblwgeom/lwgeom_api.c b/liblwgeom/lwgeom_api.c index 99e51b0ca..bda927801 100644 --- a/liblwgeom/lwgeom_api.c +++ b/liblwgeom/lwgeom_api.c @@ -19,12 +19,10 @@ ********************************************************************** * * Copyright 2001-2006 Refractions Research Inc. - * Copyright 2017 Darafei Praliaskouski + * Copyright 2017-2026 Darafei Praliaskouski * **********************************************************************/ - - #include "liblwgeom_internal.h" #include "lwgeom_log.h" @@ -452,8 +450,8 @@ void printPA(POINTARRAY *pa) else mflag = ""; lwnotice(" POINTARRAY%s{", mflag); - lwnotice(" ndims=%i, ptsize=%zu", - FLAGS_NDIMS(pa->flags), ptarray_point_size(pa)); + lwnotice( + " ndims=%i, ptsize=%lu", FLAGS_NDIMS(pa->flags), (unsigned long)ptarray_point_size(pa)); lwnotice(" npoints = %u", pa->npoints); for (t = 0; t < pa->npoints; t++) diff --git a/liblwgeom/ptarray.c b/liblwgeom/ptarray.c index 7631081bc..3baae4da6 100644 --- a/liblwgeom/ptarray.c +++ b/liblwgeom/ptarray.c @@ -20,10 +20,10 @@ * * Copyright (C) 2012-2021 Sandro Santilli * Copyright (C) 2001-2006 Refractions Research Inc. + * Copyright 2026 Darafei Praliaskouski * **********************************************************************/ - #include #include #include @@ -533,13 +533,11 @@ ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where) POINT4D pbuf; size_t ptsize = ptarray_point_size(pa); - LWDEBUGF(3, "pa %p p %p size %zu where %u", - pa, p, pdims, where); + LWDEBUGF(3, "pa %p p %p size %lu where %u", pa, p, (unsigned long)pdims, where); if ( pdims < 2 || pdims > 4 ) { - lwerror("ptarray_addPoint: point dimension out of range (%zu)", - pdims); + lwerror("ptarray_addPoint: point dimension out of range (%lu)", (unsigned long)pdims); return NULL; } commit ab211fe67c97b239ff2943e4ead65a71fa0fb012 Author: Darafei Praliaskouski Date: Wed Jun 17 09:57:39 2026 +0400 libpgcommon: mark truncated PostgreSQL messages Make libpgcommon append a truncation marker when fixed-size PostgreSQL message formatting overflows, so error, warning, notice, and debug messages no longer lose their tail silently. Closes https://github.com/postgis/postgis/pull/932 Closes #3179 diff --git a/NEWS b/NEWS index a314e2be7..5ca8c2631 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - GH-888, [sfcgal] Avoid stale detoasted geometry access in CG_Visibility empty-input handling for SFCGAL < 2.2 (Darafei Praliaskouski) + - #3179, Mark truncated libpgcommon PostgreSQL messages instead of silently + dropping the tail (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/libpgcommon/lwgeom_pg.c b/libpgcommon/lwgeom_pg.c index fbbe5b73b..d2e2fd061 100644 --- a/libpgcommon/lwgeom_pg.c +++ b/libpgcommon/lwgeom_pg.c @@ -43,8 +43,10 @@ #include #include #include +#include #define PGC_ERRMSG_MAXLEN 2048 //256 +#define PGC_ERRMSG_TRUNCATED " [truncated]" /****************************************************************************************/ /* Global to hold all the run-time constants */ @@ -350,6 +352,28 @@ pg_free(void *ptr) pfree(ptr); } +static void +pg_format_message(char *errmsg, size_t errmsg_size, const char *fmt, va_list ap) +{ + int written = vsnprintf(errmsg, errmsg_size, fmt, ap); + + if (written < 0) + { + strlcpy(errmsg, "[error formatting PostGIS message]", errmsg_size); + return; + } + + if ((size_t)written >= errmsg_size) + { + const size_t suffix_size = strlen(PGC_ERRMSG_TRUNCATED); + + if (errmsg_size > suffix_size) + memcpy(errmsg + errmsg_size - suffix_size - 1, + PGC_ERRMSG_TRUNCATED, + suffix_size + 1); + } +} + static void pg_error(const char *fmt, va_list ap) __attribute__ (( format(printf, 1, 0) )); static void @@ -357,9 +381,7 @@ pg_error(const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); ereport(ERROR, (errmsg_internal("%s", errmsg))); } @@ -370,9 +392,7 @@ pg_warning(const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); ereport(WARNING, (errmsg_internal("%s", errmsg))); } @@ -383,9 +403,7 @@ pg_notice(const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); ereport(NOTICE, (errmsg_internal("%s", errmsg))); } @@ -395,8 +413,7 @@ static void pg_debug(int level, const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); int pglevel[6] = {NOTICE, DEBUG1, DEBUG2, DEBUG3, DEBUG4, DEBUG5}; if ( level >= 0 && level <= 5 ) commit 0edc31efc4d80c30801755b91c82297281a35e21 Author: Darafei Praliaskouski Date: Tue Jun 16 23:37:32 2026 +0400 sfcgal: fix regression gating and roof checks Gate polygon-repair regression tests on the CGAL version that provides the exercised behavior, keep SFCGAL 2.3-only regression selection together, and add generic roof-generation checks against the specialized wrappers. Closes https://github.com/postgis/postgis/pull/900 diff --git a/sfcgal/regress/roofgeneration.sql b/sfcgal/regress/roofgeneration.sql index 106f5105e..50b11ab16 100644 --- a/sfcgal/regress/roofgeneration.sql +++ b/sfcgal/regress/roofgeneration.sql @@ -13,4 +13,10 @@ SELECT 'generic_hipped', ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0 SELECT 'generic_flat', ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'FLAT', 2.0, 30.0, 0)); SELECT 'generic_gable_3d', ST_CoordDim(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'GABLE', 2.0, 30.0, 0)); SELECT 'generic_skillion_3d', ST_CoordDim(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'SKILLION', 2.0, 30.0, 0)); +SELECT 'generic_gable_matches_specialized', + ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'GABLE', 5.0, 15.0, 0)) = + ST_AsText(CG_GenerateGableRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 5.0, 15.0)); +SELECT 'generic_skillion_matches_specialized', + ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'SKILLION', 5.0, 15.0, 0)) = + ST_AsText(CG_GenerateSkillionRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 5.0, 15.0, 0)); SELECT 'invalid_type', CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'DOME', 2.0, 30.0, 0); diff --git a/sfcgal/regress/roofgeneration_expected b/sfcgal/regress/roofgeneration_expected index d67b1e24d..d90fef96f 100644 --- a/sfcgal/regress/roofgeneration_expected +++ b/sfcgal/regress/roofgeneration_expected @@ -8,4 +8,6 @@ generic_hipped|POLYHEDRALSURFACE Z (((0 4 0,4 4 0,4 0 0,0 0 0,0 4 0)),((0 4 0,0 generic_flat|POLYHEDRALSURFACE Z (((0 0 0,0 4 0,4 4 0,4 0 0,0 0 0)),((0 0 2,4 0 2,4 4 2,0 4 2,0 0 2)),((0 0 0,0 0 2,0 4 2,0 4 0,0 0 0)),((0 4 0,0 4 2,4 4 2,4 4 0,0 4 0)),((4 4 0,4 4 2,4 0 2,4 0 0,4 4 0)),((4 0 0,4 0 2,0 0 2,0 0 0,4 0 0))) generic_gable_3d|3 generic_skillion_3d|3 +generic_gable_matches_specialized|t +generic_skillion_matches_specialized|t ERROR: CG_GenerateRoof: unknown roof type 'DOME', expected FLAT, HIPPED, GABLE or SKILLION diff --git a/sfcgal/regress/tests.mk.in b/sfcgal/regress/tests.mk.in index 89b2e4627..c1c39d069 100644 --- a/sfcgal/regress/tests.mk.in +++ b/sfcgal/regress/tests.mk.in @@ -49,13 +49,15 @@ ifeq ($(shell expr "$(POSTGIS_SFCGAL_VERSION)" ">=" 20300),1) TESTS += \ $(top_srcdir)/sfcgal/regress/alphashape_components.sql \ $(top_srcdir)/sfcgal/regress/roofgeneration.sql \ - $(top_srcdir)/sfcgal/regress/polygonrepair.sql \ $(top_srcdir)/sfcgal/regress/approximatemedialaxis_projected.sql \ $(top_srcdir)/sfcgal/regress/nurbs.sql - ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 601),1) - TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union.sql - else - TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union_pre61.sql + ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 600),1) + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair.sql + ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 601),1) + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union.sql + else + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union_pre61.sql + endif endif else TESTS += \ commit 5673ac9fdedc6cd309a8b3b6fca0f1a0ad5cc737 Author: Darafei Praliaskouski Date: Tue Jun 16 17:15:54 2026 +0400 Fix SFCGAL visibility empty input handling Avoid stale detoasted geometry access in CG_Visibility empty-input compatibility handling for builds against SFCGAL before 2.2, while preserving the empty polygon result for empty inputs. Closes https://github.com/postgis/postgis/pull/888 diff --git a/NEWS b/NEWS index 30ae0eb1a..a314e2be7 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,9 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - GH-888, [sfcgal] Avoid stale detoasted geometry access in + CG_Visibility empty-input handling for SFCGAL < 2.2 + (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/sfcgal/lwgeom_sfcgal.c b/sfcgal/lwgeom_sfcgal.c index 000ae3211..e33c92fa3 100644 --- a/sfcgal/lwgeom_sfcgal.c +++ b/sfcgal/lwgeom_sfcgal.c @@ -19,6 +19,7 @@ ********************************************************************** * * Copyright 2012-2020 Oslandia + * Copyright 2026 Darafei Praliaskouski * **********************************************************************/ @@ -1235,22 +1236,30 @@ sfcgal_visibility_point(PG_FUNCTION_ARGS) input0 = PG_GETARG_GSERIALIZED_P(0); srid = gserialized_get_srid(input0); input1 = PG_GETARG_GSERIALIZED_P(1); - polygon = POSTGIS2SFCGALGeometry(input0); - PG_FREE_IF_COPY(input0, 0); - point = POSTGIS2SFCGALGeometry(input1); - PG_FREE_IF_COPY(input1, 1); #if POSTGIS_SFCGAL_VERSION < 20200 + /* + * SFCGAL < 2.2 needs PostGIS to preserve the empty-input result. + * Check this before converting and freeing detoasted inputs, because + * gserialized_is_empty() must not inspect a freed copy. + */ if (gserialized_is_empty(input0) || gserialized_is_empty(input1)) { result = sfcgal_polygon_create(); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); + PG_FREE_IF_COPY(input0, 0); + PG_FREE_IF_COPY(input1, 1); PG_RETURN_POINTER(output); } #endif + polygon = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + point = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + result = sfcgal_geometry_visibility_point(polygon, point); sfcgal_geometry_delete(polygon); sfcgal_geometry_delete(point); @@ -1285,24 +1294,33 @@ sfcgal_visibility_segment(PG_FUNCTION_ARGS) srid = gserialized_get_srid(input0); input1 = PG_GETARG_GSERIALIZED_P(1); input2 = PG_GETARG_GSERIALIZED_P(2); - polygon = POSTGIS2SFCGALGeometry(input0); - PG_FREE_IF_COPY(input0, 0); - pointA = POSTGIS2SFCGALGeometry(input1); - PG_FREE_IF_COPY(input1, 1); - pointB = POSTGIS2SFCGALGeometry(input2); - PG_FREE_IF_COPY(input2, 2); #if POSTGIS_SFCGAL_VERSION < 20200 + /* + * SFCGAL < 2.2 needs PostGIS to preserve the empty-input result. + * Check this before converting and freeing detoasted inputs, because + * gserialized_is_empty() must not inspect a freed copy. + */ if (gserialized_is_empty(input0) || gserialized_is_empty(input1) || gserialized_is_empty(input2)) { result = sfcgal_polygon_create(); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); + PG_FREE_IF_COPY(input0, 0); + PG_FREE_IF_COPY(input1, 1); + PG_FREE_IF_COPY(input2, 2); PG_RETURN_POINTER(output); } #endif + polygon = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + pointA = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + pointB = POSTGIS2SFCGALGeometry(input2); + PG_FREE_IF_COPY(input2, 2); + result = sfcgal_geometry_visibility_segment(polygon, pointA, pointB); sfcgal_geometry_delete(polygon); sfcgal_geometry_delete(pointA); commit f1330c340b2d84e93738ea042ee582b003e4d028 Author: Darafei Praliaskouski Date: Thu Jun 18 11:23:12 2026 +0400 Stabilize NURBS approximation regression output Apply explicit two-decimal ST_AsText output for the high-tolerance NURBS approximation regression so SFCGAL/CGAL precision drift does not fail otherwise unrelated CI runs. Closes https://github.com/postgis/postgis/pull/959 diff --git a/sfcgal/regress/nurbs.sql b/sfcgal/regress/nurbs.sql index a71fc9f54..bed1a0361 100644 --- a/sfcgal/regress/nurbs.sql +++ b/sfcgal/regress/nurbs.sql @@ -96,7 +96,7 @@ SELECT 'approximate_high_tol', ST_AsText(CG_NurbsCurveApproximate( 'LINESTRING(0 0, 1 2.1, 2 1.9, 3 3.2, 4 2.8, 5 1)'::geometry, 2, 0.5 -)); +), 2); -- Test approximation with 3D points SELECT 'approximate_3d', ST_AsText(CG_NurbsCurveApproximate( diff --git a/sfcgal/regress/nurbs_expected b/sfcgal/regress/nurbs_expected index a7e2856fb..9ccee264f 100644 --- a/sfcgal/regress/nurbs_expected +++ b/sfcgal/regress/nurbs_expected @@ -10,6 +10,6 @@ ERROR: Data points must be a LINESTRING ERROR: Need at least 4 data points for degree 3 interpolation approximate_default|NURBSCURVE(DEGREE 3,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(0.18 -0.15),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(1.49 4.36),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(3.33 1.33),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(4.34 0.83),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 0),WEIGHT 1)),KNOTS (KNOT(0,4),KNOT(0.46,1),KNOT(0.64,1),KNOT(1,4))) approximate_max_ctrl|NURBSCURVE(DEGREE 3,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(3.3 6.18),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(6.48 40.13),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(8.84 73.32),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(10 100),WEIGHT 1)),KNOTS (KNOT(0,4),KNOT(0.21,1),KNOT(1,4))) -approximate_high_tol|NURBSCURVE(DEGREE 2,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(-0.048424154393691 2.640915492953116),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.237552942255657 1.646186724700419),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.786598026195684 3.476253776863865),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(4.840573182610214 2.429625830321494),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 1),WEIGHT 1)),KNOTS (KNOT(0,3),KNOT(0.349154606588781,1),KNOT(0.512902297757245,1),KNOT(0.680173066921787,1),KNOT(1,3))) +approximate_high_tol|NURBSCURVE(DEGREE 2,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(-0.05 2.64),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.24 1.65),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.79 3.48),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(4.84 2.43),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 1),WEIGHT 1)),KNOTS (KNOT(0,3),KNOT(0.35,1),KNOT(0.51,1),KNOT(0.68,1),KNOT(1,3))) approximate_3d|NURBSCURVE Z (DEGREE 3,CONTROLPOINTS Z (NURBSPOINT(WEIGHTEDPOINT Z (0 0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (0.18 -0.15 -1.29),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (1.49 4.36 3.35),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (3.33 1.33 0.38),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (4.34 0.83 -0.44),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (5 0 0),WEIGHT 1)),KNOTS (KNOT(0,4),KNOT(0.46,1),KNOT(0.64,1),KNOT(1,4))) ERROR: Need at least 4 data points for degree 3 approximation ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ liblwgeom/cunit/cu_in_wkb.c | 4 ++++ liblwgeom/lwin_wkb.c | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 06:20:08 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 13:20:08 -0000 Subject: [PostGIS] #3179: Make libpgcommon notice handlers warn on truncation In-Reply-To: <046.62f03f936d70354d3aa40c21aa112941@osgeo.org> References: <046.62f03f936d70354d3aa40c21aa112941@osgeo.org> Message-ID: <061.893e3e937d382fde781d7e6111b24089@osgeo.org> #3179: Make libpgcommon notice handlers warn on truncation --------------------------+----------------------------- Reporter: strk | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"ab211fe67c97b239ff2943e4ead65a71fa0fb012/git" ab211fe/git]: {{{#!CommitTicketReference repository="git" revision="ab211fe67c97b239ff2943e4ead65a71fa0fb012" libpgcommon: mark truncated PostgreSQL messages Make libpgcommon append a truncation marker when fixed-size PostgreSQL message formatting overflows, so error, warning, notice, and debug messages no longer lose their tail silently. Closes https://github.com/postgis/postgis/pull/932 Closes #3179 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 18 06:20:09 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 13:20:09 -0000 Subject: [PostGIS] #6003: unknown conversion warning in lwgeom under mingw64/msys2 gcc 13.2 In-Reply-To: <046.af1e8163b07c9a3c6d2c1916c460f2e6@osgeo.org> References: <046.af1e8163b07c9a3c6d2c1916c460f2e6@osgeo.org> Message-ID: <061.7e78bbe7470a1efb63d3b8e4380b1b2c@osgeo.org> #6003: unknown conversion warning in lwgeom under mingw64/msys2 gcc 13.2 ----------------------+--------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: low | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.5.x Resolution: fixed | Keywords: windows ----------------------+--------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"8c5ead8c7e0c3b152929189b8f5e4f00f23525af/git" 8c5ead8/git]: {{{#!CommitTicketReference repository="git" revision="8c5ead8c7e0c3b152929189b8f5e4f00f23525af" Avoid size_t formats in lwgeom logs Replace size_t formatting in liblwgeom logging and error messages with unsigned-long casts so MinGW builds do not warn on unsupported %zu format specifiers. Closes https://github.com/postgis/postgis/pull/903 Closes #6003 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 18 06:20:09 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 13:20:09 -0000 Subject: [PostGIS] #6080: Error casting int -> uint8_t In-Reply-To: <050.ca96fba3af513625ac4b9117964eefa1@osgeo.org> References: <050.ca96fba3af513625ac4b9117964eefa1@osgeo.org> Message-ID: <065.8b328fab4f1a3b94d3a991bbba139909@osgeo.org> #6080: Error casting int -> uint8_t -----------------------+--------------------------- Reporter: ezimanyi | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.6.5 Component: postgis | Version: 3.6.x Resolution: fixed | Keywords: -----------------------+--------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"07e64e5f0f1361abec66940c45b951d835c5bd1f/git" 07e64e5/git]: {{{#!CommitTicketReference repository="git" revision="07e64e5f0f1361abec66940c45b951d835c5bd1f" Fix signed hex WKB lookup Cast hex input bytes to uint8_t before indexing the liblwgeom hex lookup table, and cover malformed high-bit WKB input in CUnit. Closes https://github.com/postgis/postgis/pull/902 Closes #6080 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 06:32:40 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 06:32:40 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-600-g184d3a567 Message-ID: <20260618133240.D265F1C2581@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 184d3a567885288608c1049c4cbe32f7058176dc (commit) via c3004485c01808aaedefbf75d6b8de9090739811 (commit) via b90c3dbb175c92ea3c113c38cacc6a3617a51695 (commit) via ea9c759b0b8d6c9b27fa5e12c5bb0be8b3405c66 (commit) via 9b9950de1262a24c41e9e4d647627b1816a6ac52 (commit) via 014d02c42befac740f904b1cceca52391b671097 (commit) via cff529aa81f12c0dc12b2b273a0e836e38c3f122 (commit) via 8c034d0faef7819f920cb4d921068217f679c1cd (commit) via 9cc6dac3d6d9c119667a438118cb4b5b6bb21c3b (commit) via d078fd9e158e18640e901eed329dca1f0cbc0133 (commit) via 67d6df38c343a8be4605061e330587d9aafaffaf (commit) from 07e64e5f0f1361abec66940c45b951d835c5bd1f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 184d3a567885288608c1049c4cbe32f7058176dc Merge: 07e64e5f0 c3004485c Author: Darafei Praliaskouski Date: Thu Jun 18 17:30:25 2026 +0400 Merge Weblate manual repository state Record Weblate's exported master as merged after the PR landing history rewrite, so Weblate can fast-forward to the resolved upstream state instead of replaying duplicate PR commits and conflicting in NEWS. commit c3004485c01808aaedefbf75d6b8de9090739811 Merge: b90c3dbb1 d078fd9e1 Author: Darafei Praliaskouski Date: Thu Jun 18 16:55:30 2026 +0400 Merge PR #903: Avoid size_t log formats for MinGW Replace size_t formatting in liblwgeom logging and error messages with unsigned-long casts so MinGW builds do not warn on unsupported %zu format specifiers. diff --cc NEWS index 5ca8c2631,1aa7f0626..6f57e1a8c --- a/NEWS +++ b/NEWS @@@ -55,11 -54,8 +55,13 @@@ To take advantage of all postgis_sfcga finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - GH-888, [sfcgal] Avoid stale detoasted geometry access in + CG_Visibility empty-input handling for SFCGAL < 2.2 + (Darafei Praliaskouski) + - #3179, Mark truncated libpgcommon PostgreSQL messages instead of silently + dropping the tail (Darafei Praliaskouski) + - #6003, Avoid size_t formats in liblwgeom logging/error wrappers for + MinGW builds (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in commit b90c3dbb175c92ea3c113c38cacc6a3617a51695 Merge: ea9c759b0 67d6df38c Author: Darafei Praliaskouski Date: Thu Jun 18 16:46:19 2026 +0400 Merge PR #932: Mark truncated PostgreSQL messages Make libpgcommon append a truncation marker when fixed-size PostgreSQL message formatting overflows, so error, warning, notice, and debug messages no longer lose their tail silently. diff --cc NEWS index a314e2be7,2910943b4..5ca8c2631 --- a/NEWS +++ b/NEWS @@@ -55,9 -54,8 +55,11 @@@ To take advantage of all postgis_sfcga finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - GH-888, [sfcgal] Avoid stale detoasted geometry access in + CG_Visibility empty-input handling for SFCGAL < 2.2 + (Darafei Praliaskouski) + - #3179, Mark truncated libpgcommon PostgreSQL messages instead of silently + dropping the tail (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in commit ea9c759b0b8d6c9b27fa5e12c5bb0be8b3405c66 Merge: 9b9950de1 8c034d0fa Author: Darafei Praliaskouski Date: Thu Jun 18 16:37:46 2026 +0400 Merge PR #900: Fix SFCGAL regression gating and roof checks Gate polygon-repair regression tests on the CGAL version that provides the exercised behavior, keep SFCGAL 2.3-only regression selection together, and add generic roof-generation checks against the specialized wrappers. commit 9b9950de1262a24c41e9e4d647627b1816a6ac52 Merge: 014d02c42 9cc6dac3d Author: Darafei Praliaskouski Date: Thu Jun 18 16:27:57 2026 +0400 Merge PR #888: Fix SFCGAL visibility empty input handling Avoid stale detoasted geometry access in CG_Visibility empty-input compatibility handling for builds against SFCGAL before 2.2, while preserving the empty polygon result for empty inputs. commit 014d02c42befac740f904b1cceca52391b671097 Merge: 857652e24 cff529aa8 Author: Darafei Praliaskouski Date: Thu Jun 18 16:18:43 2026 +0400 Merge PR #959: Stabilize NURBS approximation regression output Apply explicit two-decimal ST_AsText output for the high-tolerance NURBS approximation regression so SFCGAL/CGAL precision drift does not fail otherwise unrelated CI runs. Validation: GitHub CI green on cff529aa81f12c0dc12b2b273a0e836e38c3f122; local git diff --check upstream/master..HEAD passed; local make -C sfcgal/regress check RUNTESTFLAGS='--verbose --extension' TESTS="/home/kom/proj/osgeo/postgis/sfcgal/regress/nurbs.sql" passed, including automatic upgrade rerun. commit cff529aa81f12c0dc12b2b273a0e836e38c3f122 Author: Darafei Praliaskouski Date: Thu Jun 18 11:23:12 2026 +0400 Stabilize NURBS approximation regression output diff --git a/sfcgal/regress/nurbs.sql b/sfcgal/regress/nurbs.sql index a71fc9f54..bed1a0361 100644 --- a/sfcgal/regress/nurbs.sql +++ b/sfcgal/regress/nurbs.sql @@ -96,7 +96,7 @@ SELECT 'approximate_high_tol', ST_AsText(CG_NurbsCurveApproximate( 'LINESTRING(0 0, 1 2.1, 2 1.9, 3 3.2, 4 2.8, 5 1)'::geometry, 2, 0.5 -)); +), 2); -- Test approximation with 3D points SELECT 'approximate_3d', ST_AsText(CG_NurbsCurveApproximate( diff --git a/sfcgal/regress/nurbs_expected b/sfcgal/regress/nurbs_expected index a7e2856fb..9ccee264f 100644 --- a/sfcgal/regress/nurbs_expected +++ b/sfcgal/regress/nurbs_expected @@ -10,6 +10,6 @@ ERROR: Data points must be a LINESTRING ERROR: Need at least 4 data points for degree 3 interpolation approximate_default|NURBSCURVE(DEGREE 3,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(0.18 -0.15),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(1.49 4.36),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(3.33 1.33),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(4.34 0.83),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 0),WEIGHT 1)),KNOTS (KNOT(0,4),KNOT(0.46,1),KNOT(0.64,1),KNOT(1,4))) approximate_max_ctrl|NURBSCURVE(DEGREE 3,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(3.3 6.18),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(6.48 40.13),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(8.84 73.32),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(10 100),WEIGHT 1)),KNOTS (KNOT(0,4),KNOT(0.21,1),KNOT(1,4))) -approximate_high_tol|NURBSCURVE(DEGREE 2,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(-0.048424154393691 2.640915492953116),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.237552942255657 1.646186724700419),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.786598026195684 3.476253776863865),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(4.840573182610214 2.429625830321494),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 1),WEIGHT 1)),KNOTS (KNOT(0,3),KNOT(0.349154606588781,1),KNOT(0.512902297757245,1),KNOT(0.680173066921787,1),KNOT(1,3))) +approximate_high_tol|NURBSCURVE(DEGREE 2,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(-0.05 2.64),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.24 1.65),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2.79 3.48),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(4.84 2.43),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 1),WEIGHT 1)),KNOTS (KNOT(0,3),KNOT(0.35,1),KNOT(0.51,1),KNOT(0.68,1),KNOT(1,3))) approximate_3d|NURBSCURVE Z (DEGREE 3,CONTROLPOINTS Z (NURBSPOINT(WEIGHTEDPOINT Z (0 0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (0.18 -0.15 -1.29),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (1.49 4.36 3.35),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (3.33 1.33 0.38),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (4.34 0.83 -0.44),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT Z (5 0 0),WEIGHT 1)),KNOTS (KNOT(0,4),KNOT(0.46,1),KNOT(0.64,1),KNOT(1,4))) ERROR: Need at least 4 data points for degree 3 approximation commit 8c034d0faef7819f920cb4d921068217f679c1cd Author: Darafei Praliaskouski Date: Tue Jun 16 23:37:32 2026 +0400 sfcgal: fix regression gating and roof checks diff --git a/sfcgal/regress/roofgeneration.sql b/sfcgal/regress/roofgeneration.sql index 106f5105e..50b11ab16 100644 --- a/sfcgal/regress/roofgeneration.sql +++ b/sfcgal/regress/roofgeneration.sql @@ -13,4 +13,10 @@ SELECT 'generic_hipped', ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0 SELECT 'generic_flat', ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'FLAT', 2.0, 30.0, 0)); SELECT 'generic_gable_3d', ST_CoordDim(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'GABLE', 2.0, 30.0, 0)); SELECT 'generic_skillion_3d', ST_CoordDim(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'SKILLION', 2.0, 30.0, 0)); +SELECT 'generic_gable_matches_specialized', + ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'GABLE', 5.0, 15.0, 0)) = + ST_AsText(CG_GenerateGableRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 5.0, 15.0)); +SELECT 'generic_skillion_matches_specialized', + ST_AsText(CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'SKILLION', 5.0, 15.0, 0)) = + ST_AsText(CG_GenerateSkillionRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 5.0, 15.0, 0)); SELECT 'invalid_type', CG_GenerateRoof('POLYGON((0 0,4 0,4 4,0 4,0 0))', 'DOME', 2.0, 30.0, 0); diff --git a/sfcgal/regress/roofgeneration_expected b/sfcgal/regress/roofgeneration_expected index d67b1e24d..d90fef96f 100644 --- a/sfcgal/regress/roofgeneration_expected +++ b/sfcgal/regress/roofgeneration_expected @@ -8,4 +8,6 @@ generic_hipped|POLYHEDRALSURFACE Z (((0 4 0,4 4 0,4 0 0,0 0 0,0 4 0)),((0 4 0,0 generic_flat|POLYHEDRALSURFACE Z (((0 0 0,0 4 0,4 4 0,4 0 0,0 0 0)),((0 0 2,4 0 2,4 4 2,0 4 2,0 0 2)),((0 0 0,0 0 2,0 4 2,0 4 0,0 0 0)),((0 4 0,0 4 2,4 4 2,4 4 0,0 4 0)),((4 4 0,4 4 2,4 0 2,4 0 0,4 4 0)),((4 0 0,4 0 2,0 0 2,0 0 0,4 0 0))) generic_gable_3d|3 generic_skillion_3d|3 +generic_gable_matches_specialized|t +generic_skillion_matches_specialized|t ERROR: CG_GenerateRoof: unknown roof type 'DOME', expected FLAT, HIPPED, GABLE or SKILLION diff --git a/sfcgal/regress/tests.mk.in b/sfcgal/regress/tests.mk.in index 89b2e4627..c1c39d069 100644 --- a/sfcgal/regress/tests.mk.in +++ b/sfcgal/regress/tests.mk.in @@ -49,13 +49,15 @@ ifeq ($(shell expr "$(POSTGIS_SFCGAL_VERSION)" ">=" 20300),1) TESTS += \ $(top_srcdir)/sfcgal/regress/alphashape_components.sql \ $(top_srcdir)/sfcgal/regress/roofgeneration.sql \ - $(top_srcdir)/sfcgal/regress/polygonrepair.sql \ $(top_srcdir)/sfcgal/regress/approximatemedialaxis_projected.sql \ $(top_srcdir)/sfcgal/regress/nurbs.sql - ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 601),1) - TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union.sql - else - TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union_pre61.sql + ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 600),1) + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair.sql + ifeq ($(shell expr "$(POSTGIS_CGAL_VERSION)" ">=" 601),1) + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union.sql + else + TESTS += $(top_srcdir)/sfcgal/regress/polygonrepair_union_pre61.sql + endif endif else TESTS += \ commit 9cc6dac3d6d9c119667a438118cb4b5b6bb21c3b Author: Darafei Praliaskouski Date: Tue Jun 16 17:15:54 2026 +0400 Fix SFCGAL visibility empty input handling diff --git a/NEWS b/NEWS index 4cd72746a..cf06261d4 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,9 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - GH-888, [sfcgal] Avoid stale detoasted geometry access in + CG_Visibility empty-input handling for SFCGAL < 2.2 + (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/sfcgal/lwgeom_sfcgal.c b/sfcgal/lwgeom_sfcgal.c index 5ee90f878..0289ccb21 100644 --- a/sfcgal/lwgeom_sfcgal.c +++ b/sfcgal/lwgeom_sfcgal.c @@ -19,6 +19,7 @@ ********************************************************************** * * Copyright 2012-2020 Oslandia + * Copyright 2026 Darafei Praliaskouski * **********************************************************************/ @@ -1232,22 +1233,30 @@ sfcgal_visibility_point(PG_FUNCTION_ARGS) input0 = PG_GETARG_GSERIALIZED_P(0); srid = gserialized_get_srid(input0); input1 = PG_GETARG_GSERIALIZED_P(1); - polygon = POSTGIS2SFCGALGeometry(input0); - PG_FREE_IF_COPY(input0, 0); - point = POSTGIS2SFCGALGeometry(input1); - PG_FREE_IF_COPY(input1, 1); #if POSTGIS_SFCGAL_VERSION < 20200 + /* + * SFCGAL < 2.2 needs PostGIS to preserve the empty-input result. + * Check this before converting and freeing detoasted inputs, because + * gserialized_is_empty() must not inspect a freed copy. + */ if (gserialized_is_empty(input0) || gserialized_is_empty(input1)) { result = sfcgal_polygon_create(); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); + PG_FREE_IF_COPY(input0, 0); + PG_FREE_IF_COPY(input1, 1); PG_RETURN_POINTER(output); } #endif + polygon = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + point = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + result = sfcgal_geometry_visibility_point(polygon, point); sfcgal_geometry_delete(polygon); sfcgal_geometry_delete(point); @@ -1282,24 +1291,33 @@ sfcgal_visibility_segment(PG_FUNCTION_ARGS) srid = gserialized_get_srid(input0); input1 = PG_GETARG_GSERIALIZED_P(1); input2 = PG_GETARG_GSERIALIZED_P(2); - polygon = POSTGIS2SFCGALGeometry(input0); - PG_FREE_IF_COPY(input0, 0); - pointA = POSTGIS2SFCGALGeometry(input1); - PG_FREE_IF_COPY(input1, 1); - pointB = POSTGIS2SFCGALGeometry(input2); - PG_FREE_IF_COPY(input2, 2); #if POSTGIS_SFCGAL_VERSION < 20200 + /* + * SFCGAL < 2.2 needs PostGIS to preserve the empty-input result. + * Check this before converting and freeing detoasted inputs, because + * gserialized_is_empty() must not inspect a freed copy. + */ if (gserialized_is_empty(input0) || gserialized_is_empty(input1) || gserialized_is_empty(input2)) { result = sfcgal_polygon_create(); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); + PG_FREE_IF_COPY(input0, 0); + PG_FREE_IF_COPY(input1, 1); + PG_FREE_IF_COPY(input2, 2); PG_RETURN_POINTER(output); } #endif + polygon = POSTGIS2SFCGALGeometry(input0); + PG_FREE_IF_COPY(input0, 0); + pointA = POSTGIS2SFCGALGeometry(input1); + PG_FREE_IF_COPY(input1, 1); + pointB = POSTGIS2SFCGALGeometry(input2); + PG_FREE_IF_COPY(input2, 2); + result = sfcgal_geometry_visibility_segment(polygon, pointA, pointB); sfcgal_geometry_delete(polygon); sfcgal_geometry_delete(pointA); commit d078fd9e158e18640e901eed329dca1f0cbc0133 Author: Darafei Praliaskouski Date: Wed Jun 17 01:19:03 2026 +0400 Avoid size_t formats in lwgeom logs diff --git a/NEWS b/NEWS index 4cd72746a..1aa7f0626 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - #6003, Avoid size_t formats in liblwgeom logging/error wrappers for + MinGW builds (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/liblwgeom/lwgeom_api.c b/liblwgeom/lwgeom_api.c index 99e51b0ca..bda927801 100644 --- a/liblwgeom/lwgeom_api.c +++ b/liblwgeom/lwgeom_api.c @@ -19,12 +19,10 @@ ********************************************************************** * * Copyright 2001-2006 Refractions Research Inc. - * Copyright 2017 Darafei Praliaskouski + * Copyright 2017-2026 Darafei Praliaskouski * **********************************************************************/ - - #include "liblwgeom_internal.h" #include "lwgeom_log.h" @@ -452,8 +450,8 @@ void printPA(POINTARRAY *pa) else mflag = ""; lwnotice(" POINTARRAY%s{", mflag); - lwnotice(" ndims=%i, ptsize=%zu", - FLAGS_NDIMS(pa->flags), ptarray_point_size(pa)); + lwnotice( + " ndims=%i, ptsize=%lu", FLAGS_NDIMS(pa->flags), (unsigned long)ptarray_point_size(pa)); lwnotice(" npoints = %u", pa->npoints); for (t = 0; t < pa->npoints; t++) diff --git a/liblwgeom/ptarray.c b/liblwgeom/ptarray.c index 7631081bc..3baae4da6 100644 --- a/liblwgeom/ptarray.c +++ b/liblwgeom/ptarray.c @@ -20,10 +20,10 @@ * * Copyright (C) 2012-2021 Sandro Santilli * Copyright (C) 2001-2006 Refractions Research Inc. + * Copyright 2026 Darafei Praliaskouski * **********************************************************************/ - #include #include #include @@ -533,13 +533,11 @@ ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where) POINT4D pbuf; size_t ptsize = ptarray_point_size(pa); - LWDEBUGF(3, "pa %p p %p size %zu where %u", - pa, p, pdims, where); + LWDEBUGF(3, "pa %p p %p size %lu where %u", pa, p, (unsigned long)pdims, where); if ( pdims < 2 || pdims > 4 ) { - lwerror("ptarray_addPoint: point dimension out of range (%zu)", - pdims); + lwerror("ptarray_addPoint: point dimension out of range (%lu)", (unsigned long)pdims); return NULL; } commit 67d6df38c343a8be4605061e330587d9aafaffaf Author: Darafei Praliaskouski Date: Wed Jun 17 09:57:39 2026 +0400 libpgcommon: mark truncated PostgreSQL messages diff --git a/NEWS b/NEWS index 4cd72746a..2910943b4 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - #3179, Mark truncated libpgcommon PostgreSQL messages instead of silently + dropping the tail (Darafei Praliaskouski) - Build PostgreSQL extension modules with `-fno-semantic-interposition` when available so LTO can optimize same-DSO calls to exported PostGIS entry points directly instead of routing through the module PLT; in diff --git a/libpgcommon/lwgeom_pg.c b/libpgcommon/lwgeom_pg.c index fbbe5b73b..d2e2fd061 100644 --- a/libpgcommon/lwgeom_pg.c +++ b/libpgcommon/lwgeom_pg.c @@ -43,8 +43,10 @@ #include #include #include +#include #define PGC_ERRMSG_MAXLEN 2048 //256 +#define PGC_ERRMSG_TRUNCATED " [truncated]" /****************************************************************************************/ /* Global to hold all the run-time constants */ @@ -350,6 +352,28 @@ pg_free(void *ptr) pfree(ptr); } +static void +pg_format_message(char *errmsg, size_t errmsg_size, const char *fmt, va_list ap) +{ + int written = vsnprintf(errmsg, errmsg_size, fmt, ap); + + if (written < 0) + { + strlcpy(errmsg, "[error formatting PostGIS message]", errmsg_size); + return; + } + + if ((size_t)written >= errmsg_size) + { + const size_t suffix_size = strlen(PGC_ERRMSG_TRUNCATED); + + if (errmsg_size > suffix_size) + memcpy(errmsg + errmsg_size - suffix_size - 1, + PGC_ERRMSG_TRUNCATED, + suffix_size + 1); + } +} + static void pg_error(const char *fmt, va_list ap) __attribute__ (( format(printf, 1, 0) )); static void @@ -357,9 +381,7 @@ pg_error(const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); ereport(ERROR, (errmsg_internal("%s", errmsg))); } @@ -370,9 +392,7 @@ pg_warning(const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); ereport(WARNING, (errmsg_internal("%s", errmsg))); } @@ -383,9 +403,7 @@ pg_notice(const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); ereport(NOTICE, (errmsg_internal("%s", errmsg))); } @@ -395,8 +413,7 @@ static void pg_debug(int level, const char *fmt, va_list ap) { char errmsg[PGC_ERRMSG_MAXLEN+1]; - vsnprintf (errmsg, PGC_ERRMSG_MAXLEN, fmt, ap); - errmsg[PGC_ERRMSG_MAXLEN]='\0'; + pg_format_message(errmsg, sizeof(errmsg), fmt, ap); int pglevel[6] = {NOTICE, DEBUG1, DEBUG2, DEBUG3, DEBUG4, DEBUG5}; if ( level >= 0 && level <= 5 ) ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 18 07:44:49 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 07:44:49 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-601-g95226e1ad Message-ID: <20260618144449.751FC1C389C@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 95226e1ad45650c30a6fb0da1af67eca18554ea8 (commit) from 184d3a567885288608c1049c4cbe32f7058176dc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 95226e1ad45650c30a6fb0da1af67eca18554ea8 Author: Darafei Praliaskouski Date: Tue Jun 16 23:38:34 2026 +0400 loader: stop marking tiger geocoder for upgrade Keep the loader upgrade helper from setting postgis_tiger_geocoder.extversion to ANY now that postgis_extensions_upgrade() no longer iterates that extension. Closes https://github.com/postgis/postgis/pull/901 diff --git a/NEWS b/NEWS index 6ad9ec024..ef97557c4 100644 --- a/NEWS +++ b/NEWS @@ -74,6 +74,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #5948, [topology] Prevent MakeTopologyPrecise from erasing edges when grid size exceeds their extent (Darafei Praliaskouski) - #5959, Prevent histogram target overflow when analysing massive tables (Darafei Praliaskouski) + - GH-901, Stop loader upgrade helper from marking postgis_tiger_geocoder + for extension upgrade (Darafei Praliaskouski) - #6080, Avoid out-of-bounds hex WKB lookup for high-bit input bytes (Darafei Praliaskouski) - #4828, geometry_columns handles NOT VALID SRID checks without errors (Darafei Praliaskouski) diff --git a/loader/postgis.pl b/loader/postgis.pl index fa2ea8a62..ff8cc8e28 100644 --- a/loader/postgis.pl +++ b/loader/postgis.pl @@ -232,8 +232,7 @@ BEGIN 'postgis', 'postgis_raster', 'postgis_sfcgal', - 'postgis_topology', - 'postgis_tiger_geocoder' + 'postgis_topology' ); PERFORM postgis_extensions_upgrade(); END IF; ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ loader/postgis.pl | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 18 08:18:27 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 08:18:27 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-602-g746769bc9 Message-ID: <20260618151827.CEB751C4339@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 746769bc9603c34262f2a704369a5efda9ac4ebe (commit) from 95226e1ad45650c30a6fb0da1af67eca18554ea8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 746769bc9603c34262f2a704369a5efda9ac4ebe Author: Darafei Praliaskouski Date: Wed Jun 17 08:30:26 2026 +0400 doc: fix Japanese PDF listing arrows Replace non-ASCII arrows in the CG_GenerateSkillionRoof SQL program listing so the Japanese PDF build does not trip over undefined XeTeX/listings control sequences. Closes https://github.com/postgis/postgis/pull/928 Closes #6082 diff --git a/NEWS b/NEWS index ef97557c4..9c40c9f0c 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - #6082, Fix Japanese PDF build by avoiding non-ASCII arrows in SQL + program listings (Darafei Praliaskouski) - GH-888, [sfcgal] Avoid stale detoasted geometry access in CG_Visibility empty-input handling for SFCGAL < 2.2 (Darafei Praliaskouski) diff --git a/doc/reference_sfcgal.xml b/doc/reference_sfcgal.xml index 936367412..85037ed0f 100644 --- a/doc/reference_sfcgal.xml +++ b/doc/reference_sfcgal.xml @@ -2083,14 +2083,14 @@ SELECT CG_ApproximateMedialAxis('POLYGON((0 0,2 0,2 1,0 1,0 0))', true); - -- height 2.0 ? 6 patches + -- height 2.0 -> 6 patches SELECT ST_NumPatches( CG_GenerateSkillionRoof( 'POLYGON((0 0,5 0,5 4,0 4,0 0))', 2.0)); -- 6 --- height 4.0 ? 5 patches (one face filtered) +-- height 4.0 -> 5 patches (one face filtered) SELECT ST_NumPatches( CG_GenerateSkillionRoof( 'POLYGON((0 0,5 0,5 4,0 4,0 0))', ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ doc/reference_sfcgal.xml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 08:18:29 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 15:18:29 -0000 Subject: [PostGIS] #6082: Debbie failing on docbook ja building In-Reply-To: <046.b68f8faa448a912ac9cacf070f6f6403@osgeo.org> References: <046.b68f8faa448a912ac9cacf070f6f6403@osgeo.org> Message-ID: <061.c25981a22b093cf19359738c06d009d9@osgeo.org> #6082: Debbie failing on docbook ja building ----------------------------+--------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: documentation | Version: master Resolution: fixed | Keywords: ----------------------------+--------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"746769bc9603c34262f2a704369a5efda9ac4ebe/git" 746769b/git]: {{{#!CommitTicketReference repository="git" revision="746769bc9603c34262f2a704369a5efda9ac4ebe" doc: fix Japanese PDF listing arrows Replace non-ASCII arrows in the CG_GenerateSkillionRoof SQL program listing so the Japanese PDF build does not trip over undefined XeTeX/listings control sequences. Closes https://github.com/postgis/postgis/pull/928 Closes #6082 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 08:28:17 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 08:28:17 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-603-g3fd87bf0f Message-ID: <20260618152817.EAF1A1C49A2@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 3fd87bf0f0d4b3a2cec5eebb611f263af89010eb (commit) from 746769bc9603c34262f2a704369a5efda9ac4ebe (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 3fd87bf0f0d4b3a2cec5eebb611f263af89010eb Author: Darafei Praliaskouski Date: Wed Jun 17 12:29:03 2026 +0400 Add shp2pgsql unlogged table option Allow shp2pgsql create, drop, prepare, and dump modes to emit CREATE UNLOGGED TABLE for transient staging loads, and expose the option through the GUI and documentation. Closes https://github.com/postgis/postgis/pull/940 Closes #1124 diff --git a/NEWS b/NEWS index 9c40c9f0c..578109e8d 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * New Features * + - #1124, shp2pgsql can create UNLOGGED tables for transient staging loads + (Darafei Praliaskouski) - [topology] FindVertexSegmentPairsBelowDistance function (Sandro Santilli) - ST_CoverageEdges, returns MultiLinestring of distinct shared edges in polygonal coverage (Paul Ramsey) diff --git a/doc/man/shp2pgsql.1 b/doc/man/shp2pgsql.1 index 7b6e8ae18..37ccabcba 100644 --- a/doc/man/shp2pgsql.1 +++ b/doc/man/shp2pgsql.1 @@ -108,6 +108,11 @@ If this option is used the output will be encoded in UTF-8. \fB\-I\fR Create a GiST index on the geometry column. .TP +\fB\-u\fR +Create the target table as UNLOGGED. This can speed up loading transient +staging data, but PostgreSQL does not preserve unlogged table contents after +a crash or unclean shutdown. +.TP \fB\-N\fR <\fIpolicy\fR> Specify NULL geometries handling policy (insert,skip,abort). .TP diff --git a/doc/using_postgis_dataman.xml b/doc/using_postgis_dataman.xml index 0fc321fe7..8f840a5ce 100644 --- a/doc/using_postgis_dataman.xml +++ b/doc/using_postgis_dataman.xml @@ -1995,6 +1995,17 @@ COMMIT; + + + + + Create the target table as UNLOGGED. This can speed up loading + transient staging data, but PostgreSQL does not preserve unlogged table contents + after a crash or unclean shutdown. + + + + diff --git a/loader/shp2pgsql-cli.c b/loader/shp2pgsql-cli.c index c2c4719a9..784ba3a7e 100644 --- a/loader/shp2pgsql-cli.c +++ b/loader/shp2pgsql-cli.c @@ -47,6 +47,7 @@ usage() printf(_( " -k Keep postgresql identifiers case.\n" )); printf(_( " -i Use int4 type for all integer dbf fields.\n" )); printf(_( " -I Create a spatial index on the geocolumn.\n" )); + printf(_( " -u Create the table as UNLOGGED.\n" )); printf(_(" -m Specify a file containing a set of mappings of (long) column\n" " names to 10 character DBF column names. The content of the file is one or\n" " more lines of two names separated by white space and no trailing or\n" @@ -105,7 +106,7 @@ main (int argc, char **argv) set_loader_config_defaults(config); /* Keep the flag list alphabetic so it's easy to see what's left. */ - while ((c = pgis_getopt(argc, argv, "-?acdeg:ikm:nps:t:wDGIN:ST:W:X:Z")) != EOF) + while ((c = pgis_getopt(argc, argv, "-?acdeg:ikm:nps:t:uwDGIN:ST:W:X:Z")) != EOF) { // can not do this inside the switch case if ('-' == c) @@ -178,6 +179,10 @@ main (int argc, char **argv) config->createindex = 1; break; + case 'u': + config->unlogged = 1; + break; + case 'w': config->use_wkt = 1; break; diff --git a/loader/shp2pgsql-core.c b/loader/shp2pgsql-core.c index 9065bdf6f..ac1adc528 100644 --- a/loader/shp2pgsql-core.c +++ b/loader/shp2pgsql-core.c @@ -770,6 +770,7 @@ set_loader_config_defaults(SHPLOADERCONFIG *config) config->quoteidentifiers = 0; config->forceint4 = 0; config->createindex = 0; + config->unlogged = 0; config->analyze = 1; config->readshape = 1; config->force_output = FORCE_OUTPUT_DISABLE; @@ -1350,12 +1351,14 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) */ if (state->config->schema) { - stringbuffer_aprintf(sb, "CREATE TABLE \"%s\".\"%s\" (gid serial", + stringbuffer_aprintf(sb, "CREATE %sTABLE \"%s\".\"%s\" (gid serial", + state->config->unlogged ? "UNLOGGED " : "", state->config->schema, state->config->table); } else { - stringbuffer_aprintf(sb, "CREATE TABLE \"%s\" (gid serial", state->config->table); + stringbuffer_aprintf(sb, "CREATE %sTABLE \"%s\" (gid serial", + state->config->unlogged ? "UNLOGGED " : "", state->config->table); } /* Generate the field types based upon the shapefile information */ diff --git a/loader/shp2pgsql-core.h b/loader/shp2pgsql-core.h index 748d4773a..fd078e21b 100644 --- a/loader/shp2pgsql-core.h +++ b/loader/shp2pgsql-core.h @@ -114,6 +114,9 @@ typedef struct shp_loader_config /* 0 = no index, 1 = create index after load */ int createindex; + /* 0 = logged table, 1 = create as UNLOGGED table */ + int unlogged; + /* 0 = don't analyze tables , 1 = analyze tables */ int analyze; diff --git a/loader/shp2pgsql-gui.c b/loader/shp2pgsql-gui.c index bfc301f50..7f8dbbc87 100644 --- a/loader/shp2pgsql-gui.c +++ b/loader/shp2pgsql-gui.c @@ -113,6 +113,7 @@ static GtkWidget *checkbutton_loader_options_forceint = NULL; static GtkWidget *checkbutton_loader_options_autoindex = NULL; static GtkWidget *checkbutton_loader_options_dbfonly = NULL; static GtkWidget *checkbutton_loader_options_dumpformat = NULL; +static GtkWidget *checkbutton_loader_options_unlogged = NULL; static GtkWidget *checkbutton_loader_options_geography = NULL; static GtkWidget *checkbutton_loader_options_simplegeoms = NULL; @@ -540,6 +541,7 @@ update_loader_config_globals_from_options_ui(SHPLOADERCONFIG *config) gboolean createindex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_autoindex)); gboolean dbfonly = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_dbfonly)); gboolean dumpformat = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_dumpformat)); + gboolean unlogged = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_unlogged)); gboolean geography = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_geography)); gboolean simplegeoms = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_simplegeoms)); @@ -606,6 +608,12 @@ update_loader_config_globals_from_options_ui(SHPLOADERCONFIG *config) else config->dump_format = 0; + /* Create an unlogged table */ + if (unlogged) + config->unlogged = 1; + else + config->unlogged = 0; + /* Simple geometries only */ if (simplegeoms) config->simple_geometries = 1; @@ -625,6 +633,7 @@ update_options_ui_from_loader_config_globals(void) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_autoindex), global_loader_config->createindex ? TRUE : FALSE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_dbfonly), global_loader_config->readshape ? FALSE : TRUE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_dumpformat), global_loader_config->dump_format ? TRUE : FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_unlogged), global_loader_config->unlogged ? TRUE : FALSE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_geography), global_loader_config->geography ? TRUE : FALSE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton_loader_options_simplegeoms), global_loader_config->simple_geometries ? TRUE : FALSE); @@ -2712,7 +2721,7 @@ pgui_create_loader_options_dialog() gtk_window_set_keep_above (GTK_WINDOW(dialog_loader_options), TRUE); gtk_window_set_default_size (GTK_WINDOW(dialog_loader_options), 180, -1); - table_options = gtk_table_new(7, 3, TRUE); + table_options = gtk_table_new(9, 3, TRUE); gtk_container_set_border_width (GTK_CONTAINER (table_options), 12); gtk_table_set_row_spacings(GTK_TABLE(table_options), 5); gtk_table_set_col_spacings(GTK_TABLE(table_options), 10); @@ -2752,16 +2761,22 @@ pgui_create_loader_options_dialog() gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 5, 6 ); gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_dumpformat); - pgui_create_options_dialog_add_label(table_options, _("Load into GEOGRAPHY column"), 0.0, 6); - checkbutton_loader_options_geography = gtk_check_button_new(); + pgui_create_options_dialog_add_label(table_options, _("Create as UNLOGGED table"), 0.0, 6); + checkbutton_loader_options_unlogged = gtk_check_button_new(); align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 6, 7 ); - gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_geography); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_unlogged); - pgui_create_options_dialog_add_label(table_options, _("Generate simple geometries instead of MULTI geometries"), 0.0, 7); - checkbutton_loader_options_simplegeoms = gtk_check_button_new(); + pgui_create_options_dialog_add_label(table_options, _("Load into GEOGRAPHY column"), 0.0, 7); + checkbutton_loader_options_geography = gtk_check_button_new(); align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 7, 8 ); + gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_geography); + + pgui_create_options_dialog_add_label(table_options, _("Generate simple geometries instead of MULTI geometries"), 0.0, 8); + checkbutton_loader_options_simplegeoms = gtk_check_button_new(); + align_options_center = gtk_alignment_new( 0.5, 0.5, 0.0, 1.0 ); + gtk_table_attach_defaults(GTK_TABLE(table_options), align_options_center, 0, 1, 8, 9 ); gtk_container_add (GTK_CONTAINER (align_options_center), checkbutton_loader_options_simplegeoms); /* Catch the response from the dialog */ ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ doc/man/shp2pgsql.1 | 5 +++++ doc/using_postgis_dataman.xml | 11 +++++++++++ loader/shp2pgsql-cli.c | 7 ++++++- loader/shp2pgsql-core.c | 7 +++++-- loader/shp2pgsql-core.h | 3 +++ loader/shp2pgsql-gui.c | 25 ++++++++++++++++++++----- 7 files changed, 52 insertions(+), 8 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 08:28:21 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 15:28:21 -0000 Subject: [PostGIS] #1124: shp2pgsql, shp2pgsql-gui switch to create unlogged table In-Reply-To: <046.0334c2840999f9e846977c850b0a606c@osgeo.org> References: <046.0334c2840999f9e846977c850b0a606c@osgeo.org> Message-ID: <061.feeb14d1edfab596cc613aff83a87a57@osgeo.org> #1124: shp2pgsql, shp2pgsql-gui switch to create unlogged table --------------------------+----------------------------- Reporter: robe | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"3fd87bf0f0d4b3a2cec5eebb611f263af89010eb/git" 3fd87bf0/git]: {{{#!CommitTicketReference repository="git" revision="3fd87bf0f0d4b3a2cec5eebb611f263af89010eb" Add shp2pgsql unlogged table option Allow shp2pgsql create, drop, prepare, and dump modes to emit CREATE UNLOGGED TABLE for transient staging loads, and expose the option through the GUI and documentation. Closes https://github.com/postgis/postgis/pull/940 Closes #1124 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 08:38:56 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 08:38:56 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-604-g5f207dbe5 Message-ID: <20260618153856.40AF31C4B24@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 5f207dbe59a552eba46617f8436d4478aa7045f7 (commit) from 3fd87bf0f0d4b3a2cec5eebb611f263af89010eb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5f207dbe59a552eba46617f8436d4478aa7045f7 Author: Darafei Praliaskouski Date: Thu Jun 18 19:36:32 2026 +0400 Initialize skipped union-find cluster ids Initialize unassigned entries returned by UF_get_collapsed_cluster_ids to UINT32_MAX so callers and tests see deterministic values for elements outside the filtered cluster set. Closes https://github.com/postgis/postgis/pull/974 References #5975 diff --git a/NEWS b/NEWS index 578109e8d..249f6c879 100644 --- a/NEWS +++ b/NEWS @@ -53,6 +53,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Bug Fixes * + - #5975, Initialize skipped union-find cluster ids deterministically + (Darafei Praliaskouski) - GH-885, [topology] Avoid GMP overflow in ring orientation for very large finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, diff --git a/liblwgeom/cunit/cu_unionfind.c b/liblwgeom/cunit/cu_unionfind.c index fb00dc5c1..9deff2adb 100644 --- a/liblwgeom/cunit/cu_unionfind.c +++ b/liblwgeom/cunit/cu_unionfind.c @@ -4,6 +4,7 @@ * http://postgis.net * * Copyright 2015 Daniel Baston + * Copyright 2026 Darafei Praliaskouski * * This is free software; you can redistribute and/or modify it under * the terms of the GNU General Public Licence. See the COPYING file. @@ -148,15 +149,13 @@ static void test_unionfind_collapse_cluster_ids(void) lwfree(collapsed_ids); uint8_t is_in_cluster[] = {0, 1, 1, 1, 0, 1, 0, 0, 0, 0}; - uint32_t expected_collapsed_ids2[] = { 8, 0, 0, 0, 7, 0, 8, 7, 8, 7 }; + uint32_t expected_collapsed_ids2[] = { + UINT32_MAX, 0, 0, 0, UINT32_MAX, 0, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; collapsed_ids = UF_get_collapsed_cluster_ids(uf, is_in_cluster); uint32_t i; for (i = 0; i < uf->N; i++) - { - if (is_in_cluster[i]) - ASSERT_INT_EQUAL(expected_collapsed_ids2[i], collapsed_ids[i]); - } + ASSERT_INT_EQUAL(expected_collapsed_ids2[i], collapsed_ids[i]); lwfree(collapsed_ids); UF_destroy(uf); diff --git a/liblwgeom/lwunionfind.c b/liblwgeom/lwunionfind.c index 9ca47a1c3..7e78d8064 100644 --- a/liblwgeom/lwunionfind.c +++ b/liblwgeom/lwunionfind.c @@ -19,10 +19,10 @@ ********************************************************************** * * Copyright 2015 Daniel Baston + * Copyright 2026 Darafei Praliaskouski * **********************************************************************/ - #include "liblwgeom.h" #include "lwunionfind.h" #include @@ -150,6 +150,8 @@ UF_get_collapsed_cluster_ids(UNIONFIND *uf, const uint8_t *is_in_cluster) uint32_t last_old_id, current_new_id, i; uint8_t encountered_cluster = LW_FALSE; + memset(new_ids, 0xFF, uf->N * sizeof(uint32_t)); + current_new_id = 0; last_old_id = 0; for (i = 0; i < uf->N; i++) { ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ liblwgeom/cunit/cu_unionfind.c | 9 ++++----- liblwgeom/lwunionfind.c | 4 +++- 3 files changed, 9 insertions(+), 6 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 08:38:57 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 15:38:57 -0000 Subject: [PostGIS] #5975: Enable MobilityDB to call some PostGIS functions In-Reply-To: <050.98458873e5d5f9d80926d4393cd14396@osgeo.org> References: <050.98458873e5d5f9d80926d4393cd14396@osgeo.org> Message-ID: <065.5789d73b555b718d203ae233cc1f1846@osgeo.org> #5975: Enable MobilityDB to call some PostGIS functions --------------------------+--------------------------- Reporter: ezimanyi | Owner: pramsey Type: enhancement | Status: new Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.5.x Resolution: | Keywords: --------------------------+--------------------------- Comment (by Darafei Praliaskouski ): In [changeset:"5f207dbe59a552eba46617f8436d4478aa7045f7/git" 5f207db/git]: {{{#!CommitTicketReference repository="git" revision="5f207dbe59a552eba46617f8436d4478aa7045f7" Initialize skipped union-find cluster ids Initialize unassigned entries returned by UF_get_collapsed_cluster_ids to UINT32_MAX so callers and tests see deterministic values for elements outside the filtered cluster set. Closes https://github.com/postgis/postgis/pull/974 References #5975 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 09:04:12 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 09:04:12 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-605-g5034847fe Message-ID: <20260618160412.EF4621C557E@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 5034847fea82a43f56353719e2481056b3bd8860 (commit) from 5f207dbe59a552eba46617f8436d4478aa7045f7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5034847fea82a43f56353719e2481056b3bd8860 Author: Darafei Praliaskouski Date: Thu Jun 18 19:59:58 2026 +0400 Add single-geometry distance wrappers Add one-argument ST_MaxDistance and ST_LongestLine SQL wrappers that delegate to the existing same-geometry binary behavior, and document the new public overloads with regression coverage. Closes https://github.com/postgis/postgis/pull/953 Closes #4208 diff --git a/NEWS b/NEWS index 249f6c879..1c7f5fc8d 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #1124, shp2pgsql can create UNLOGGED tables for transient staging loads (Darafei Praliaskouski) + - #4208, Add single-geometry variants of ST_MaxDistance and ST_LongestLine + (Darafei Praliaskouski) - [topology] FindVertexSegmentPairsBelowDistance function (Sandro Santilli) - ST_CoverageEdges, returns MultiLinestring of distinct shared edges in polygonal coverage (Paul Ramsey) diff --git a/doc/reference_measure.xml b/doc/reference_measure.xml index 5b2de34fa..66585ee67 100644 --- a/doc/reference_measure.xml +++ b/doc/reference_measure.xml @@ -1242,6 +1242,12 @@ CAST('SPHEROID["GRS_1980",6378137,298.257222101]' As spheroid) As sph_m) as foo + + geometry ST_LongestLine + + geometry + g + geometry ST_LongestLine @@ -1265,10 +1271,11 @@ CAST('SPHEROID["GRS_1980",6378137,298.257222101]' As spheroid) As sph_m) as foo The length of the line is equal to the distance returned by . - If g1 and g2 are the same geometry, returns the line between the two vertices farthest apart in the geometry. + If only one geometry is provided, or g1 and g2 are the same geometry, returns the line between the two vertices farthest apart in the geometry. The endpoints of the line lie on the circle computed by . Availability: 1.5.0 + Enhanced: 3.7.0 - support for a single geometry input.
@@ -1322,9 +1329,9 @@ LINESTRING(20 10,105.3073372946034 186.95518130045156) -SELECT ST_AsText( ST_LongestLine( geom, geom)) AS llinewkt, - ST_MaxDistance( geom, geom) AS max_dist, - ST_Length( ST_LongestLine(geom, geom)) AS lenll +SELECT ST_AsText( ST_LongestLine( geom)) AS llinewkt, + ST_MaxDistance( geom) AS max_dist, + ST_Length( ST_LongestLine(geom)) AS lenll FROM (SELECT 'POLYGON ((40 180, 110 160, 180 180, 180 120, 140 90, 160 40, 80 10, 70 40, 20 50, 40 180), (60 140, 99 77.5, 90 140, 60 140))'::geometry AS geom) AS t; @@ -1452,6 +1459,10 @@ SELECT ST_AsEWKT(ST_3DLongestLine(line,pt)) AS lol3d_line_pt, + + float ST_MaxDistance + geometry g + float ST_MaxDistance geometry g1 @@ -1468,11 +1479,12 @@ SELECT ST_AsEWKT(ST_3DLongestLine(line,pt)) AS lol3d_line_pt, The maximum distance always occurs between two vertices. This is the length of the line returned by . - If g1 and g2 are the same geometry, returns the distance between + If only one geometry is provided, or g1 and g2 are the same geometry, returns the distance between the two vertices farthest apart in that geometry. Availability: 1.5.0 + Enhanced: 3.7.0 - support for a single geometry input. Examples @@ -1489,8 +1501,7 @@ SELECT ST_MaxDistance('POINT(0 0)'::geometry, 'LINESTRING ( 2 2, 2 2 )'::geometr Maximum distance between vertices of a single geometry. -SELECT ST_MaxDistance('POLYGON ((10 10, 10 0, 0 0, 10 10))'::geometry, - 'POLYGON ((10 10, 10 0, 0 0, 10 10))'::geometry); +SELECT ST_MaxDistance('POLYGON ((10 10, 10 0, 0 0, 10 10))'::geometry); ------------------ 14.142135623730951 diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 580237410..1264a0822 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -6168,6 +6168,12 @@ CREATE OR REPLACE FUNCTION ST_MaxDistance(geom1 geometry, geom2 geometry) LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE _COST_HIGH; +CREATE OR REPLACE FUNCTION ST_MaxDistance(geom geometry) + RETURNS float8 + AS 'SELECT @extschema at .ST_MaxDistance($1, $1)' + LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE + _COST_HIGH; + CREATE OR REPLACE FUNCTION ST_ClosestPoint(geom1 geometry, geom2 geometry) RETURNS geometry AS 'MODULE_PATHNAME', 'LWGEOM_closestpoint' @@ -6192,6 +6198,12 @@ CREATE OR REPLACE FUNCTION ST_LongestLine(geom1 geometry, geom2 geometry) LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE _COST_HIGH; +CREATE OR REPLACE FUNCTION ST_LongestLine(geom geometry) + RETURNS geometry + AS 'SELECT @extschema at .ST_LongestLine($1, $1)' + LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE + _COST_HIGH; + -- Availability: 2.2.0 CREATE OR REPLACE FUNCTION ST_SwapOrdinates(geom geometry, ords cstring) RETURNS geometry diff --git a/regress/core/measures.sql b/regress/core/measures.sql index 3e01f5175..544ceb84b 100644 --- a/regress/core/measures.sql +++ b/regress/core/measures.sql @@ -45,6 +45,7 @@ select 'st_maxdistance_134', st_maxdistance('POINT(1 2)', 'POINT(1 2)'); select 'st_maxdistance_135', st_maxdistance('POINT(5 0)', 'POINT(10 12)'); select 'st_maxdistance_136', st_maxdistance('POINT(0 0)', ST_translate('POINT(0 0)', 5, 12, 0)); +select 'st_maxdistance_1arg', st_maxdistance('LINESTRING(0 0,3 4,6 0)'::geometry); -- postgis-users/2006-May/012174.html select 'st_maxdistance_dist', st_maxdistance(a,b)::numeric(12,6), st_maxdistance(b,a)::numeric(12,6) from ( @@ -59,6 +60,7 @@ select 'st_longestline_134', st_astext(st_longestline('POINT(1 2)', 'POINT(1 2)' select 'st_longestline_135', st_astext(st_longestline('POINT(5 0)', 'POINT(10 12)')); select 'st_longestline_136', st_astext(st_longestline('POINT(0 0)', ST_translate('POINT(0 0)', 5, 12, 0))); +select 'st_longestline_1arg', st_astext(st_longestline('LINESTRING(0 0,3 4,6 0)'::geometry)); -- postgis-users/2006-May/012174.html select 'st_longestline_dist', st_astext(st_longestline(a,b)), st_astext(st_longestline(b,a)) from ( diff --git a/regress/core/measures_expected b/regress/core/measures_expected index e0b654476..798eaa2fc 100644 --- a/regress/core/measures_expected +++ b/regress/core/measures_expected @@ -16,10 +16,12 @@ st_shortestline_dist|LINESTRING(10 0,11 0)|LINESTRING(11 0,10 0) st_maxdistance_134|0 st_maxdistance_135|13 st_maxdistance_136|13 +st_maxdistance_1arg|6 st_maxdistance_dist|22.360680|22.360680 st_longestline_134|LINESTRING(1 2,1 2) st_longestline_135|LINESTRING(5 0,10 12) st_longestline_136|LINESTRING(0 0,5 12) +st_longestline_1arg|LINESTRING(0 0,6 0) st_longestline_dist|LINESTRING(0 0,20 10)|LINESTRING(20 10,0 0) distancetest1|1|50|LINESTRING(17 18,17 19)|LINESTRING(17 19,17 18)|LINESTRING(29 39,-1 -1)|LINESTRING(-1 -1,29 39) distancetest2|0|50|0.0000000000|0.0000000000|0.0000000000|0.0000000000|LINESTRING(-40 -20,-10 20)|LINESTRING(-10 20,-40 -20) ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ doc/reference_measure.xml | 25 ++++++++++++++++++------- postgis/postgis.sql.in | 12 ++++++++++++ regress/core/measures.sql | 2 ++ regress/core/measures_expected | 2 ++ 5 files changed, 36 insertions(+), 7 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 09:04:14 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 16:04:14 -0000 Subject: [PostGIS] #4208: Single geometry versions of ST_MaxDistance and ST_LongestLine In-Reply-To: <048.ce7865e78c985a85aced1bd781b0b1db@osgeo.org> References: <048.ce7865e78c985a85aced1bd781b0b1db@osgeo.org> Message-ID: <063.32fde97e2cfb9e1fe97bc6d3b7ef3403@osgeo.org> #4208: Single geometry versions of ST_MaxDistance and ST_LongestLine ----------------------+----------------------------- Reporter: komzpa | Owner: komzpa Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: 2.4.x Resolution: fixed | Keywords: ----------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"5034847fea82a43f56353719e2481056b3bd8860/git" 5034847/git]: {{{#!CommitTicketReference repository="git" revision="5034847fea82a43f56353719e2481056b3bd8860" Add single-geometry distance wrappers Add one-argument ST_MaxDistance and ST_LongestLine SQL wrappers that delegate to the existing same-geometry binary behavior, and document the new public overloads with regression coverage. Closes https://github.com/postgis/postgis/pull/953 Closes #4208 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 09:08:08 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 09:08:08 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-606-gb1b94b6aa Message-ID: <20260618160808.7C36E1C5D15@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via b1b94b6aaba4ef0c9a5fadc18ef0b7edfb43cda9 (commit) from 5034847fea82a43f56353719e2481056b3bd8860 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b1b94b6aaba4ef0c9a5fadc18ef0b7edfb43cda9 Author: Darafei Praliaskouski Date: Thu Jun 18 20:06:45 2026 +0400 Remove ST_MemCollect aggregate Remove the ST_MemCollect aggregate from the install script, drop any existing aggregate during upgrades, and document the removal as a 3.7 breaking change. Closes https://github.com/postgis/postgis/pull/909 Closes #1793 diff --git a/NEWS b/NEWS index 1c7f5fc8d..4cf3f5e26 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #6052, [tiger_geocoder] Extension removed and moved to https://git.osgeo.org/postgis/postgis_tiger_geocoder (Regina Obe) - #6079, Remove support for GEOS < 3.10 (Sandro Santilli) + - #1793, Remove ST_MemCollect aggregate (Darafei Praliaskouski) * New Features * diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 1264a0822..3647429c3 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -4271,16 +4271,6 @@ CREATE OR REPLACE FUNCTION ST_Collect(geom1 geometry, geom2 geometry) LANGUAGE 'c' IMMUTABLE PARALLEL SAFE _COST_LOW; --- Availability: 1.2.2 --- Changed: 2.3.0 to support PostgreSQL 9.6 --- Changed: 2.3.1 to support PostgreSQL 9.6 parallel safe -CREATE AGGREGATE ST_MemCollect(geometry)( - sfunc = ST_collect, - combinefunc = ST_collect, - parallel = safe, - stype = geometry - ); - -- Availability: 1.2.2 CREATE OR REPLACE FUNCTION ST_Collect(geometry[]) RETURNS geometry diff --git a/postgis/postgis_after_upgrade.sql b/postgis/postgis_after_upgrade.sql index 0e6f507d2..7d86c9a5b 100644 --- a/postgis/postgis_after_upgrade.sql +++ b/postgis/postgis_after_upgrade.sql @@ -28,6 +28,7 @@ DROP AGGREGATE IF EXISTS st_geomunion(geometry); DROP AGGREGATE IF EXISTS accum_old(geometry); DROP AGGREGATE IF EXISTS st_accum_old(geometry); DROP AGGREGATE IF EXISTS st_accum(geometry); -- Dropped in 3.0.0 +DROP AGGREGATE IF EXISTS ST_MemCollect(geometry); -- Dropped in 3.7.0 SELECT _postgis_drop_function_by_signature('pgis_geometry_accum_finalfn(internal)'); DROP AGGREGATE IF EXISTS st_astwkb_agg(geometry, integer); -- temporarily introduced before 2.2.0 final ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + postgis/postgis.sql.in | 10 ---------- postgis/postgis_after_upgrade.sql | 1 + 3 files changed, 2 insertions(+), 10 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 09:08:09 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 16:08:09 -0000 Subject: [PostGIS] #1793: Missing documentation for ST_MemCollect(geometry) In-Reply-To: <049.02ab7592f85d2f938c81932fec52b267@osgeo.org> References: <049.02ab7592f85d2f938c81932fec52b267@osgeo.org> Message-ID: <064.d9a96651a86f62cbddd11ba9869883e0@osgeo.org> #1793: Missing documentation for ST_MemCollect(geometry) ----------------------------+----------------------------- Reporter: Mike Taves | Owner: Mike Taves Type: task | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: documentation | Version: master Resolution: fixed | Keywords: ----------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"b1b94b6aaba4ef0c9a5fadc18ef0b7edfb43cda9/git" b1b94b6/git]: {{{#!CommitTicketReference repository="git" revision="b1b94b6aaba4ef0c9a5fadc18ef0b7edfb43cda9" Remove ST_MemCollect aggregate Remove the ST_MemCollect aggregate from the install script, drop any existing aggregate during upgrades, and document the removal as a 3.7 breaking change. Closes https://github.com/postgis/postgis/pull/909 Closes #1793 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 09:20:31 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 09:20:31 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-607-g663d84635 Message-ID: <20260618162031.5BCD11C5C45@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 663d846350266125cbed07fa50e3b534cfc4fe81 (commit) from b1b94b6aaba4ef0c9a5fadc18ef0b7edfb43cda9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 663d846350266125cbed07fa50e3b534cfc4fe81 Author: Darafei Praliaskouski Date: Thu Jun 18 20:18:07 2026 +0400 doc: document PostGIS function cost tiers Document the SQL cost-tier rule of thumb near the shared cost macros so contributors can pick DEFAULT, LOW, MEDIUM, or HIGH consistently. Clarify that detoasting is not a separate stable multiplier because its cost depends on input size and prior detoasting. Closes https://github.com/postgis/postgis/pull/933 Closes #2898 diff --git a/NEWS b/NEWS index 4cf3f5e26..ce02af436 100644 --- a/NEWS +++ b/NEWS @@ -50,6 +50,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Enhancements * + - #2898, Document SQL function cost tiers for contributors + (Darafei Praliaskouski) - #6062, [topology] Stop using recursive snapping, for improved robustness (Sandro Santilli) - #6065, Improved winding order computation robustness for rings having collapsed elements (Sandro Santilli) diff --git a/postgis/sqldefines.h.in b/postgis/sqldefines.h.in index d8bbfa312..4b88a65ba 100644 --- a/postgis/sqldefines.h.in +++ b/postgis/sqldefines.h.in @@ -20,7 +20,19 @@ * where the support functions have been used in * place of index SQL inlining. * See https://trac.osgeo.org/postgis/ticket/3675 - * for sideffects of costing inlined SQL. + * for side effects of costing inlined SQL. + * + * Cost tiers: + * - DEFAULT: metadata, casts, accessors, operators, and index helpers. + * - LOW: simple serialization, measurement, or calculation over one value. + * - MEDIUM: constructors, parsers, exporters, transforms, or algorithms that + * usually walk most or all coordinates, pixels, or input elements. + * - HIGH: expensive GEOS, geography, raster, or multi-input operations where + * planner support functions preserve index-assisted plans. + * + * These tiers describe planner-visible function work. Do not add a separate + * detoasting multiplier here: detoast cost depends on toasted input size and + * on whether the datum has already been detoasted before the function call. */ #define _COST_DEFAULT COST 1 #define _COST_LOW COST 50 @@ -52,4 +64,3 @@ #endif /* _LWPGIS_DEFINES */ - ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ postgis/sqldefines.h.in | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 09:20:33 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 16:20:33 -0000 Subject: [PostGIS] #2898: Define a guideline for function cost In-Reply-To: <046.2c7fdb97efac9cf2e14076f570f01a09@osgeo.org> References: <046.2c7fdb97efac9cf2e14076f570f01a09@osgeo.org> Message-ID: <061.b23d1fa778aa72bc862eb7806aa60619@osgeo.org> #2898: Define a guideline for function cost --------------------------+----------------------------- Reporter: strk | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"663d846350266125cbed07fa50e3b534cfc4fe81/git" 663d846/git]: {{{#!CommitTicketReference repository="git" revision="663d846350266125cbed07fa50e3b534cfc4fe81" doc: document PostGIS function cost tiers Document the SQL cost-tier rule of thumb near the shared cost macros so contributors can pick DEFAULT, LOW, MEDIUM, or HIGH consistently. Clarify that detoasting is not a separate stable multiplier because its cost depends on input size and prior detoasting. Closes https://github.com/postgis/postgis/pull/933 Closes #2898 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 09:29:33 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 09:29:33 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-609-gea6867474 Message-ID: <20260618162934.317891C683A@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via ea686747486090d3da1a40e5b753671699b4177d (commit) via defcb5edcd9d02ad5743e9c03a175a1b37b7b03c (commit) from 663d846350266125cbed07fa50e3b534cfc4fe81 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit ea686747486090d3da1a40e5b753671699b4177d Author: Darafei Praliaskouski Date: Thu Jun 18 20:27:54 2026 +0400 upgrade: clarify incomplete deprecated cleanup errors Report a PostGIS-specific diagnostic when a repeated upgrade cannot rename a replaced function because a deprecated alias from an earlier partial cleanup still exists. Add a focused create_upgrade generator check for that replaced-function error path. Closes https://github.com/postgis/postgis/pull/970 Closes #5487 diff --git a/NEWS b/NEWS index 2184d6798..0b6caaaeb 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Bug Fixes * + - #5487, Improve error detail for repeated upgrades after an incomplete + deprecated-function cleanup (Darafei Praliaskouski) - GH-899, [raster] Honor PostgreSQL interrupts in long-running GDAL progress callbacks (Darafei Praliaskouski) - #5975, Initialize skipped union-find cluster ids deterministically diff --git a/utils/Makefile.in b/utils/Makefile.in index 090bbedfd..42f1dd4b1 100644 --- a/utils/Makefile.in +++ b/utils/Makefile.in @@ -123,7 +123,10 @@ check-regress: check: check-unit -check-unit: postgis_restore-check +create_upgrade_replaced_function_errors_check: + srcdir=$(srcdir) PERL=$(PERL) $(SHELL) $(srcdir)/check_create_upgrade_replaced_function_errors.sh + +check-unit: postgis_restore-check create_upgrade_replaced_function_errors_check installdir: @mkdir -p $(DESTDIR)$(bindir) diff --git a/utils/check_create_upgrade_replaced_function_errors.sh b/utils/check_create_upgrade_replaced_function_errors.sh new file mode 100644 index 000000000..caa5d375d --- /dev/null +++ b/utils/check_create_upgrade_replaced_function_errors.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +set -e + +TMPDIR="${TMPDIR:-/tmp}/check_create_upgrade_replaced_function_errors.$$" +trap 'rm -rf "${TMPDIR}"' EXIT + +mkdir -p "${TMPDIR}" + +cat > "${TMPDIR}/postgis.sql" <<'SQL' +-- INSTALL VERSION: 3.7.0dev +-- Availability: 1.0.0 +-- Changed: 3.1.0 add a default argument +-- Replaces ST_Test(geometry) deprecated in 3.1.0 +CREATE OR REPLACE FUNCTION ST_Test(geometry, float8 DEFAULT 0.0) RETURNS geometry +AS 'MODULE_PATHNAME', 'ST_Test' +LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE; +SQL + +"${PERL:-perl}" "${srcdir:-.}/create_upgrade.pl" "${TMPDIR}/postgis.sql" > "${TMPDIR}/upgrade.sql" + +# The duplicate-function branch turns a PostgreSQL rename collision from a +# partially completed upgrade into an actionable PostGIS diagnostic. +grep -Fq \ + "PostGIS upgrade cannot rename replaced function st_test(geometry): leftover deprecated function st_test_deprecated_by_postgis_301(geometry) already exists" \ + "${TMPDIR}/upgrade.sql" + +grep -Fq \ + "retry SELECT postgis_extensions_upgrade()" \ + "${TMPDIR}/upgrade.sql" diff --git a/utils/create_upgrade.pl b/utils/create_upgrade.pl index 38826cfe6..b10ecc61e 100644 --- a/utils/create_upgrade.pl +++ b/utils/create_upgrade.pl @@ -505,6 +505,12 @@ EOF EXCEPTION WHEN undefined_function THEN RAISE DEBUG 'Replaced function $name($args) does not exist'; + WHEN duplicate_function THEN + -- The target name is left behind when an earlier upgrade could not drop + -- a deprecated function still referenced by user objects. + RAISE EXCEPTION 'PostGIS upgrade cannot rename replaced function $name($args): leftover deprecated function ${replacement} already exists' + USING DETAIL = 'A previous upgrade likely left ${replacement} because a user object still depends on it.', + HINT = 'Run SELECT postgis_full_version(); and inspect objects depending on functions named *_deprecated_by_postgis_*. Drop or update those objects, then retry SELECT postgis_extensions_upgrade().'; WHEN OTHERS THEN GET STACKED DIAGNOSTICS detail := PG_EXCEPTION_DETAIL; RAISE EXCEPTION 'Attempting to rename replaced function $name($args) got % (%)', SQLERRM, SQLSTATE @@ -1062,4 +1068,3 @@ END $$ LANGUAGE 'plpgsql'; - commit defcb5edcd9d02ad5743e9c03a175a1b37b7b03c Author: Darafei Praliaskouski Date: Thu Jun 18 20:24:43 2026 +0400 raster: honor registered interrupts in GDAL progress Register a postgis_raster liblwgeom interrupt callback so raster-only backends can propagate PostgreSQL cancel and death requests into long-running GDAL progress callbacks. Restore any previously registered callback on module unload. Closes https://github.com/postgis/postgis/pull/899 diff --git a/NEWS b/NEWS index ce02af436..2184d6798 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Bug Fixes * + - GH-899, [raster] Honor PostgreSQL interrupts in long-running GDAL + progress callbacks (Darafei Praliaskouski) - #5975, Initialize skipped union-find cluster ids deterministically (Darafei Praliaskouski) - GH-885, [topology] Avoid GMP overflow in ring orientation for very large diff --git a/raster/rt_core/rt_gdal.c b/raster/rt_core/rt_gdal.c index ff01c1d66..f41c246f4 100644 --- a/raster/rt_core/rt_gdal.c +++ b/raster/rt_core/rt_gdal.c @@ -68,6 +68,9 @@ rt_util_gdal_progress_func(double dfComplete, const char *pszMessage, void *pPro (void)dfComplete; (void)pszMessage; + if (_lwgeom_interrupt_callback) + (*_lwgeom_interrupt_callback)(); + if (_lwgeom_interrupt_requested) { // rtwarn("%s interrupted at %g", (const char*)pProgressArg, dfComplete); @@ -307,4 +310,3 @@ int rt_raster_gdal_contour( /* Done */ return TRUE; } - diff --git a/raster/rt_pg/rtpostgis.c b/raster/rt_pg/rtpostgis.c index 49089b70e..663fe8552 100644 --- a/raster/rt_pg/rtpostgis.c +++ b/raster/rt_pg/rtpostgis.c @@ -137,6 +137,7 @@ #include "utils/builtins.h" #include "utils/memutils.h" #include "utils/elog.h" +#include "miscadmin.h" /* PostGIS */ #include "postgis_config.h" @@ -149,6 +150,18 @@ #include "rtpostgis.h" #include "rtpg_internal.h" +static void +rtpg_interrupt_liblwgeom_callback(void) +{ +#ifdef WIN32 + if (UNBLOCKED_SIGNAL_QUEUE()) + pgwin32_dispatch_queued_signals(); +#endif + if (QueryCancelPending || ProcDiePending) + lwgeom_request_interrupt(); +} + +static lwinterrupt_callback *prev_liblwgeom_interrupt_callback = NULL; #ifndef __GNUC__ # define __attribute__ (x) @@ -715,6 +728,7 @@ _PG_init(void) { /* Install liblwgeom handlers */ pg_install_lwgeom_handlers(); + prev_liblwgeom_interrupt_callback = lwgeom_register_interrupt_callback(rtpg_interrupt_liblwgeom_callback); /* Install rtcore handlers */ rt_set_handlers_options(rt_pg_alloc, rt_pg_realloc, rt_pg_free, @@ -847,6 +861,9 @@ _PG_fini(void) { elog(NOTICE, "Goodbye from PostGIS Raster %s", POSTGIS_VERSION); + lwgeom_register_interrupt_callback(prev_liblwgeom_interrupt_callback); + prev_liblwgeom_interrupt_callback = NULL; + /* Clean up */ pfree(env_postgis_gdal_enabled_drivers); pfree(boot_postgis_gdal_enabled_drivers); @@ -859,6 +876,3 @@ _PG_fini(void) { /* Revert back to old context */ MemoryContextSwitchTo(old_context); } - - - ----------------------------------------------------------------------- Summary of changes: NEWS | 4 +++ raster/rt_core/rt_gdal.c | 4 ++- raster/rt_pg/rtpostgis.c | 20 ++++++++++++--- utils/Makefile.in | 5 +++- ...heck_create_upgrade_replaced_function_errors.sh | 30 ++++++++++++++++++++++ utils/create_upgrade.pl | 7 ++++- 6 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 utils/check_create_upgrade_replaced_function_errors.sh hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 09:29:35 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 16:29:35 -0000 Subject: [PostGIS] #5487: Confusing error when upgrading from partially upgraded database In-Reply-To: <046.0fc3dd0ca8a072e8ebba96ffa3bc1d3c@osgeo.org> References: <046.0fc3dd0ca8a072e8ebba96ffa3bc1d3c@osgeo.org> Message-ID: <061.7f19e2e0b98b4f43dc1d03c5aeeaecd4@osgeo.org> #5487: Confusing error when upgrading from partially upgraded database ----------------------+--------------------------- Reporter: strk | Owner: strk Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.5.7 Component: upgrade | Version: master Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"ea686747486090d3da1a40e5b753671699b4177d/git" ea686747/git]: {{{#!CommitTicketReference repository="git" revision="ea686747486090d3da1a40e5b753671699b4177d" upgrade: clarify incomplete deprecated cleanup errors Report a PostGIS-specific diagnostic when a repeated upgrade cannot rename a replaced function because a deprecated alias from an earlier partial cleanup still exists. Add a focused create_upgrade generator check for that replaced-function error path. Closes https://github.com/postgis/postgis/pull/970 Closes #5487 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 09:40:37 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 09:40:37 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-610-gd56c04e9a Message-ID: <20260618164037.526FF1C6969@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via d56c04e9a8e23f5f6ebddc1f9a0269b230838abf (commit) from ea686747486090d3da1a40e5b753671699b4177d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit d56c04e9a8e23f5f6ebddc1f9a0269b230838abf Author: Darafei Praliaskouski Date: Thu Jun 18 20:39:12 2026 +0400 doc: skip XML checks without xsltproc Let make check skip documentation XML validation when configure did not find xsltproc, while direct check-xml still reports the missing requirement. Closes https://github.com/postgis/postgis/pull/919 Closes #5655 diff --git a/NEWS b/NEWS index 0b6caaaeb..ebfe62cef 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Bug Fixes * + - #5655, [doc] Skip XML validation during `make check` when xsltproc is + unavailable (Darafei Praliaskouski) - #5487, Improve error detail for repeated upgrades after an incomplete deprecated-function cleanup (Darafei Praliaskouski) - GH-899, [raster] Honor PostgreSQL interrupts in long-running GDAL diff --git a/doc/Makefile.in b/doc/Makefile.in index b68c6ae1b..418d46ab6 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -264,6 +264,11 @@ VPATH = $(srcdir) CAN_CHECK_XML = yes +ifeq ($(XSLTPROC),) +check-xml: requirements_not_met_xsltproc +CAN_CHECK_XML = no +endif + ifeq ($(XMLLINT),) postgis-nospecial.xml: requirements_not_met_xmllint postgis-out.xml: requirements_not_met_xmllint ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ doc/Makefile.in | 5 +++++ 2 files changed, 7 insertions(+) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 09:40:38 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 16:40:38 -0000 Subject: [PostGIS] #5655: make check fails when you do not have docs building/testing requirements (build works) In-Reply-To: <046.51625eb8da0862a89a77aed72f465820@osgeo.org> References: <046.51625eb8da0862a89a77aed72f465820@osgeo.org> Message-ID: <061.00de59b921b20984fdb304c2bd92103c@osgeo.org> #5655: make check fails when you do not have docs building/testing requirements (build works) ---------------------+-------------------------------------- Reporter: strk | Owner: strk Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.5.7 Component: build | Version: 3.4.x Resolution: fixed | Keywords: documentation, testsuite ---------------------+-------------------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"d56c04e9a8e23f5f6ebddc1f9a0269b230838abf/git" d56c04e/git]: {{{#!CommitTicketReference repository="git" revision="d56c04e9a8e23f5f6ebddc1f9a0269b230838abf" doc: skip XML checks without xsltproc Let make check skip documentation XML validation when configure did not find xsltproc, while direct check-xml still reports the missing requirement. Closes https://github.com/postgis/postgis/pull/919 Closes #5655 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 09:57:17 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 09:57:17 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-611-g8868c689e Message-ID: <20260618165717.B08611C7162@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 8868c689e96dc91c50a0549aac3d7bf5b8b6238e (commit) from d56c04e9a8e23f5f6ebddc1f9a0269b230838abf (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 8868c689e96dc91c50a0549aac3d7bf5b8b6238e Author: Darafei Praliaskouski Date: Thu Jun 18 20:55:30 2026 +0400 regress: cover find_srid duplicate-table lookups Add ticket coverage for exact-schema find_srid calls, dotted table-name lookup, and geometry_columns rows when two schemas contain same-named geometry tables. Closes https://github.com/postgis/postgis/pull/951 Closes #3103 diff --git a/NEWS b/NEWS index ebfe62cef..33f074411 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Bug Fixes * + - #3103, Add regression coverage for exact-schema find_srid and + geometry_columns lookups (Darafei Praliaskouski) - #5655, [doc] Skip XML validation during `make check` when xsltproc is unavailable (Darafei Praliaskouski) - #5487, Improve error detail for repeated upgrades after an incomplete diff --git a/regress/core/tickets.sql b/regress/core/tickets.sql index 7da7f4c1f..3e0533a76 100644 --- a/regress/core/tickets.sql +++ b/regress/core/tickets.sql @@ -1584,6 +1584,26 @@ SELECT f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, t ORDER BY f_table_name, f_geometry_column; DROP TABLE IF EXISTS test5829, test5978; +-- ------------------------------------------------------------------------------------- +-- #3103, geometry_columns/find_srid exact-match behavior +CREATE SCHEMA test3103a; +CREATE SCHEMA test3103b; +CREATE TABLE test3103a.geomtab (geom geometry(Point, 4326)); +CREATE TABLE test3103b.geomtab (geom geometry(Point, 3857)); + +SELECT '#3103.1', find_srid('test3103a', 'geomtab', 'geom'); +SELECT '#3103.2', find_srid('', 'test3103b.geomtab', 'geom'); +SELECT '#3103.3', f_table_schema, srid + FROM geometry_columns + WHERE f_table_name = 'geomtab' + AND f_geometry_column = 'geom' + ORDER BY srid; + +DROP TABLE test3103a.geomtab; +DROP TABLE test3103b.geomtab; +DROP SCHEMA test3103a; +DROP SCHEMA test3103b; + -- ------------------------------------------------------------------------------------- -- #4828, geometry_columns should ignore pending NOT VALID SRID checks CREATE TABLE test4828 ( @@ -1643,4 +1663,3 @@ DROP TABLE IF EXISTS fault6028; -- #5357 SELECT '#5357', ST_AsText(ST_LineFromEncodedPolyline('__nphBgcoeiA?@', 6), 6); - diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected index dcdffa995..9c3451edd 100644 --- a/regress/core/tickets_expected +++ b/regress/core/tickets_expected @@ -490,6 +490,10 @@ public.test5978.geometry SRID:4326 TYPE:POINT DIMS:2 public|test5829|geom|2|4326|GEOMETRY public|test5978|geometry|2|4326|POINT public|test5978|shape|2|4326|POINT +#3103.1|4326 +#3103.2|3857 +#3103.3|test3103b|3857 +#3103.3|test3103a|4326 #4828|4326 #5987|LINESTRING(20 20,20.1 20,20.2 19.9)|LINESTRING(20 20,20.1 20,20.2 19.9) #5962|MULTIPOINT((1 1),(3 4))|POINT(1 1) ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ regress/core/tickets.sql | 21 ++++++++++++++++++++- regress/core/tickets_expected | 4 ++++ 3 files changed, 26 insertions(+), 1 deletion(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 09:57:19 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 16:57:19 -0000 Subject: [PostGIS] #3103: geometry_columns, find_srid performance regress tests In-Reply-To: <046.65fc534dcf2886ce4898173ee4d8dce3@osgeo.org> References: <046.65fc534dcf2886ce4898173ee4d8dce3@osgeo.org> Message-ID: <061.e9872e995790545f2a48617016610ee6@osgeo.org> #3103: geometry_columns, find_srid performance regress tests ----------------------+----------------------------- Reporter: robe | Owner: robe Type: task | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: 2.1.x Resolution: fixed | Keywords: ----------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"8868c689e96dc91c50a0549aac3d7bf5b8b6238e/git" 8868c689/git]: {{{#!CommitTicketReference repository="git" revision="8868c689e96dc91c50a0549aac3d7bf5b8b6238e" regress: cover find_srid duplicate-table lookups Add ticket coverage for exact-schema find_srid calls, dotted table-name lookup, and geometry_columns rows when two schemas contain same-named geometry tables. Closes https://github.com/postgis/postgis/pull/951 Closes #3103 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 10:14:14 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 10:14:14 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-612-g2f87b9ef2 Message-ID: <20260618171414.D866E1C7D9A@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 2f87b9ef28eb63e50d935da7141647ceb34f520f (commit) from 8868c689e96dc91c50a0549aac3d7bf5b8b6238e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 2f87b9ef28eb63e50d935da7141647ceb34f520f Author: Darafei Praliaskouski Date: Thu Jun 18 21:09:39 2026 +0400 liblwgeom: preserve TIN Z qualifiers in EWKT Preserve explicit Z and ZM qualifiers when ST_AsEWKT serializes TIN geometries, and cover the changed output in CUnit and SQL regressions. Closes https://github.com/postgis/postgis/pull/950 Closes #2583 diff --git a/NEWS b/NEWS index 33f074411..f4db1a5fc 100644 --- a/NEWS +++ b/NEWS @@ -112,6 +112,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - GH-848, CG_AlphaShape now returns a MultiPolygon (Jean Felder) - Flatgeobuf schema mismatch vulnerability (NeuroWinter) - #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey) + - #2583, Preserve Z/ZM dimensional qualifiers in ST_AsEWKT output for TIN + (Darafei Praliaskouski) PostGIS 3.6.0 diff --git a/liblwgeom/cunit/cu_algorithm.c b/liblwgeom/cunit/cu_algorithm.c index 6ac9da3c7..9d1519f65 100644 --- a/liblwgeom/cunit/cu_algorithm.c +++ b/liblwgeom/cunit/cu_algorithm.c @@ -798,7 +798,7 @@ test_lwtriangle_clip(void) ewkt = lwgeom_to_ewkt((LWGEOM *)c); // printf("c = %s\n", ewkt); - ASSERT_STRING_EQUAL(ewkt, "TIN(((0 0 0,1 1 1,3 2 2,0 0 0)))"); + ASSERT_STRING_EQUAL(ewkt, "TIN Z (((0 0 0,1 1 1,3 2 2,0 0 0)))"); lwfree(ewkt); lwcollection_free(c); lwgeom_free(g); @@ -808,7 +808,7 @@ test_lwtriangle_clip(void) ewkt = lwgeom_to_ewkt((LWGEOM *)c); // printf("c = %s\n", ewkt); - ASSERT_STRING_EQUAL(ewkt, "TIN(((0 0 0,1 1 1,1.5 1 1,0 0 0)))"); + ASSERT_STRING_EQUAL(ewkt, "TIN Z (((0 0 0,1 1 1,1.5 1 1,0 0 0)))"); lwfree(ewkt); lwcollection_free(c); lwgeom_free(g); @@ -820,7 +820,7 @@ test_lwtriangle_clip(void) // printf("c = %s\n", ewkt); ASSERT_STRING_EQUAL( ewkt, - "TIN(((1 1 1,2 1.5 2,2 1.333333333333 2,1 1 1)),((1 1 1,2 1.333333333333 2,1 0.666666666667 1,1 1 1)))"); + "TIN Z (((1 1 1,2 1.5 2,2 1.333333333333 2,1 1 1)),((1 1 1,2 1.333333333333 2,1 0.666666666667 1,1 1 1)))"); lwfree(ewkt); lwcollection_free(c); lwgeom_free(g); @@ -839,7 +839,7 @@ test_lwtriangle_clip(void) // printf("c = %s\n", ewkt); ASSERT_STRING_EQUAL( ewkt, - "TIN(((0 0 2,0 1 2,-1 2 2,0 0 2)),((0 1 2,0 0 2,0 1 4,0 1 2)),((-1 2 2,0 1 2,1 1 2,-1 2 2)),((0 0 2,-1 2 2,-1 -1 2,0 0 2)),((0 1 4,0 0 2,0 0 4,0 1 4)),((0 1 2,0 1 4,1 1 4,0 1 2)),((1 1 2,0 1 2,1 1 4,1 1 2)),((-1 2 2,1 1 2,2 2 2,-1 2 2)),((-1 -1 2,-1 2 2,-1 0 0,-1 -1 2)),((-1 -1 2,-1 0 0,-1 -1 0,-1 -1 2)),((0 0 2,-1 -1 2,1 0 2,0 0 2)),((0 0 4,0 0 2,1 0 2,0 0 4)),((0 1 4,0 0 4,1 0 4,0 1 4)),((1 1 4,0 1 4,1 0 4,1 1 4)),((1 1 2,1 1 4,1 0 4,1 1 2)),((2 2 2,1 1 2,2 -1 2,2 2 2)),((-1 2 2,2 2 2,0 2 0,-1 2 2)),((-1 2 2,0 2 0,-1 2 0,-1 2 2)),((-1 0 0,-1 2 2,-1 2 0,-1 0 0)),((-1 -1 2,-1 -1 0,1 -1 0,-1 -1 2)),((1 0 2,-1 -1 2,2 -1 2,1 0 2)),((0 0 4,1 0 2,1 0 4,0 0 4)),((1 1 2,1 0 4,1 0 2,1 1 2)),((2 -1 2,1 1 2,1 0 2,2 -1 2)),((2 2 2,2 -1 2,2 1 0,2 2 2)),((2 2 2,2 1 0,2 2 0,2 2 2)),((0 2 0,2 2 2,2 2 0,0 2 0)),((-1 -1 2,1 -1 0,2 -1 0,-1 -1 2)),((-1 -1 2,2 -1 0,2 -1 2,-1 -1 2)),((2 1 0,2 -1 2,2 -1 0,2 1 0)))"); + "TIN Z (((0 0 2,0 1 2,-1 2 2,0 0 2)),((0 1 2,0 0 2,0 1 4,0 1 2)),((-1 2 2,0 1 2,1 1 2,-1 2 2)),((0 0 2,-1 2 2,-1 -1 2,0 0 2)),((0 1 4,0 0 2,0 0 4,0 1 4)),((0 1 2,0 1 4,1 1 4,0 1 2)),((1 1 2,0 1 2,1 1 4,1 1 2)),((-1 2 2,1 1 2,2 2 2,-1 2 2)),((-1 -1 2,-1 2 2,-1 0 0,-1 -1 2)),((-1 -1 2,-1 0 0,-1 -1 0,-1 -1 2)),((0 0 2,-1 -1 2,1 0 2,0 0 2)),((0 0 4,0 0 2,1 0 2,0 0 4)),((0 1 4,0 0 4,1 0 4,0 1 4)),((1 1 4,0 1 4,1 0 4,1 1 4)),((1 1 2,1 1 4,1 0 4,1 1 2)),((2 2 2,1 1 2,2 -1 2,2 2 2)),((-1 2 2,2 2 2,0 2 0,-1 2 2)),((-1 2 2,0 2 0,-1 2 0,-1 2 2)),((-1 0 0,-1 2 2,-1 2 0,-1 0 0)),((-1 -1 2,-1 -1 0,1 -1 0,-1 -1 2)),((1 0 2,-1 -1 2,2 -1 2,1 0 2)),((0 0 4,1 0 2,1 0 4,0 0 4)),((1 1 2,1 0 4,1 0 2,1 1 2)),((2 -1 2,1 1 2,1 0 2,2 -1 2)),((2 2 2,2 -1 2,2 1 0,2 2 2)),((2 2 2,2 1 0,2 2 0,2 2 2)),((0 2 0,2 2 2,2 2 0,0 2 0)),((-1 -1 2,1 -1 0,2 -1 0,-1 -1 2)),((-1 -1 2,2 -1 0,2 -1 2,-1 -1 2)),((2 1 0,2 -1 2,2 -1 0,2 1 0)))"); lwfree(ewkt); lwcollection_free(c); lwgeom_free(g); diff --git a/liblwgeom/cunit/cu_gserialized1.c b/liblwgeom/cunit/cu_gserialized1.c index 7f443ca74..23f3b9743 100644 --- a/liblwgeom/cunit/cu_gserialized1.c +++ b/liblwgeom/cunit/cu_gserialized1.c @@ -720,7 +720,7 @@ static void test_lwgeom_clone(void) "SRID=4326;GEOMETRYCOLLECTION(POINT(0 1),POLYGON((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0)),MULTIPOLYGON(((-1 -1,-1 2.5,2 2,2 -1,-1 -1),(0 0,0 1,1 1,1 0,0 0),(-0.5 -0.5,-0.5 -0.4,-0.4 -0.4,-0.4 -0.5,-0.5 -0.5))))", "MULTICURVE((5 5 1 3,3 5 2 2,3 3 3 1,0 3 1 1),CIRCULARSTRING(0 0 0 0,0.26794 1 3 -2,0.5857864 1.414213 1 2))", "MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(-2 0,-1 -1,0 0,1 -1,2 0,0 2,-2 0),(-1 0,0 0.5,1 0,0 1,-1 0)),((7 8,10 10,6 14,4 11,7 8)))", - "TIN(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))" + "TIN Z (((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))" }; diff --git a/liblwgeom/cunit/cu_sfcgal.c b/liblwgeom/cunit/cu_sfcgal.c index fd26d58c1..86eb16562 100644 --- a/liblwgeom/cunit/cu_sfcgal.c +++ b/liblwgeom/cunit/cu_sfcgal.c @@ -103,7 +103,7 @@ test_sfcgal_noop(void) "MULTIPOLYGONM(((0 0 1,0 1 2,1 1 3,1 0 4,0 0 1)),((2 2 5,2 3 6,3 3 7,3 2 8,2 2 5)))", "MULTIPOLYGON(((0 0 1 10,0 1 2 20,1 1 3 30,1 0 4 40,0 0 1 10)),((2 2 5 50,2 3 6 60,3 3 7 70,3 2 8 80,2 2 5 50)))", "TINM(((0 0 1,0 1 2,1 0 3,0 0 1)),((0 0 1,1 0 3,1 1 4,0 0 1)))", - "TIN(((0 0 1 10,0 1 2 20,1 0 3 30,0 0 1 10)),((0 0 1 10,1 0 3 30,1 1 4 40,0 0 1 10)))", + "TIN ZM (((0 0 1 10,0 1 2 20,1 0 3 30,0 0 1 10)),((0 0 1 10,1 0 3 30,1 1 4 40,0 0 1 10)))", "POLYHEDRALSURFACEM(((0 0 1,0 1 2,1 1 3,1 0 4,0 0 1)),((0 0 1,1 0 4,1 -1 5,0 -1 6,0 0 1)))", "POLYHEDRALSURFACE(((0 0 1 10,0 1 2 20,1 1 3 30,1 0 4 40,0 0 1 10)),((0 0 1 10,1 0 4 40,1 -1 5 50,0 -1 6 60,0 0 1 10)))", "GEOMETRYCOLLECTIONM(LINESTRINGM(-1 -1 3,2 19 25,-4 20 15),POLYGONM((0 0 10,2 19 25,-4 20 15,0 0 10)))", diff --git a/liblwgeom/cunit/cu_surface.c b/liblwgeom/cunit/cu_surface.c index 074a9dd05..985eb63db 100644 --- a/liblwgeom/cunit/cu_surface.c +++ b/liblwgeom/cunit/cu_surface.c @@ -141,6 +141,24 @@ void tin_parse(void) lwfree(tmp); lwgeom_free(geom); + /* 3DZ */ + geom = lwgeom_from_wkt("TIN Z(((0 1 2,3 4 5,6 7 8,0 1 2)))", LW_PARSER_CHECK_NONE); + CU_ASSERT_EQUAL(strlen(cu_error_msg), 0); + CU_ASSERT_EQUAL(geom->type, TINTYPE); + tmp = lwgeom_to_ewkt(geom); + ASSERT_STRING_EQUAL("TIN Z (((0 1 2,3 4 5,6 7 8,0 1 2)))", tmp); + lwfree(tmp); + lwgeom_free(geom); + + /* 4D */ + geom = lwgeom_from_wkt("TIN ZM(((0 1 2 3,3 4 5 6,6 7 8 9,0 1 2 3)))", LW_PARSER_CHECK_NONE); + CU_ASSERT_EQUAL(strlen(cu_error_msg), 0); + CU_ASSERT_EQUAL(geom->type, TINTYPE); + tmp = lwgeom_to_ewkt(geom); + ASSERT_STRING_EQUAL("TIN ZM (((0 1 2 3,3 4 5 6,6 7 8 9,0 1 2 3)))", tmp); + lwfree(tmp); + lwgeom_free(geom); + /* ERROR: a missing Z values */ geom = lwgeom_from_wkt("TIN(((0 1 2,3 4 5,6 7,0 1 2)))", LW_PARSER_CHECK_NONE); ASSERT_STRING_EQUAL("can not mix dimensionality in a geometry", cu_error_msg); @@ -198,7 +216,9 @@ void tin_parse(void) CU_ASSERT_EQUAL(geom->type, TINTYPE); CU_ASSERT_EQUAL(geom->srid, SRID_UNKNOWN); tmp = lwgeom_to_ewkt(geom); - ASSERT_STRING_EQUAL("TIN(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))", tmp); + ASSERT_STRING_EQUAL( + "TIN Z (((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))", + tmp); lwfree(tmp); lwgeom_free(geom); @@ -209,7 +229,9 @@ void tin_parse(void) CU_ASSERT_EQUAL(FLAGS_GET_M(geom->flags), 1); CU_ASSERT_EQUAL(geom->srid, SRID_UNKNOWN); tmp = lwgeom_to_ewkt(geom); - ASSERT_STRING_EQUAL("TIN(((0 0 0 0,0 0 1 0,0 1 0 2,0 0 0 0)),((0 0 0 0,0 1 0 0,1 0 0 4,0 0 0 0)),((0 0 0 0,1 0 0 0,0 0 1 6,0 0 0 0)),((1 0 0 0,0 1 0 0,0 0 1 0,1 0 0 0)))", tmp); + ASSERT_STRING_EQUAL( + "TIN ZM (((0 0 0 0,0 0 1 0,0 1 0 2,0 0 0 0)),((0 0 0 0,0 1 0 0,1 0 0 4,0 0 0 0)),((0 0 0 0,1 0 0 0,0 0 1 6,0 0 0 0)),((1 0 0 0,0 1 0 0,0 0 1 0,1 0 0 0)))", + tmp); lwfree(tmp); lwgeom_free(geom); @@ -219,7 +241,9 @@ void tin_parse(void) CU_ASSERT_EQUAL(geom->type, TINTYPE); CU_ASSERT_EQUAL(geom->srid, 4326); tmp = lwgeom_to_ewkt(geom); - ASSERT_STRING_EQUAL("SRID=4326;TIN(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))", tmp); + ASSERT_STRING_EQUAL( + "SRID=4326;TIN Z (((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))", + tmp); lwfree(tmp); lwgeom_free(geom); diff --git a/liblwgeom/lwout_wkt.c b/liblwgeom/lwout_wkt.c index 967a04a9f..e3fe15045 100644 --- a/liblwgeom/lwout_wkt.c +++ b/liblwgeom/lwout_wkt.c @@ -19,10 +19,10 @@ ********************************************************************** * * Copyright (C) 2009 Paul Ramsey + * Copyright (C) 2026 Darafei Praliaskouski * **********************************************************************/ - #include "liblwgeom_internal.h" #include "lwgeom_log.h" #include "stringbuffer.h" @@ -43,6 +43,15 @@ static void lwnurbscurve_to_wkt_sb(const LWNURBSCURVE *curve, stringbuffer_t *sb static void dimension_qualifiers_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, uint8_t variant) { + if ((variant & WKT_EXTENDED) && geom->type == TINTYPE && FLAGS_GET_Z(geom->flags)) + { + stringbuffer_append_len(sb, " Z", 2); + if (FLAGS_GET_M(geom->flags)) + stringbuffer_append_len(sb, "M", 1); + stringbuffer_append_len(sb, " ", 1); + return; + } + /* Extended WKT: POINTM(0 0 0) */ #if 0 if ( (variant & WKT_EXTENDED) && ! (variant & WKT_IS_CHILD) && FLAGS_GET_M(geom->flags) && (!FLAGS_GET_Z(geom->flags)) ) diff --git a/regress/core/in_gml_expected b/regress/core/in_gml_expected index 1bd48ba70..5b5257ec2 100644 --- a/regress/core/in_gml_expected +++ b/regress/core/in_gml_expected @@ -166,24 +166,24 @@ polyhedralsurface_22|POLYHEDRALSURFACE(((1 2,4 5,7 8,1 2)),((10 11,12 13,14 15,1 polyhedralsurface_23|POLYHEDRALSURFACE(((1 2,3 4,5 6,1 2)),((7 8,10 11,13 14,7 8))) polyhedralsurface_24|POLYHEDRALSURFACE(((1 2 3,4 5 6,7 8 9,1 2 3))) ERROR: invalid GML representation -tin_1|TIN(((1 2 3,4 5 6,7 8 9,1 2 3))) -tin_2|SRID=4326;TIN(((1 2 3,4 5 6,7 8 9,1 2 3))) +tin_1|TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3))) +tin_2|SRID=4326;TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3))) ERROR: invalid GML representation ERROR: invalid GML representation ERROR: invalid GML representation ERROR: invalid GML representation ERROR: invalid GML representation -tin_8|TIN EMPTY -tin_9|TIN EMPTY -tin_10|TIN EMPTY -tin_11|TIN(((1 2 3,4 5 6,7 8 9,1 2 3)),((10 11 12,13 14 15,16 17 18,10 11 12))) -tin_12|TIN(((1 2 3,4 5 6,7 8 9,1 2 3)),((10 11 12,13 14 15,16 17 18,10 11 12))) -tin_13|TIN(((1 2 3,4 5 6,7 8 9,1 2 3)),((10 11 12,13 14 15,16 17 18,10 11 12)),((19 20 21,22 23 24,25 26 27,19 20 21))) +tin_8|TIN Z EMPTY +tin_9|TIN Z EMPTY +tin_10|TIN Z EMPTY +tin_11|TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3)),((10 11 12,13 14 15,16 17 18,10 11 12))) +tin_12|TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3)),((10 11 12,13 14 15,16 17 18,10 11 12))) +tin_13|TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3)),((10 11 12,13 14 15,16 17 18,10 11 12)),((19 20 21,22 23 24,25 26 27,19 20 21))) tin_14|TIN(((1 2,4 5,7 8,1 2)),((10 11,12 13,14 15,10 11))) tin_15|TIN(((1 2,3 4,5 6,1 2)),((7 8,10 11,13 14,7 8))) -tin_16|TIN(((1 2 3,4 5 6,7 8 9,1 2 3))) -tin_17|TIN(((1 2 3,4 5 6,7 8 9,1 2 3))) -tin_18|TIN(((1 2 3,4 5 6,7 8 9,1 2 3))) +tin_16|TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3))) +tin_17|TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3))) +tin_18|TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3))) collection_1|GEOMETRYCOLLECTION(POINT(1 2)) collection_2|GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6)) collection_3|GEOMETRYCOLLECTION(MULTIPOINT(1 2,3 4)) @@ -384,9 +384,9 @@ gml_48|SRID=4326;MULTIPOLYGON(((1 2 3,4 5 6,7 8 9,1 2 3))) gml_49|TIN(((1 2,3 4,5 6,1 2))) gml_50|SRID=27582;TIN(((1 2,3 4,5 6,1 2))) gml_51|SRID=4326;TIN(((1 2,3 4,5 6,1 2))) -gml_52|TIN(((1 2 3,4 5 6,7 8 9,1 2 3))) -gml_53|SRID=27582;TIN(((1 2 3,4 5 6,7 8 9,1 2 3))) -gml_54|SRID=4326;TIN(((1 2 3,4 5 6,7 8 9,1 2 3))) +gml_52|TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3))) +gml_53|SRID=27582;TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3))) +gml_54|SRID=4326;TIN Z (((1 2 3,4 5 6,7 8 9,1 2 3))) gml_55|GEOMETRYCOLLECTION(POINT(1 2)) gml_56|GEOMETRYCOLLECTION(POINT(1 2 3)) gml_57|SRID=27582;GEOMETRYCOLLECTION(POINT(1 2)) diff --git a/regress/core/triangulatedsurface.sql b/regress/core/triangulatedsurface.sql index cf0892e49..fe6fab17c 100644 --- a/regress/core/triangulatedsurface.sql +++ b/regress/core/triangulatedsurface.sql @@ -38,3 +38,7 @@ SELECT 'geometryN_01', ST_AsEWKT(ST_GeometryN('TIN EMPTY'::geometry, 1)); SELECT 'geometryN_02', ST_AsEWKT(ST_GeometryN('TIN(((0 0,0 0,0 1,0 0)))'::geometry, 1)); SELECT 'geometryN_03', ST_AsEWKT(ST_GeometryN('TIN(((0 0,0 0,0 1,0 0)))'::geometry, 0)); SELECT 'geometryN_04', ST_AsEWKT(ST_GeometryN('TIN(((0 0,0 0,0 1,0 0)))'::geometry, 2)); + +-- ST_AsEWKT dimensional qualifiers +SELECT '#2583.1', ST_AsEWKT(ST_GeomFromEWKT('TIN Z(((0 0 1,1 0 2,0 1 3,0 0 1)))')); +SELECT '#2583.2', ST_AsEWKT(ST_GeomFromEWKT('TIN ZM(((0 0 1 2,1 0 2 3,0 1 3 4,0 0 1 2)))')); diff --git a/regress/core/triangulatedsurface_expected b/regress/core/triangulatedsurface_expected index ab5d737f8..5c8722d2e 100644 --- a/regress/core/triangulatedsurface_expected +++ b/regress/core/triangulatedsurface_expected @@ -21,3 +21,5 @@ geometryN_01| geometryN_02|TIN(((0 0,0 0,0 1,0 0))) geometryN_03| geometryN_04| +#2583.1|TIN Z (((0 0 1,1 0 2,0 1 3,0 0 1))) +#2583.2|TIN ZM (((0 0 1 2,1 0 2 3,0 1 3 4,0 0 1 2))) ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ liblwgeom/cunit/cu_algorithm.c | 8 ++++---- liblwgeom/cunit/cu_gserialized1.c | 2 +- liblwgeom/cunit/cu_sfcgal.c | 2 +- liblwgeom/cunit/cu_surface.c | 30 +++++++++++++++++++++++++++--- liblwgeom/lwout_wkt.c | 11 ++++++++++- regress/core/in_gml_expected | 28 ++++++++++++++-------------- regress/core/triangulatedsurface.sql | 4 ++++ regress/core/triangulatedsurface_expected | 2 ++ 9 files changed, 65 insertions(+), 24 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 10:14:16 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 17:14:16 -0000 Subject: [PostGIS] #2583: Add TIN Z support to ST_AsEWKT and ST_GeomFromEWKT In-Reply-To: <055.5cc3a79ad5d97a04aae04515c31b5a54@osgeo.org> References: <055.5cc3a79ad5d97a04aae04515c31b5a54@osgeo.org> Message-ID: <070.f6b2541a35ee941aaa7222745c599eaf@osgeo.org> #2583: Add TIN Z support to ST_AsEWKT and ST_GeomFromEWKT ----------------------------+----------------------------- Reporter: smathermather | Owner: smathermather Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: 2.1.x Resolution: fixed | Keywords: ----------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"2f87b9ef28eb63e50d935da7141647ceb34f520f/git" 2f87b9ef/git]: {{{#!CommitTicketReference repository="git" revision="2f87b9ef28eb63e50d935da7141647ceb34f520f" liblwgeom: preserve TIN Z qualifiers in EWKT Preserve explicit Z and ZM qualifiers when ST_AsEWKT serializes TIN geometries, and cover the changed output in CUnit and SQL regressions. Closes https://github.com/postgis/postgis/pull/950 Closes #2583 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 10:20:05 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 10:20:05 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-613-gfc2a5bdd5 Message-ID: <20260618172005.659291A025D@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via fc2a5bdd5ea9e0f9a26a9374e0d3bb69ae4288b3 (commit) from 2f87b9ef28eb63e50d935da7141647ceb34f520f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit fc2a5bdd5ea9e0f9a26a9374e0d3bb69ae4288b3 Author: Darafei Praliaskouski Date: Thu Jun 18 21:18:39 2026 +0400 geography: stabilize 32-bit LRS and pole centroid tests Clamp geography interpolation at tolerant segment endpoints, skip zero-length interpolation segments, and assert signed pole latitude in centroid regressions. Closes https://github.com/postgis/postgis/pull/907 Closes #6073 Closes #6074 diff --git a/NEWS b/NEWS index f4db1a5fc..8a8baa0d2 100644 --- a/NEWS +++ b/NEWS @@ -72,6 +72,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed finite coordinates (Darafei Praliaskouski) - GH-892, Add OSS-Fuzz coverage for TWKB and serialized raster inputs, including guards for malformed TWKB reads and counts (Darafei Praliaskouski) + - #6073, #6074, Stabilize geography LRS endpoint interpolation and pole + centroid regressions on 32-bit systems (Darafei Praliaskouski) - #6082, Fix Japanese PDF build by avoiding non-ASCII arrows in SQL program listings (Darafei Praliaskouski) - GH-888, [sfcgal] Avoid stale detoasted geometry access in diff --git a/liblwgeom/lwgeodetic_measures.c b/liblwgeom/lwgeodetic_measures.c index 27f57ecdb..0640d0c39 100644 --- a/liblwgeom/lwgeodetic_measures.c +++ b/liblwgeom/lwgeodetic_measures.c @@ -317,15 +317,34 @@ geography_interpolate_points( else segment_length_frac = spheroid_distance(&g1, &g2, s) / length; + /* Duplicate vertices produce zero-length geodetic segments. Skip them + * before endpoint tolerance matching because spheroid interpolation with + * identical endpoints has no stable direction. */ + if (segment_length_frac <= 0.0) + { + p1 = p2; + g1 = g2; + continue; + } + /* If our target distance is before the total length we've seen * so far. create a new point some distance down the current * segment. */ - while ( length_fraction < length_fraction_consumed + segment_length_frac && points_found < points_to_interpolate ) + while (length_fraction <= length_fraction_consumed + segment_length_frac + FP_TOLERANCE && + points_found < points_to_interpolate) { + double segment_end_fraction = length_fraction_consumed + segment_length_frac; + double segment_fraction; geog2cart(&g1, &q1); geog2cart(&g2, &q2); - double segment_fraction = (length_fraction - length_fraction_consumed) / segment_length_frac; + /* The endpoint tolerance compensates for 32-bit accumulated fraction + * drift, but it must clamp before segment normalization so short + * segments are not extrapolated. */ + if (length_fraction > segment_end_fraction) + segment_fraction = 1.0; + else + segment_fraction = (length_fraction - length_fraction_consumed) / segment_length_frac; interpolate_point4d_spheroid(&p1, &p2, &pt, s, segment_fraction); ptarray_set_point4d(opa, points_found++, &pt); length_fraction += length_fraction_increment; @@ -342,7 +361,7 @@ geography_interpolate_points( if (points_found < points_to_interpolate) { getPoint4d_p(ipa, ipa->npoints - 1, &pt); - ptarray_set_point4d(opa, points_found, &pt); + ptarray_set_point4d(opa, points_found++, &pt); } if (opa->npoints <= 1) diff --git a/regress/core/geography.sql b/regress/core/geography.sql index 5f98c7066..6e5ca26c5 100644 --- a/regress/core/geography.sql +++ b/regress/core/geography.sql @@ -141,6 +141,14 @@ SELECT 'lrs_lip_2', ST_AsText(ST_LineInterpolatePoints(geography 'Linestring(4.3 SELECT 'lrs_lip_3', ST_AsText(ST_LineInterpolatePoints(geography 'Linestring(4.35 50.85, 37.617222 55.755833)', 1.0, false), 2); SELECT 'lrs_lip_4', ST_AsText(ST_LineInterpolatePoints(geography 'Linestring(4.35 50.85, 37.617222 55.755833)', 0.1, true), 2); SELECT 'lrs_lip_5', ST_AsText(ST_LineInterpolatePoints(geography 'Linestring(4.35 50.85, 37.617222 55.755833)', 0.1, false), 2); +SELECT 'lrs_lip_6073_short_segment', ST_Distance( + ST_LineInterpolatePoint(geography 'LINESTRING(0 0, 0 0.000000000001, 1 0)', 0.000000000001), + geography 'POINT(0 0.000000000001)' +) < 1e-8; +SELECT 'lrs_lip_6073_duplicate_start', ST_Distance( + ST_LineInterpolatePoint(geography 'LINESTRING(0 0, 0 0, 1 0)', 0.00000000000001), + geography 'POINT(0.00000000000001 0)' +) < 1e-8; SELECT 'lrs_llp_1', round(ST_LineLocatePoint(geography 'linestring(0 1, 50 1)', geography 'Point(25 0)')::numeric, 2); SELECT 'lrs_llp_2', round(ST_LineLocatePoint(geography 'linestring(0 1, 50 1)', geography 'Point(-5 0)')::numeric, 2); @@ -157,4 +165,3 @@ SELECT 'ticket_6076_perimeter', round(ST_Perimeter(ST_GeogFromText('GEOMETRYCOLL --SELECT 'lrs_cp_2', ST_AsText(ST_ClosestPoint(geography 'Point(25 20)', geography 'Linestring(0 20, 50 20)'), 3); SELECT 'lrs_sl_1', ST_AsText(ST_ShortestLine(geography 'linestring(0 40, 50 40)', 'Point(25 40)', true), 2); - diff --git a/regress/core/geography_centroid.sql b/regress/core/geography_centroid.sql index 260e4d32a..077a64ce2 100644 --- a/regress/core/geography_centroid.sql +++ b/regress/core/geography_centroid.sql @@ -1,6 +1,6 @@ -- check for pole crossing -SELECT c, ST_AsText(ST_Centroid(g::geography),6) FROM +SELECT c, ST_Y(ST_Centroid(g::geography)::geometry)::numeric(12,6) FROM ( VALUES ('geog_centroid_mpt_pole_north', 'MULTIPOINT ( 90 80, -90 80)'), ('geog_centroid_mpt_pole_south', 'MULTIPOINT ( 90 -80, -90 -80)') diff --git a/regress/core/geography_centroid_expected b/regress/core/geography_centroid_expected index b9e5ca7ca..805e6987c 100644 --- a/regress/core/geography_centroid_expected +++ b/regress/core/geography_centroid_expected @@ -1,5 +1,5 @@ -geog_centroid_mpt_pole_north|POINT(0 90) -geog_centroid_mpt_pole_south|POINT(0 -90) +geog_centroid_mpt_pole_north|90.000000 +geog_centroid_mpt_pole_south|-90.000000 geog_centroid_mpt_idl_1|180.000000|0.000000 geog_centroid_mpt_idl_2|179.500000|0.000000 geog_centroid_mpt_idl_3|-179.500000|0.000000 diff --git a/regress/core/geography_expected b/regress/core/geography_expected index 8584b7df0..6c5af43d8 100644 --- a/regress/core/geography_expected +++ b/regress/core/geography_expected @@ -61,6 +61,8 @@ lrs_lip_2|POINT(4.35 50.85) lrs_lip_3|POINT(37.62 55.76) lrs_lip_4|MULTIPOINT((7.27 51.73),(10.3 52.54),(13.43 53.27),(16.67 53.91),(20 54.47),(23.42 54.93),(26.9 55.29),(30.44 55.55),(34.02 55.7),(37.62 55.76)) lrs_lip_5|MULTIPOINT((7.27 51.73),(10.29 52.54),(13.43 53.27),(16.67 53.91),(20 54.46),(23.42 54.92),(26.9 55.29),(30.44 55.55),(34.02 55.7),(37.62 55.76)) +lrs_lip_6073_short_segment|t +lrs_lip_6073_duplicate_start|t lrs_llp_1|0.50 lrs_llp_2|0.00 lrs_llp_3|1.00 ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ liblwgeom/lwgeodetic_measures.c | 25 ++++++++++++++++++++++--- regress/core/geography.sql | 9 ++++++++- regress/core/geography_centroid.sql | 2 +- regress/core/geography_centroid_expected | 4 ++-- regress/core/geography_expected | 2 ++ 6 files changed, 37 insertions(+), 7 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 10:20:06 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 17:20:06 -0000 Subject: [PostGIS] #6073: Geography LRS tests failing on 32bit In-Reply-To: <046.e050c239c91a1bf4d681ad0d16d3e98a@osgeo.org> References: <046.e050c239c91a1bf4d681ad0d16d3e98a@osgeo.org> Message-ID: <061.426fc4d69a34f7245f025a17825de1ef@osgeo.org> #6073: Geography LRS tests failing on 32bit ----------------------+--------------------------- Reporter: strk | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: fixed | Keywords: 32bit ----------------------+--------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"fc2a5bdd5ea9e0f9a26a9374e0d3bb69ae4288b3/git" fc2a5bdd/git]: {{{#!CommitTicketReference repository="git" revision="fc2a5bdd5ea9e0f9a26a9374e0d3bb69ae4288b3" geography: stabilize 32-bit LRS and pole centroid tests Clamp geography interpolation at tolerant segment endpoints, skip zero- length interpolation segments, and assert signed pole latitude in centroid regressions. Closes https://github.com/postgis/postgis/pull/907 Closes #6073 Closes #6074 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 18 10:20:06 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 17:20:06 -0000 Subject: [PostGIS] #6074: Geography centroid tests fail on 32bit In-Reply-To: <046.4f0505cfc98781f4f985e5733b552ee9@osgeo.org> References: <046.4f0505cfc98781f4f985e5733b552ee9@osgeo.org> Message-ID: <061.6f65bba2758252ada010a52a88dab956@osgeo.org> #6074: Geography centroid tests fail on 32bit ----------------------+--------------------------- Reporter: strk | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: fixed | Keywords: 32bit ----------------------+--------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"fc2a5bdd5ea9e0f9a26a9374e0d3bb69ae4288b3/git" fc2a5bdd/git]: {{{#!CommitTicketReference repository="git" revision="fc2a5bdd5ea9e0f9a26a9374e0d3bb69ae4288b3" geography: stabilize 32-bit LRS and pole centroid tests Clamp geography interpolation at tolerant segment endpoints, skip zero- length interpolation segments, and assert signed pole latitude in centroid regressions. Closes https://github.com/postgis/postgis/pull/907 Closes #6073 Closes #6074 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 10:42:25 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 10:42:25 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-614-gafc9284ef Message-ID: <20260618174226.105221A0B0F@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via afc9284efd51e84ce985e3637e5177fe93f41e36 (commit) from fc2a5bdd5ea9e0f9a26a9374e0d3bb69ae4288b3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit afc9284efd51e84ce985e3637e5177fe93f41e36 Author: Darafei Praliaskouski Date: Thu Jun 18 21:33:25 2026 +0400 doc: clarify ST_LineSubstring 2D fractions References #5776 Closes https://github.com/postgis/postgis/pull/956 diff --git a/doc/reference_lrs.xml b/doc/reference_lrs.xml index c0c797c65..8080dedfb 100644 --- a/doc/reference_lrs.xml +++ b/doc/reference_lrs.xml @@ -381,8 +381,8 @@ FROM (SELECT ST_GeomFromText('LINESTRING(1 2, 4 5, 6 7)') As the_line) As foo; starting and ending at the given fractional locations. The first argument must be a LINESTRING. The second and third arguments are values in the range [0, 1] - representing the start and end locations - as fractions of line length. + representing the start and end locations. + For geometry inputs, the fractions are measured in 2D line length. The Z and M values are interpolated for added endpoints if present. @@ -479,6 +479,23 @@ SELECT ST_AsText(ST_LineSubstring( 'LINESTRING(-118.2436 34.0522, -71.0570 42.36 geog_sub | LINESTRING(-104.167064 38.854691,-87.674646 41.849854) geom_sub | LINESTRING(-102.530462 36.819064,-86.817324 39.585927) + + For geometry inputs, the fractional locations are based on the 2D + length of the line, even when the input has Z values. The resulting Z values + are interpolated along the selected 2D location. + + WITH data AS ( + SELECT 'LINESTRING Z (0 0 0, 0 2 5, 0 10 10)'::geometry AS geom + ) + SELECT ST_Length(geom) AS length_2d, + ST_3DLength(geom) AS length_3d, + ST_AsText(ST_LineSubstring(geom, 0, 0.5)) AS substring + FROM data; + + length_2d | length_3d | substring + -----------+------------------+------------------------------------- + 10 | 14.8191459391911 | LINESTRING Z (0 0 0,0 2 5,0 5 6.875) + ----------------------------------------------------------------------- Summary of changes: doc/reference_lrs.xml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 10:42:27 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 17:42:27 -0000 Subject: [PostGIS] #5776: ST_LineSubstring 3D support In-Reply-To: <048.96e8fdb3535d14517c85bab7d52c512d@osgeo.org> References: <048.96e8fdb3535d14517c85bab7d52c512d@osgeo.org> Message-ID: <063.27ebb693465ddff36921dbde2bb11881@osgeo.org> #5776: ST_LineSubstring 3D support --------------------------+--------------------------- Reporter: vla123 | Owner: pramsey Type: enhancement | Status: new Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.4.x Resolution: | Keywords: --------------------------+--------------------------- Comment (by Darafei Praliaskouski ): In [changeset:"afc9284efd51e84ce985e3637e5177fe93f41e36/git" afc9284/git]: {{{#!CommitTicketReference repository="git" revision="afc9284efd51e84ce985e3637e5177fe93f41e36" doc: clarify ST_LineSubstring 2D fractions References #5776 Closes https://github.com/postgis/postgis/pull/956 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 10:50:41 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 10:50:41 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-615-ge80ff0a0c Message-ID: <20260618175041.7F23E1A0BA1@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via e80ff0a0cf01e8834eb7fdef7d17161dd2a825b1 (commit) from afc9284efd51e84ce985e3637e5177fe93f41e36 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e80ff0a0cf01e8834eb7fdef7d17161dd2a825b1 Author: Darafei Praliaskouski Date: Thu Jun 18 21:48:41 2026 +0400 doc: flatten PDF manual images Closes #1408 Closes https://github.com/postgis/postgis/pull/931 diff --git a/NEWS b/NEWS index 8a8baa0d2..ad8c66e92 100644 --- a/NEWS +++ b/NEWS @@ -107,6 +107,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #5593, Docs: render manual images with GraphicsMagick without temporary files, enabling parallel builds, keeping ImageMagick fallbacks working, and documenting the generator workflow for contributors (Darafei Praliaskouski) + - #1408, Docs: flatten transparent manual images onto white backgrounds for + PDF builds while keeping HTML images transparent (Darafei Praliaskouski) - [fuzzers] Centralize OSS-Fuzz build/dependency logic in PostGIS scripts, prefer requested CXX over pg_config --cc for internal C++ checks, and make fuzzer linking/runtime dependency packaging portable diff --git a/doc/Makefile.in b/doc/Makefile.in index 418d46ab6..6230b2031 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -49,6 +49,7 @@ DOCSUFFIX=-en # TODO: change this ? html_builddir=$(abs_builddir)/html images_builddir=$(html_builddir)/images +pdf_images_builddir=$(abs_builddir)/pdf/images ifneq (,$(findstring dev,$(POSTGIS_MICRO_VERSION))) POSTGIS_DOWNLOAD_URL=https://postgis.net/stuff @@ -422,7 +423,7 @@ $(html_builddir)/postgis$(DOCSUFFIX).html: postgis-out.xml Makefile $< -postgis-${POSTGIS_MAJOR_VERSION}.${POSTGIS_MINOR_VERSION}.${POSTGIS_MICRO_VERSION}$(DOCSUFFIX).pdf: postgis-out.xml $(abs_srcdir)/texstyle-common.sty $(abs_srcdir)/texstyle.sty | images +postgis-${POSTGIS_MAJOR_VERSION}.${POSTGIS_MINOR_VERSION}.${POSTGIS_MICRO_VERSION}$(DOCSUFFIX).pdf: postgis-out.xml $(abs_srcdir)/texstyle-common.sty $(abs_srcdir)/texstyle.sty | images pdf-images ifeq ($(DBLATEX),) @echo @echo "configure was unable to find the 'dblatex' utility program." @@ -432,7 +433,7 @@ ifeq ($(DBLATEX),) else $(DBLATEX) -T native -t pdf \ -x "--path $(XSLT_PATH)" \ - -I "$(abs_builddir)/html" \ + -I "$(abs_builddir)/pdf" \ -P doc.collab.show=0 \ -P figure.note="images/note" \ -P figure.tip="images/tip" \ @@ -487,12 +488,16 @@ doxygen: doxygen.cfg images images-install images-uninstall images-clean: $(MAKE) -C $(images_builddir) $@ +pdf-images: images + $(MAKE) -C $(images_builddir) $@ PDF_IMAGES_BUILD_DIR="$(pdf_images_builddir)" + html-clean: rm -f $(html_builddir)/postgis$(DOCSUFFIX).html rm -rf $(html_builddir)/postgis$(DOCSUFFIX)/ pdf-clean: rm -f postgis*$(DOCSUFFIX).pdf + rm -rf $(abs_builddir)/pdf epub-clean: rm -f postgis*$(DOCSUFFIX).epub diff --git a/doc/html/images/Makefile.in b/doc/html/images/Makefile.in index 288065530..daeb3b706 100644 --- a/doc/html/images/Makefile.in +++ b/doc/html/images/Makefile.in @@ -262,6 +262,9 @@ ALL_IMAGES = \ $(GENERATED_IMAGES_RESIZED) \ $(STATIC_IMAGES) +PDF_IMAGES_BUILD_DIR ?= pdf-images +PDF_IMAGES = $(ALL_IMAGES:%=$(PDF_IMAGES_BUILD_DIR)/%) + OBJS=styles.o generator.o # Build the generator @@ -270,6 +273,8 @@ all: generator # generate the images images: $(ALL_IMAGES) +pdf-images: $(PDF_IMAGES) + images-install: $(ALL_IMAGES) mkdir -p $(DESTDIR)$(htmldir)/images $(INSTALL_DATA) $(ALL_IMAGES) $(DESTDIR)$(htmldir)/images/ @@ -285,6 +290,23 @@ $(OBJS): %.o: %.c $(STATIC_IMAGES): ln -fs $(srcdir)/static/$@ $@ +$(PDF_IMAGES_BUILD_DIR)/%: % + @mkdir -p $(dir $@) + @converter=$${POSTGIS_DOC_CONVERTER:-}; \ + if test -z "$$converter"; then \ + if command -v gm >/dev/null 2>&1; then \ + converter="gm convert"; \ + elif command -v magick >/dev/null 2>&1; then \ + converter="magick convert"; \ + elif command -v convert >/dev/null 2>&1; then \ + converter="convert"; \ + else \ + echo "Could not find GraphicsMagick or ImageMagick executables (gm, magick, convert)." >&2; \ + exit 1; \ + fi; \ + fi; \ + $$converter "$<" -background white -flatten "$@" + # Command to build each of the .wkt files $(GENERATED_IMAGES): %.png: wkt/%.wkt generator wkt/styles.conf @./generator $< $@ @@ -312,3 +334,4 @@ distclean: clean images-clean: rm -f $(ALL_IMAGES) + rm -rf $(PDF_IMAGES_BUILD_DIR) ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ doc/Makefile.in | 9 +++++++-- doc/html/images/Makefile.in | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 10:50:43 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 17:50:43 -0000 Subject: [PostGIS] #1408: PDF generator sets transparency to black In-Reply-To: <046.00cd0d815732906567acbf797834bd88@osgeo.org> References: <046.00cd0d815732906567acbf797834bd88@osgeo.org> Message-ID: <061.6c2c5afa8c5184867d7155688c3c49c8@osgeo.org> #1408: PDF generator sets transparency to black ----------------------------+----------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: documentation | Version: master Resolution: fixed | Keywords: ----------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"e80ff0a0cf01e8834eb7fdef7d17161dd2a825b1/git" e80ff0a/git]: {{{#!CommitTicketReference repository="git" revision="e80ff0a0cf01e8834eb7fdef7d17161dd2a825b1" doc: flatten PDF manual images Closes #1408 Closes https://github.com/postgis/postgis/pull/931 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 18 11:14:53 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 18:14:53 -0000 Subject: [PostGIS] #6075: Extend ST_GetFaceGeometry with a optional srid parameter for geom In-Reply-To: <050.576af3d8862a6003859386a81241cf59@osgeo.org> References: <050.576af3d8862a6003859386a81241cf59@osgeo.org> Message-ID: <065.acbbc0c4519817f992e575bdd0156ddc@osgeo.org> #6075: Extend ST_GetFaceGeometry with a optional srid parameter for geom --------------------------------+--------------------------- Reporter: Lars Aksel Opsahl | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: topology | Version: 3.6.x Resolution: invalid | Keywords: --------------------------------+--------------------------- Changes (by komzpa): * resolution: => invalid * status: new => closed Comment: Closing as invalid as it is not clear what could be done and what is the expected result. Some pictures of "what we got" vs "what we expected" may help if you resubmit. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 11:35:26 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 11:35:26 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-616-gbf9cc9f63 Message-ID: <20260618183527.1006B1A1876@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via bf9cc9f63a8a1557976a2518792167fada45ed2d (commit) from e80ff0a0cf01e8834eb7fdef7d17161dd2a825b1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit bf9cc9f63a8a1557976a2518792167fada45ed2d Author: Darafei Praliaskouski Date: Thu Jun 18 22:21:37 2026 +0400 raster: document raster2pgsql SRID reprojection Closes #3743 Closes https://github.com/postgis/postgis/pull/964 diff --git a/NEWS b/NEWS index ad8c66e92..af7656e13 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #6062, [topology] Stop using recursive snapping, for improved robustness (Sandro Santilli) - #6065, Improved winding order computation robustness for rings having collapsed elements (Sandro Santilli) + - #3743, [raster] Document and test raster2pgsql -s FROM_SRID:SRID + reprojection support (Darafei Praliaskouski) * Bug Fixes * diff --git a/doc/using_raster_dataman.xml b/doc/using_raster_dataman.xml index ef79c1164..2f8773895 100644 --- a/doc/using_raster_dataman.xml +++ b/doc/using_raster_dataman.xml @@ -177,10 +177,10 @@ Available GDAL raster formats: - + - Assign output raster with specified SRID. If not provided or is zero, raster's metadata will be checked to determine an appropriate SRID. + Assign the output raster to the specified SRID. When FROM_SRID is also provided, raster2pgsql marks the input raster with FROM_SRID and emits SQL that reprojects the raster to the target SRID. If the source SRID is omitted or is zero, the raster metadata will be checked to determine an appropriate source SRID. Reprojection cannot be used with copy mode. diff --git a/raster/loader/raster2pgsql.c b/raster/loader/raster2pgsql.c index f593ac64b..68f68b526 100644 --- a/raster/loader/raster2pgsql.c +++ b/raster/loader/raster2pgsql.c @@ -8,6 +8,7 @@ * Copyright 2009 Mark Cave-Ayland * Copyright (C) 2011 Regents of the University of California * + * Copyright 2026 Darafei Praliaskouski * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -338,25 +339,17 @@ chartrim(const char *input, char *remove) { static void usage() { printf(_("RELEASE: %s GDAL_VERSION=%d (%s)\n"), POSTGIS_LIB_VERSION, POSTGIS_GDAL_VERSION, xstr(POSTGIS_REVISION)); - printf(_( - "USAGE: raster2pgsql [] [ [ ...]] [[.]]\n" - " Multiple rasters can also be specified using wildcards (*,?).\n" - "\n" - "OPTIONS:\n" - )); - /* - printf(_( - " -s [:] Set the SRID field. Defaults to %d.\n" - " Optionally reprojects from given SRID (cannot be used with -Y).\n" - " Raster's metadata will be checked to determine an appropriate SRID.\n" - " If a srid of %d is provided (either as from or as target).\n" - ), SRID_UNKNOWN, SRID_UNKNOWN); - */ - printf(_( - " -s Set the SRID field. Defaults to %d. If SRID not\n" - " provided or is %d, raster's metadata will be checked to\n" - " determine an appropriate SRID.\n" - ), SRID_UNKNOWN, SRID_UNKNOWN); + printf( + _("USAGE: raster2pgsql [] [ [ ...]] [[.]
]\n" + " Multiple rasters can also be specified using wildcards (*,?).\n" + "\n" + "OPTIONS:\n")); + printf(_(" -s [:] Set the SRID field. Defaults to %d.\n" + " Optionally reprojects from given SRID (cannot be used with -Y).\n" + " Raster's metadata will be checked to determine an appropriate SRID.\n" + " Metadata lookup is also used when %d is provided as from or target.\n"), + SRID_UNKNOWN, + SRID_UNKNOWN); printf(_( " -b Index (1-based) of band to extract from raster. For more\n" " than one band index, separate with comma (,). Ranges can be\n" diff --git a/raster/test/regress/loader/Projected.opts b/raster/test/regress/loader/Projected.opts index d98e23d0d..12a2b1e3b 100644 --- a/raster/test/regress/loader/Projected.opts +++ b/raster/test/regress/loader/Projected.opts @@ -1 +1 @@ --s :3857 -l 2 +-s 4326:3857 -l 2 ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ doc/using_raster_dataman.xml | 4 ++-- raster/loader/raster2pgsql.c | 31 ++++++++++++------------------- raster/test/regress/loader/Projected.opts | 2 +- 4 files changed, 17 insertions(+), 22 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 11:35:29 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 18:35:29 -0000 Subject: [PostGIS] #3743: raster2pgsql correctly support the -s from_srid:to_srid In-Reply-To: <046.4f75087fbeecf5a3f22400d858787773@osgeo.org> References: <046.4f75087fbeecf5a3f22400d858787773@osgeo.org> Message-ID: <061.2bc28834711f863fe54e9816de9a3083@osgeo.org> #3743: raster2pgsql correctly support the -s from_srid:to_srid --------------------------+----------------------------- Reporter: robe | Owner: robe Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: 2.3.x Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: assigned => closed Comment: In [changeset:"bf9cc9f63a8a1557976a2518792167fada45ed2d/git" bf9cc9f6/git]: {{{#!CommitTicketReference repository="git" revision="bf9cc9f63a8a1557976a2518792167fada45ed2d" raster: document raster2pgsql SRID reprojection Closes #3743 Closes https://github.com/postgis/postgis/pull/964 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 11:46:23 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 11:46:23 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-617-g965711498 Message-ID: <20260618184623.65BBE1A2544@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 96571149829e3a65f8ad7b4c488b8d1ca4666137 (commit) from bf9cc9f63a8a1557976a2518792167fada45ed2d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 96571149829e3a65f8ad7b4c488b8d1ca4666137 Author: Darafei Praliaskouski Date: Thu Jun 18 22:39:47 2026 +0400 fuzzers: keep recursive checks on source makefile diff --git a/fuzzers/Makefile b/fuzzers/Makefile index 01b324312..51c4ed5e2 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -1,4 +1,5 @@ -FUZZER_SRC_DIR ?= $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +FUZZER_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +FUZZER_SRC_DIR ?= $(abspath $(dir $(FUZZER_MAKEFILE))) POSTGIS_BUILD_DIR ?= $(abspath ..) FUZZER_OUT ?= /tmp FUZZER_WORK ?= $(FUZZER_OUT)/postgis-fuzzer-check @@ -35,10 +36,10 @@ check: set -e; \ if { command -v python3 >/dev/null 2>&1 && python3 -m zipfile --help >/dev/null 2>&1; } || \ { command -v unzip >/dev/null 2>&1 && unzip -v >/dev/null 2>&1; }; then \ - $(MAKE) check-corpus; \ + $(MAKE) -f "$(FUZZER_MAKEFILE)" check-corpus; \ else \ echo "No seed corpus zip extractor found; running fuzzer smoke check without corpus replay."; \ - $(MAKE) dummyfuzzers; \ + $(MAKE) -f "$(FUZZER_MAKEFILE)" dummyfuzzers; \ for fuzzer in $(FUZZER_NAMES); do \ "$(FUZZER_OUT)/$${fuzzer}"; \ done; \ ----------------------------------------------------------------------- Summary of changes: fuzzers/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 12:20:28 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 19:20:28 -0000 Subject: [PostGIS] #6075: Extend ST_GetFaceGeometry with a optional srid parameter for geom In-Reply-To: <050.576af3d8862a6003859386a81241cf59@osgeo.org> References: <050.576af3d8862a6003859386a81241cf59@osgeo.org> Message-ID: <065.1e5d6fd4127cd460e19692a22ae686db@osgeo.org> #6075: Extend ST_GetFaceGeometry with a optional srid parameter for geom --------------------------------+--------------------------- Reporter: Lars Aksel Opsahl | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: topology | Version: 3.6.x Resolution: invalid | Keywords: --------------------------------+--------------------------- Changes (by Lars Aksel Opsahl): * Attachment "Screenshot 2026-06-18 at 21.18.18.png" added. Before transform -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Thu Jun 18 14:14:14 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 14:14:14 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-618-g63cbf4f06 Message-ID: <20260618211414.7740E1A4183@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 63cbf4f069afebe50cb520b7abe6440c898842e9 (commit) from 96571149829e3a65f8ad7b4c488b8d1ca4666137 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 63cbf4f069afebe50cb520b7abe6440c898842e9 Author: Darafei Praliaskouski Date: Fri Jun 19 00:25:55 2026 +0400 raster: fix import, warp, and GDAL log handling Fix raster behavior covering ST_ReclassExact band ownership, Float16 pixel-line writes, legacy GDAL signed-byte imports, mixed nodata/no-nodata warps, zero-band warp nodata allocation, and GDAL credential-bearing log redaction. No extension upgrade SQL is required because SQL definitions and catalog-visible objects are unchanged. Closes https://github.com/postgis/postgis/pull/894 diff --git a/NEWS b/NEWS index af7656e13..2e4b7cac6 100644 --- a/NEWS +++ b/NEWS @@ -104,6 +104,9 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #4828, geometry_columns handles NOT VALID SRID checks without errors (Darafei Praliaskouski) - #6048, [raster] ST_Clip no longer crashes when clipping sparse band selections (Darafei Praliaskouski) + - GH-894, [raster] Fix Float16 import, mixed nodata warping, + band replacement cleanup, GDAL credential redaction, and Python + GDAL compatibility (Darafei Praliaskouski) - #5645, Docs: keep code operators ("=>") intact in translated manuals by enforcing verbatim CSS (Darafei Praliaskouski) - #5593, Docs: render manual images with GraphicsMagick without temporary files, diff --git a/raster/rt_core/rt_band.c b/raster/rt_core/rt_band.c index 2cbe92ead..0fb95d1f8 100644 --- a/raster/rt_core/rt_band.c +++ b/raster/rt_core/rt_band.c @@ -1080,6 +1080,12 @@ rt_band_set_pixel_line( memcpy(ptr, vals, (size_t)size * len); break; } + case PT_16BF: { + uint16_t *ptr = (uint16_t *) data; + ptr += offset; + memcpy(ptr, vals, (size_t)size * len); + break; + } case PT_32BUI: { uint32_t *ptr = (uint32_t *) data; ptr += offset; diff --git a/raster/rt_core/rt_warp.c b/raster/rt_core/rt_warp.c index f5854fd0f..2cdda3c1e 100644 --- a/raster/rt_core/rt_warp.c +++ b/raster/rt_core/rt_warp.c @@ -30,6 +30,8 @@ #include "../../postgis_config.h" +#include + #include "librtcore.h" #include "librtcore_internal.h" @@ -163,6 +165,9 @@ rt_raster rt_raster_gdal_warp( char *dst_options[] = {"SUBCLASS=VRTWarpedDataset", NULL}; _rti_warp_arg arg = NULL; + int nodata_count = 0; + int has_nodata_count = 0; + GDALRasterBandH band; rt_band rtband = NULL; rt_pixtype pt = PT_END; @@ -179,8 +184,19 @@ rt_raster rt_raster_gdal_warp( int ul_user = 0; rt_raster rast = NULL; + rt_raster nodata_src = NULL; + rt_raster data_src = NULL; + rt_raster nodata_warp = NULL; + rt_raster data_warp = NULL; + rt_raster src = NULL; + uint32_t *nodata_bands = NULL; + uint32_t *data_bands = NULL; + int *group_index = NULL; + int *group_has_nodata = NULL; int i = 0; int numBands = 0; + int nodata_pos = 0; + int data_pos = 0; int subspatial = 0; @@ -188,6 +204,155 @@ rt_raster rt_raster_gdal_warp( assert(NULL != raster); + numBands = rt_raster_get_num_bands(raster); + for (i = 0; i < numBands; i++) + { + rtband = rt_raster_get_band(raster, i); + if (NULL == rtband) + { + rterror("rt_raster_gdal_warp: Could not get band %d for checking nodata state", i); + return NULL; + } + if (rt_band_get_hasnodata_flag(rtband) != FALSE) + has_nodata_count++; + } + + if (has_nodata_count > 0 && has_nodata_count < numBands) + { + nodata_bands = rtalloc(sizeof(uint32_t) * has_nodata_count); + data_bands = rtalloc(sizeof(uint32_t) * (numBands - has_nodata_count)); + group_index = rtalloc(sizeof(int) * numBands); + group_has_nodata = rtalloc(sizeof(int) * numBands); + if (nodata_bands == NULL || data_bands == NULL || group_index == NULL || group_has_nodata == NULL) + { + rterror("rt_raster_gdal_warp: Could not allocate mixed nodata band mapping"); + rtdealloc(nodata_bands); + rtdealloc(data_bands); + rtdealloc(group_index); + rtdealloc(group_has_nodata); + return NULL; + } + + for (i = 0; i < numBands; i++) + { + rtband = rt_raster_get_band(raster, i); + if (rt_band_get_hasnodata_flag(rtband) != FALSE) + { + nodata_bands[nodata_pos] = i; + group_index[i] = nodata_pos++; + group_has_nodata[i] = 1; + } + else + { + data_bands[data_pos] = i; + group_index[i] = data_pos++; + group_has_nodata[i] = 0; + } + } + + nodata_src = rt_raster_from_band(raster, nodata_bands, has_nodata_count); + data_src = rt_raster_from_band(raster, data_bands, numBands - has_nodata_count); + if (nodata_src == NULL || data_src == NULL) + { + rterror("rt_raster_gdal_warp: Could not split mixed nodata raster"); + if (nodata_src != NULL) + rt_raster_destroy(nodata_src); + if (data_src != NULL) + rt_raster_destroy(data_src); + rtdealloc(nodata_bands); + rtdealloc(data_bands); + rtdealloc(group_index); + rtdealloc(group_has_nodata); + return NULL; + } + + nodata_warp = rt_raster_gdal_warp(nodata_src, + src_srs, + dst_srs, + scale_x, + scale_y, + width, + height, + ul_xw, + ul_yw, + grid_xw, + grid_yw, + skew_x, + skew_y, + resample_alg, + max_err); + data_warp = rt_raster_gdal_warp(data_src, + src_srs, + dst_srs, + scale_x, + scale_y, + width, + height, + ul_xw, + ul_yw, + grid_xw, + grid_yw, + skew_x, + skew_y, + resample_alg, + max_err); + rt_raster_destroy(nodata_src); + rt_raster_destroy(data_src); + if (nodata_warp == NULL || data_warp == NULL) + { + rterror("rt_raster_gdal_warp: Could not warp mixed nodata raster groups"); + if (nodata_warp != NULL) + rt_raster_destroy(nodata_warp); + if (data_warp != NULL) + rt_raster_destroy(data_warp); + rtdealloc(nodata_bands); + rtdealloc(data_bands); + rtdealloc(group_index); + rtdealloc(group_has_nodata); + return NULL; + } + + rast = rt_raster_clone(nodata_warp, 0); + if (rast == NULL) + { + rterror("rt_raster_gdal_warp: Could not create mixed nodata output raster"); + rt_raster_destroy(nodata_warp); + rt_raster_destroy(data_warp); + rtdealloc(nodata_bands); + rtdealloc(data_bands); + rtdealloc(group_index); + rtdealloc(group_has_nodata); + return NULL; + } + + for (i = 0; i < numBands; i++) + { + src = group_has_nodata[i] ? nodata_warp : data_warp; + if (rt_raster_copy_band(rast, src, group_index[i], i) < 0) + { + rterror("rt_raster_gdal_warp: Could not merge warped mixed nodata band"); + rt_raster_destroy(rast); + rt_raster_destroy(nodata_warp); + rt_raster_destroy(data_warp); + rtdealloc(nodata_bands); + rtdealloc(data_bands); + rtdealloc(group_index); + rtdealloc(group_has_nodata); + return NULL; + } + } + + rt_raster_destroy(nodata_warp); + rt_raster_destroy(data_warp); + rtdealloc(nodata_bands); + rtdealloc(data_bands); + rtdealloc(group_index); + rtdealloc(group_has_nodata); + + RASTER_DEBUG(3, "rt_raster_gdal_warp: done"); + return rast; + } + arg = _rti_warp_arg_init(); if (arg == NULL) { rterror("rt_raster_gdal_warp: Could not initialize internal variables"); @@ -627,7 +792,6 @@ rt_raster rt_raster_gdal_warp( } /* add bands */ - numBands = rt_raster_get_num_bands(raster); for (i = 0; i < numBands; i++) { rtband = rt_raster_get_band(raster, i); if (NULL == rtband) { @@ -656,6 +820,7 @@ rt_raster rt_raster_gdal_warp( } if (rt_band_get_hasnodata_flag(rtband) != FALSE) { + nodata_count++; rt_band_get_nodata(rtband, &nodata); if (GDALSetRasterNoDataValue(band, nodata) != CE_None) rtwarn("rt_raster_gdal_warp: Could not set nodata value for band %d", i); @@ -700,10 +865,17 @@ rt_raster rt_raster_gdal_warp( arg->wopts->hDstDS = arg->dst.ds; arg->wopts->pfnTransformer = arg->transform.func; arg->wopts->pTransformerArg = arg->transform.arg.transform; - arg->wopts->papszWarpOptions = (char **) CPLMalloc(sizeof(char *) * 2); + arg->wopts->papszWarpOptions = (char **) CPLMalloc(sizeof(char *) * 3); arg->wopts->papszWarpOptions[0] = (char *) CPLMalloc(sizeof(char) * (strlen("INIT_DEST=NO_DATA") + 1)); strcpy(arg->wopts->papszWarpOptions[0], "INIT_DEST=NO_DATA"); - arg->wopts->papszWarpOptions[1] = NULL; +#if POSTGIS_GDAL_VERSION >= 30302 + arg->wopts->papszWarpOptions[1] = (char *) CPLMalloc(sizeof(char) * (strlen("UNIFIED_SRC_NODATA=PARTIAL") + 1)); + strcpy(arg->wopts->papszWarpOptions[1], "UNIFIED_SRC_NODATA=PARTIAL"); +#else + arg->wopts->papszWarpOptions[1] = (char *) CPLMalloc(sizeof(char) * (strlen("UNIFIED_SRC_NODATA=NO") + 1)); + strcpy(arg->wopts->papszWarpOptions[1], "UNIFIED_SRC_NODATA=NO"); +#endif + arg->wopts->papszWarpOptions[2] = NULL; /* band mapping */ arg->wopts->nBandCount = numBands; @@ -712,8 +884,12 @@ rt_raster rt_raster_gdal_warp( for (i = 0; i < arg->wopts->nBandCount; i++) arg->wopts->panDstBands[i] = arg->wopts->panSrcBands[i] = i + 1; - /* nodata mapping */ - { + /* + * When every band declares nodata, pass the explicit vector to GDAL. + * Mixed-band rasters keep their intrinsic per-band nodata metadata; a + * synthetic value for bands without nodata can collide with valid pixels. + */ + if (numBands > 0 && nodata_count == numBands) { arg->wopts->padfSrcNoDataReal = (double *) CPLMalloc(numBands * sizeof(double)); arg->wopts->padfDstNoDataReal = (double *) CPLMalloc(numBands * sizeof(double)); arg->wopts->padfSrcNoDataImag = (double *) CPLMalloc(numBands * sizeof(double)); @@ -735,10 +911,7 @@ rt_raster rt_raster_gdal_warp( _rti_warp_arg_destroy(arg); return NULL; } - if (!rt_band_get_hasnodata_flag(band)) - arg->wopts->padfSrcNoDataReal[i] = -123456.789; - else - rt_band_get_nodata(band, &(arg->wopts->padfSrcNoDataReal[i])); + rt_band_get_nodata(band, &(arg->wopts->padfSrcNoDataReal[i])); arg->wopts->padfDstNoDataReal[i] = arg->wopts->padfSrcNoDataReal[i]; arg->wopts->padfDstNoDataImag[i] = arg->wopts->padfSrcNoDataImag[i] = 0.0; } @@ -775,4 +948,3 @@ rt_raster rt_raster_gdal_warp( return rast; } - diff --git a/raster/rt_pg/rtpg_gdal.c b/raster/rt_pg/rtpg_gdal.c index 09b3f51a1..41f357f8c 100644 --- a/raster/rt_pg/rtpg_gdal.c +++ b/raster/rt_pg/rtpg_gdal.c @@ -38,6 +38,8 @@ #include /* for ArrayType */ #include /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */ #include /* For TopMemoryContext */ +#include +#include #include "../../postgis_config.h" @@ -1115,10 +1117,62 @@ static const char* const gdalErrorTypes[gdalErrorTypesSize] = "AWSSignatureDoesNotMatch" }; +static void +rtpg_gdal_redact_message(char *msg) +{ + static const struct { + const char *text; + bool header_value; + } sensitive[] = {{"access_key=", false}, + {"access_token=", false}, + {"authorization:", true}, + {"cookie:", true}, + {"key=", false}, + {"password=", false}, + {"secret=", false}, + {"sig=", false}, + {"signature=", false}, + {"token=", false}, + {"x-amz-credential=", false}, + {"x-amz-security-token:", true}, + {"x-amz-security-token=", false}}; + char *p; + size_t i; + + for (p = msg; *p; p++) + { + for (i = 0; i < sizeof(sensitive) / sizeof(sensitive[0]); i++) + { + size_t n = strlen(sensitive[i].text); + char *v; + + if (strncasecmp(p, sensitive[i].text, n) != 0) + continue; + + v = p + n; + while (*v && isspace((unsigned char) *v)) + v++; + while (*v && *v != '\r' && *v != '\n' && + (sensitive[i].header_value || + (!isspace((unsigned char)*v) && *v != '&' && *v != ';' && *v != ','))) + { + *v = 'x'; + v++; + } + p = v > p ? v - 1 : p; + break; + } + } +} + static void ogrErrorHandler(CPLErr eErrClass, int err_no, const char* msg) { const char* gdalErrType = "unknown type"; + char *redacted = pstrdup(msg ? msg : ""); + + rtpg_gdal_redact_message(redacted); + if (err_no >= 0 && err_no < gdalErrorTypesSize) { gdalErrType = gdalErrorTypes[err_no]; @@ -1126,20 +1180,21 @@ ogrErrorHandler(CPLErr eErrClass, int err_no, const char* msg) switch (eErrClass) { case CE_None: - elog(NOTICE, "GDAL %s [%d] %s", gdalErrType, err_no, msg); + elog(NOTICE, "GDAL %s [%d] %s", gdalErrType, err_no, redacted); break; case CE_Debug: - elog(DEBUG2, "GDAL %s [%d] %s", gdalErrType, err_no, msg); + elog(DEBUG2, "GDAL %s [%d] %s", gdalErrType, err_no, redacted); break; case CE_Warning: - elog(WARNING, "GDAL %s [%d] %s", gdalErrType, err_no, msg); + elog(WARNING, "GDAL %s [%d] %s", gdalErrType, err_no, redacted); break; case CE_Failure: case CE_Fatal: default: - elog(ERROR, "GDAL %s [%d] %s", gdalErrType, err_no, msg); + elog(ERROR, "GDAL %s [%d] %s", gdalErrType, err_no, redacted); break; } + pfree(redacted); return; } @@ -1152,4 +1207,3 @@ rtpg_gdal_set_cpl_debug(bool value, void *extra) CPLSetErrorHandler(value ? ogrErrorHandler : NULL); CPLSetCurrentErrorHandlerCatchDebug(value); } - diff --git a/raster/rt_pg/rtpg_mapalgebra.c b/raster/rt_pg/rtpg_mapalgebra.c index 865fb3a55..ba34e6323 100644 --- a/raster/rt_pg/rtpg_mapalgebra.c +++ b/raster/rt_pg/rtpg_mapalgebra.c @@ -4139,12 +4139,14 @@ Datum RASTER_reclass_exact(PG_FUNCTION_ARGS) { elog(ERROR, "Band reclassification failed"); /* replace old band with new band */ - if (rt_raster_replace_band(raster, newband, bandnum-1) == NULL) { + band = rt_raster_replace_band(raster, newband, bandnum-1); + if (band == NULL) { rt_band_destroy(newband); rt_raster_destroy(raster); PG_FREE_IF_COPY(pgraster, 0); elog(ERROR, "Could not replace raster band of index %d with reclassified band", bandnum); } + rt_band_destroy(band); pgrtn = rt_raster_serialize(raster); rt_raster_destroy(raster); diff --git a/raster/scripts/python/pixval.py b/raster/scripts/python/pixval.py index 44c953cd0..79ad14c5a 100755 --- a/raster/scripts/python/pixval.py +++ b/raster/scripts/python/pixval.py @@ -31,7 +31,6 @@ import sys def pt2fmt(pt): fmttypes = { gdalc.GDT_Byte: 'B', - gdalc.GDT_Int8: 'B', gdalc.GDT_Int16: 'h', gdalc.GDT_UInt16: 'H', gdalc.GDT_Int32: 'i', @@ -39,6 +38,8 @@ def pt2fmt(pt): gdalc.GDT_Float32: 'f', gdalc.GDT_Float64: 'f' } + if hasattr(gdalc, 'GDT_Int8'): + fmttypes[gdalc.GDT_Int8] = 'b' if hasattr(gdalc, 'GDT_Float16'): fmttypes[gdalc.GDT_Float16] = 'e' return fmttypes.get(pt, 'x') diff --git a/raster/scripts/python/raster2pgsql.py b/raster/scripts/python/raster2pgsql.py index 7d227b413..82423568d 100755 --- a/raster/scripts/python/raster2pgsql.py +++ b/raster/scripts/python/raster2pgsql.py @@ -214,7 +214,6 @@ def gdt2pt(gdt): """Translate GDAL data type to WKT Raster pixel type.""" pixtypes = { gdalc.GDT_Byte : { 'name': 'PT_8BUI', 'id': 4 }, - gdalc.GDT_Int8 : { 'name': 'PT_8BSI', 'id': 3 }, gdalc.GDT_Int16 : { 'name': 'PT_16BSI', 'id': 5 }, gdalc.GDT_UInt16 : { 'name': 'PT_16BUI', 'id': 6 }, gdalc.GDT_Int32 : { 'name': 'PT_32BSI', 'id': 7 }, @@ -223,6 +222,8 @@ def gdt2pt(gdt): gdalc.GDT_Float64 : { 'name': 'PT_64BF', 'id': 11 } } + if hasattr(gdalc, 'GDT_Int8'): + pixtypes[gdalc.GDT_Int8] = { 'name': 'PT_8BSI', 'id': 3 } if hasattr(gdalc, 'GDT_Float16'): pixtypes[gdalc.GDT_Float16] = { 'name': 'PT_16BF', 'id': 9 } @@ -232,6 +233,26 @@ def gdt2pt(gdt): return pixtypes.get(gdt, 13) +def band_is_signed_byte(band): + """Return True for legacy GDAL signed-byte bands exposed as GDT_Byte.""" + + pixel_type = band.GetMetadataItem('PIXELTYPE', 'IMAGE_STRUCTURE') + return band.DataType == gdalc.GDT_Byte and pixel_type is not None and pixel_type.upper() == 'SIGNEDBYTE' + +def band2pt(band): + """Translate a GDAL raster band to WKT Raster pixel type.""" + + if band_is_signed_byte(band): + return { 'name': 'PT_8BSI', 'id': 3 } + return gdt2pt(band.DataType) + +def band2numpy(band): + """Translate a GDAL raster band to NumPy data type.""" + + if band_is_signed_byte(band): + return numpy.int8 + return pt2numpy(band.DataType) + def pt2numpy(pt): """Translate GDAL data type to NumPy data type""" ptnumpy = { @@ -243,6 +264,8 @@ def pt2numpy(pt): gdalc.GDT_Float32: numpy.float32, gdalc.GDT_Float64: numpy.float64 } + if hasattr(gdalc, 'GDT_Int8'): + ptnumpy[gdalc.GDT_Int8] = numpy.int8 if hasattr(gdalc, 'GDT_Float16'): ptnumpy[gdalc.GDT_Float16] = numpy.float16 return ptnumpy.get(pt, numpy.uint8) @@ -250,6 +273,7 @@ def pt2numpy(pt): def pt2fmt(pt): """Returns binary data type specifier for given pixel type.""" fmttypes = { + 3: 'b', # PT_8BSI 4: 'B', # PT_8BUI 5: 'h', # PT_16BSI 6: 'H', # PT_16BUI @@ -265,6 +289,7 @@ def pt2fmt(pt): def fmt2printfmt(fmt): """Returns printf-like formatter for given binary data type specifier.""" fmttypes = { + 'b': '%d', # PT_8BSI 'B': '%d', # PT_8BUI 'h': '%d', # PT_16BSI 'H': '%d', # PT_16BUI @@ -530,7 +555,7 @@ def collect_pixel_types(ds, band_from, band_to): pt =[] for i in range(band_from, band_to): band = ds.GetRasterBand(i) - pixel_type = gdt2pt(band.DataType)['name'][3:] + pixel_type = band2pt(band)['name'][3:] pt.append(pixel_type) return pt @@ -746,7 +771,7 @@ def wkblify_band_header(options, band): nodata = 0 # Encode pixel type - pixtype = gdt2pt(band.DataType)['id'] + pixtype = band2pt(band)['id'] hexwkb += wkblify('B', pixtype + first4bits) # Encode nodata value (or Zero, if nodata unavailable) @@ -805,7 +830,7 @@ def wkblify_band(options, band, level, xoff, yoff, read_block_size, block_size, # XXX: Use for debugging only #dump_block_numpy(pixels) - out_pixels = numpy.zeros((block_size[1], block_size[0]), pt2numpy(band.DataType)) + out_pixels = numpy.zeros((block_size[1], block_size[0]), band2numpy(band)) logit('MSG: Read valid source:\t%d x %d\n' % (len(pixels[0]), len(pixels))) logit('MSG: Write into block:\t%d x %d\n' % (len(out_pixels[0]), len(out_pixels))) diff --git a/raster/test/regress/rt_gdalwarp.sql b/raster/test/regress/rt_gdalwarp.sql index abee24978..ad5b44638 100644 --- a/raster/test/regress/rt_gdalwarp.sql +++ b/raster/test/regress/rt_gdalwarp.sql @@ -887,3 +887,50 @@ SELECT ST_Metadata(ST_Rescale(rast, 2, 2)) AS rescale, ST_Metadata(ST_Resize(rast, 0.5, 0.5)) AS resize FROM foo; + +-- Mixed nodata/no-nodata bands keep declared nodata without treating no-nodata NaN as invalid +WITH src AS ( + SELECT ST_SetValue( + ST_AddBand( + ST_SetValue( + ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, 2, 1, -1, 0, 0, 0), 1, '8BUI', 0, 0), + 1, 1, 1, NULL + ), + 2, '64BF', 'NaN'::float8, NULL + ), + 2, 1, 1, 'NaN'::float8 + ) AS rast +), warped AS ( + SELECT ST_Resample(rast, 4, 4, NULL, NULL, 0, 0, 'NearestNeighbour', 0) AS rast + FROM src +) +SELECT + ST_Value(rast, 1, 1, 1) IS NULL AS nodata_band_preserved, + ST_Value(rast, 1, 1, 1, FALSE) = ST_BandNoDataValue(rast, 1) AS nodata_raw_matches, + ST_Value(rast, 2, 1, 1) IS NULL AS nan_band_visible_value, + ST_Value(rast, 2, 1, 1, FALSE)::text AS nan_band_raw_value, + ST_BandNoDataValue(rast, 2) IS NULL AS nan_band_has_no_nodata +FROM warped; + +WITH base AS ( + SELECT ST_SetValue( + ST_SetValue( + ST_SetValue( + ST_SetValue(ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, 2, 1, -1, 0, 0, 0), 1, '32BF', 0, 0), + 1, 1, 1, NULL), + 1, 2, 1, 100), + 1, 1, 2, 100), + 1, 2, 2, 100) AS rast +), mixed AS ( + SELECT ST_AddBand(rast, 2, '64BF', 'NaN'::float8, NULL) AS rast + FROM base +), warped AS ( + SELECT + ST_Resample((SELECT rast FROM base), 4, 4, NULL, NULL, 0, 0, 'Bilinear', 0) AS single_rast, + ST_Resample(rast, 4, 4, NULL, NULL, 0, 0, 'Bilinear', 0) AS mixed_rast + FROM mixed +) +SELECT + ST_Value(mixed_rast, 1, 2, 1) IS NULL = (ST_Value(single_rast, 1, 2, 1) IS NULL) AS mixed_bilinear_matches, + ST_BandNoDataValue(mixed_rast, 2) IS NULL AS mixed_bilinear_keeps_no_nodata +FROM warped; diff --git a/raster/test/regress/rt_gdalwarp_expected b/raster/test/regress/rt_gdalwarp_expected index d6bc47c1f..9b2137743 100644 --- a/raster/test/regress/rt_gdalwarp_expected +++ b/raster/test/regress/rt_gdalwarp_expected @@ -107,3 +107,5 @@ NOTICE: Raster has default geotransform. Adjusting metadata for use of GDAL War NOTICE: Raster has default geotransform. Adjusting metadata for use of GDAL Warp API NOTICE: Raster has default geotransform. Adjusting metadata for use of GDAL Warp API (0,0,5,5,2,-2,0,0,0,1)|(0,0,5,5,2,-2,0,0,0,1) +t|t|f|NaN|t +t|t ----------------------------------------------------------------------- Summary of changes: NEWS | 3 + raster/rt_core/rt_band.c | 6 + raster/rt_core/rt_warp.c | 192 +++++++++++++++++++++++++++++-- raster/rt_pg/rtpg_gdal.c | 64 ++++++++++- raster/rt_pg/rtpg_mapalgebra.c | 4 +- raster/scripts/python/pixval.py | 3 +- raster/scripts/python/raster2pgsql.py | 33 +++++- raster/test/regress/rt_gdalwarp.sql | 47 ++++++++ raster/test/regress/rt_gdalwarp_expected | 2 + 9 files changed, 333 insertions(+), 21 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Thu Jun 18 15:17:39 2026 From: git at osgeo.org (git at osgeo.org) Date: Thu, 18 Jun 2026 15:17:39 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-619-g6f291bf54 Message-ID: <20260618221740.1208D1A40DD@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 6f291bf547cf9b1834cfa63a779899f6ede4aeba (commit) from 63cbf4f069afebe50cb520b7abe6440c898842e9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6f291bf547cf9b1834cfa63a779899f6ede4aeba Author: Darafei Praliaskouski Date: Thu Jun 18 16:46:37 2026 +0400 Improve point-only GeometryCollection predicate fast paths References #4749 Closes https://github.com/postgis/postgis/pull/966 diff --git a/NEWS b/NEWS index 2e4b7cac6..24b7e37b5 100644 --- a/NEWS +++ b/NEWS @@ -57,6 +57,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed (Sandro Santilli) - #3743, [raster] Document and test raster2pgsql -s FROM_SRID:SRID reprojection support (Darafei Praliaskouski) + - #4749, Use point-in-polygon predicate fast paths for point-only + GeometryCollections (Darafei Praliaskouski) * Bug Fixes * diff --git a/postgis/lwgeom_geos_predicates.c b/postgis/lwgeom_geos_predicates.c index 87d34a694..2a283e17c 100644 --- a/postgis/lwgeom_geos_predicates.c +++ b/postgis/lwgeom_geos_predicates.c @@ -18,13 +18,13 @@ * ********************************************************************** * + * Copyright 2026 Darafei Praliaskouski * Copyright 2009-2014 Sandro Santilli * Copyright 2008 Paul Ramsey * Copyright 2001-2003 Refractions Research Inc. * **********************************************************************/ - #include "../postgis_config.h" /* PostgreSQL */ @@ -73,20 +73,98 @@ is_poly(const GSERIALIZED *g) } /* - * Utility to quickly check for point geometries + * Cheap type gate for geometries that may become point-like. */ static inline uint8_t -is_point(const GSERIALIZED *g) +is_point_or_collection(const GSERIALIZED *g) { int type = gserialized_get_type(g); - return type == POINTTYPE || type == MULTIPOINTTYPE; + return type == POINTTYPE || type == MULTIPOINTTYPE || type == COLLECTIONTYPE; } +/* Avoid homogenizing mixed collections just to discover that PIP cannot use them. */ +static uint8_t +lwgeom_is_pointlike(const LWGEOM *lwgeom) +{ + const LWCOLLECTION *lwcol; + uint32_t i; + if (lwgeom->type == POINTTYPE || lwgeom->type == MULTIPOINTTYPE) + return LW_TRUE; + if (lwgeom->type != COLLECTIONTYPE) + return LW_FALSE; + lwcol = (const LWCOLLECTION *)lwgeom; + if (lwcol->ngeoms == 0) + return LW_FALSE; + for (i = 0; i < lwcol->ngeoms; i++) + { + if (!lwgeom_is_pointlike(lwcol->geoms[i])) + return LW_FALSE; + } + return LW_TRUE; +} + +/* + * Return an owned point/multipoint LWGEOM for direct point inputs or for + * GeometryCollections whose children are all points. + */ +static LWGEOM * +pointlike_lwgeom_from_gserialized(const GSERIALIZED *g) +{ + int type = gserialized_get_type(g); + LWGEOM *lwgeom; + LWGEOM *hgeom; + + if (type == POINTTYPE || type == MULTIPOINTTYPE) + return lwgeom_from_gserialized(g); + + if (type != COLLECTIONTYPE) + return NULL; + + lwgeom = lwgeom_from_gserialized(g); + if (!lwgeom_is_pointlike(lwgeom)) + { + lwgeom_free(lwgeom); + return NULL; + } + + hgeom = lwgeom_homogenize(lwgeom); + lwgeom_free(lwgeom); + + if (!hgeom) + return NULL; + + if (hgeom->type == POINTTYPE || hgeom->type == MULTIPOINTTYPE) + return hgeom; + + lwgeom_free(hgeom); + return NULL; +} + +typedef bool (*itree_pip_predicate)(const IntervalTree *itree, const LWGEOM *lwpoints); + +static bool +try_itree_pointlike_pip(FunctionCallInfo fcinfo, + const GSERIALIZED *gpoints, + SHARED_GSERIALIZED *shared_gpoly, + itree_pip_predicate predicate, + bool *result) +{ + LWGEOM *lwpt = pointlike_lwgeom_from_gserialized(gpoints); + IntervalTree *itree; + + if (!lwpt) + return false; + + itree = GetIntervalTree(fcinfo, shared_gpoly); + *result = predicate(itree, lwpt); + lwgeom_free(lwpt); + return true; +} PG_FUNCTION_INFO_V1(ST_Intersects); Datum ST_Intersects(PG_FUNCTION_ARGS) @@ -98,6 +176,7 @@ Datum ST_Intersects(PG_FUNCTION_ARGS) int8_t result; GBOX box1, box2; PrepGeomCache *prep_cache; + bool pip_result; gserialized_error_if_srid_mismatch(geom1, geom2, __func__); @@ -117,20 +196,18 @@ Datum ST_Intersects(PG_FUNCTION_ARGS) } /* - * Short-circuit 2: if the geoms are a point and a polygon, - * call the itree_pip_intersects function. + * Short-circuit 2: if one geometry is polygonal and the other is a + * point or point-only collection, use the IntervalTree PIP fast path. */ - if ((is_point(geom1) && is_poly(geom2)) || - (is_point(geom2) && is_poly(geom1))) + if (is_point_or_collection(geom1) && is_poly(geom2) && + try_itree_pointlike_pip(fcinfo, geom1, shared_geom2, itree_pip_intersects, &pip_result)) { - SHARED_GSERIALIZED *shared_gpoly = is_poly(geom1) ? shared_geom1 : shared_geom2; - SHARED_GSERIALIZED *shared_gpoint = is_point(geom1) ? shared_geom1 : shared_geom2; - const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint); - LWGEOM *lwpt = lwgeom_from_gserialized(gpoint); - IntervalTree *itree = GetIntervalTree(fcinfo, shared_gpoly); - bool result = itree_pip_intersects(itree, lwpt); - lwgeom_free(lwpt); - PG_RETURN_BOOL(result); + PG_RETURN_BOOL(pip_result); + } + else if (is_point_or_collection(geom2) && is_poly(geom1) && + try_itree_pointlike_pip(fcinfo, geom2, shared_geom1, itree_pip_intersects, &pip_result)) + { + PG_RETURN_BOOL(pip_result); } initGEOS(lwpgnotice, lwgeom_geos_error); @@ -504,6 +581,7 @@ Datum contains(PG_FUNCTION_ARGS) GEOSGeometry *g1, *g2; GBOX box1, box2; PrepGeomCache *prep_cache; + bool pip_result; gserialized_error_if_srid_mismatch(geom1, geom2, __func__); @@ -525,17 +603,13 @@ Datum contains(PG_FUNCTION_ARGS) } /* - ** Short-circuit 2: if geom2 is a point and geom1 is a polygon - ** call the point-in-polygon function. + ** Short-circuit 2: if geom1 is polygonal and geom2 is a point + ** or point-only collection, use the IntervalTree PIP fast path. */ - if (is_poly(geom1) && is_point(geom2)) + if (is_poly(geom1) && is_point_or_collection(geom2) && + try_itree_pointlike_pip(fcinfo, geom2, shared_geom1, itree_pip_contains, &pip_result)) { - const GSERIALIZED *gpoint = shared_gserialized_get(shared_geom2); - LWGEOM *lwpt = lwgeom_from_gserialized(gpoint); - IntervalTree *itree = GetIntervalTree(fcinfo, shared_geom1); - bool result = itree_pip_contains(itree, lwpt); - lwgeom_free(lwpt); - PG_RETURN_BOOL(result); + PG_RETURN_BOOL(pip_result); } initGEOS(lwpgnotice, lwgeom_geos_error); @@ -585,6 +659,7 @@ Datum within(PG_FUNCTION_ARGS) GEOSGeometry *g1, *g2; GBOX box1, box2; PrepGeomCache *prep_cache; + bool pip_result; gserialized_error_if_srid_mismatch(geom1, geom2, __func__); @@ -606,17 +681,13 @@ Datum within(PG_FUNCTION_ARGS) } /* - ** Short-circuit 2: if geom2 is a polygon and geom1 is a point - ** call the point-in-polygon function. + ** Short-circuit 2: if geom2 is polygonal and geom1 is a point + ** or point-only collection, use the IntervalTree PIP fast path. */ - if (is_poly(geom2) && is_point(geom1)) + if (is_poly(geom2) && is_point_or_collection(geom1) && + try_itree_pointlike_pip(fcinfo, geom1, shared_geom2, itree_pip_contains, &pip_result)) { - const GSERIALIZED *gpoint = shared_gserialized_get(shared_geom1); - LWGEOM *lwpt = lwgeom_from_gserialized(gpoint); - IntervalTree *itree = GetIntervalTree(fcinfo, shared_geom2); - bool result = itree_pip_contains(itree, lwpt); - lwgeom_free(lwpt); - PG_RETURN_BOOL(result); + PG_RETURN_BOOL(pip_result); } initGEOS(lwpgnotice, lwgeom_geos_error); @@ -729,6 +800,7 @@ Datum covers(PG_FUNCTION_ARGS) int8_t result; GBOX box1, box2; PrepGeomCache *prep_cache; + bool pip_result; POSTGIS_DEBUGF(3, "Covers: type1: %d, type2: %d", gserialized_get_type(geom1), gserialized_get_type(geom2)); @@ -751,17 +823,13 @@ Datum covers(PG_FUNCTION_ARGS) } } /* - * Short-circuit 2: if geom2 is a point and geom1 is a polygon - * call the point-in-polygon function. + * Short-circuit 2: if geom1 is polygonal and geom2 is a point + * or point-only collection, use the IntervalTree PIP fast path. */ - if (is_poly(geom1) && is_point(geom2)) + if (is_poly(geom1) && is_point_or_collection(geom2) && + try_itree_pointlike_pip(fcinfo, geom2, shared_geom1, itree_pip_covers, &pip_result)) { - const GSERIALIZED *gpoint = shared_gserialized_get(shared_geom2); - LWGEOM *lwpt = lwgeom_from_gserialized(gpoint); - IntervalTree *itree = GetIntervalTree(fcinfo, shared_geom1); - bool result = itree_pip_covers(itree, lwpt); - lwgeom_free(lwpt); - PG_RETURN_BOOL(result); + PG_RETURN_BOOL(pip_result); } initGEOS(lwpgnotice, lwgeom_geos_error); @@ -813,6 +881,7 @@ Datum coveredby(PG_FUNCTION_ARGS) int8_t result; GBOX box1, box2; PrepGeomCache *prep_cache; + bool pip_result; gserialized_error_if_srid_mismatch(geom1, geom2, __func__); @@ -835,17 +904,13 @@ Datum coveredby(PG_FUNCTION_ARGS) } } /* - * Short-circuit 2: if geom1 is a point and geom2 is a polygon - * call the point-in-polygon function. + * Short-circuit 2: if geom2 is polygonal and geom1 is a point + * or point-only collection, use the IntervalTree PIP fast path. */ - if (is_point(geom1) && is_poly(geom2)) + if (is_point_or_collection(geom1) && is_poly(geom2) && + try_itree_pointlike_pip(fcinfo, geom1, shared_geom2, itree_pip_covers, &pip_result)) { - const GSERIALIZED *gpoint = shared_gserialized_get(shared_geom1); - IntervalTree *itree = GetIntervalTree(fcinfo, shared_geom2); - LWGEOM *lwpt = lwgeom_from_gserialized(gpoint); - bool result = itree_pip_covers(itree, lwpt); - lwgeom_free(lwpt); - PG_RETURN_BOOL(result); + PG_RETURN_BOOL(pip_result); } initGEOS(lwpgnotice, lwgeom_geos_error); diff --git a/regress/core/tickets.sql b/regress/core/tickets.sql index 3e0533a76..413a1b9f1 100644 --- a/regress/core/tickets.sql +++ b/regress/core/tickets.sql @@ -1243,6 +1243,72 @@ SELECT 'equals212', ST_equals('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry SELECT 'equals213', ST_equals('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'::geometry, 'GEOMETRYCOLLECTION (POLYGON((0 0, 10 0, 10 10, 0 10, 0 0)),MULTIPOINT(0 2, 5 5))'::geometry); +-- #4749 point-only GeometryCollections in polygon predicates use the PIP path +WITH g AS ( + SELECT + 'POLYGON((0 0,0 10,10 10,10 0,0 0))'::geometry AS poly, + 'GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(5 5)),MULTIPOINT((7 7),(8 8)))'::geometry AS pts_inside, + 'GEOMETRYCOLLECTION(POINT(5 5),POINT(0 0))'::geometry AS pts_boundary, + 'GEOMETRYCOLLECTION(POINT(5 5),POINT(11 11))'::geometry AS pts_outside +) +SELECT '#4749.contains', + ST_Contains(poly, pts_inside), + ST_Contains(poly, pts_boundary), + ST_Contains(poly, pts_outside) +FROM g; + +WITH g AS ( + SELECT + 'POLYGON((0 0,0 10,10 10,10 0,0 0))'::geometry AS poly, + 'GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(5 5)),MULTIPOINT((7 7),(8 8)))'::geometry AS pts_inside, + 'GEOMETRYCOLLECTION(POINT(5 5),POINT(0 0))'::geometry AS pts_boundary, + 'GEOMETRYCOLLECTION(POINT(5 5),POINT(11 11))'::geometry AS pts_outside +) +SELECT '#4749.within', + ST_Within(pts_inside, poly), + ST_Within(pts_boundary, poly), + ST_Within(pts_outside, poly) +FROM g; + +WITH g AS ( + SELECT + 'POLYGON((0 0,0 10,10 10,10 0,0 0))'::geometry AS poly, + 'GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(5 5)),MULTIPOINT((7 7),(8 8)))'::geometry AS pts_inside, + 'GEOMETRYCOLLECTION(POINT(5 5),POINT(0 0))'::geometry AS pts_boundary, + 'GEOMETRYCOLLECTION(POINT(5 5),POINT(11 11))'::geometry AS pts_outside +) +SELECT '#4749.covers', + ST_Covers(poly, pts_inside), + ST_Covers(poly, pts_boundary), + ST_Covers(poly, pts_outside) +FROM g; + +WITH g AS ( + SELECT + 'POLYGON((0 0,0 10,10 10,10 0,0 0))'::geometry AS poly, + 'GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(5 5)),MULTIPOINT((7 7),(8 8)))'::geometry AS pts_inside, + 'GEOMETRYCOLLECTION(POINT(5 5),POINT(0 0))'::geometry AS pts_boundary, + 'GEOMETRYCOLLECTION(POINT(5 5),POINT(11 11))'::geometry AS pts_outside +) +SELECT '#4749.coveredby', + ST_CoveredBy(pts_inside, poly), + ST_CoveredBy(pts_boundary, poly), + ST_CoveredBy(pts_outside, poly) +FROM g; + +WITH g AS ( + SELECT + 'POLYGON((0 0,0 10,10 10,10 0,0 0))'::geometry AS poly, + 'GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(5 5)),MULTIPOINT((7 7),(8 8)))'::geometry AS pts_inside, + 'GEOMETRYCOLLECTION(POINT(5 5),POINT(0 0))'::geometry AS pts_boundary, + 'GEOMETRYCOLLECTION(POINT(5 5),POINT(11 11))'::geometry AS pts_outside +) +SELECT '#4749.intersects', + ST_Intersects(poly, pts_inside), + ST_Intersects(pts_boundary, poly), + ST_Intersects(poly, pts_outside) +FROM g; + -- #4299 SELECT '#4299', ST_Disjoint(ST_GeneratePoints(g, 1000), ST_GeneratePoints(g, 1000)) FROM (SELECT 'POLYGON((0 0,1 0,1 1,0 1,0 0))'::geometry AS g) AS f; diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected index 9c3451edd..dc67b09d2 100644 --- a/regress/core/tickets_expected +++ b/regress/core/tickets_expected @@ -383,6 +383,11 @@ equals210|t equals211|t equals212|t equals213|t +#4749.contains|t|t|f +#4749.within|t|t|f +#4749.covers|t|t|f +#4749.coveredby|t|t|f +#4749.intersects|t|t|t #4299|t #4304|t|t|t ERROR: BOX3D_construct: args can not be empty points ----------------------------------------------------------------------- Summary of changes: NEWS | 2 + postgis/lwgeom_geos_predicates.c | 169 +++++++++++++++++++++++++++------------ regress/core/tickets.sql | 66 +++++++++++++++ regress/core/tickets_expected | 5 ++ 4 files changed, 190 insertions(+), 52 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Thu Jun 18 15:17:42 2026 From: trac at osgeo.org (PostGIS) Date: Thu, 18 Jun 2026 22:17:42 -0000 Subject: [PostGIS] #4749: Improve behaviour of spatial predicates with GeometryCollection inputs In-Reply-To: <048.8616200a28b49441d2b561ae439bfc30@osgeo.org> References: <048.8616200a28b49441d2b561ae439bfc30@osgeo.org> Message-ID: <063.e62b62a97ad4e5c50f42c8904dd7eda5@osgeo.org> #4749: Improve behaviour of spatial predicates with GeometryCollection inputs --------------------------+----------------------------- Reporter: mdavis | Owner: pramsey Type: enhancement | Status: new Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: 2.5.x -- EOL Resolution: | Keywords: --------------------------+----------------------------- Comment (by Darafei Praliaskouski ): In [changeset:"6f291bf547cf9b1834cfa63a779899f6ede4aeba/git" 6f291bf/git]: {{{#!CommitTicketReference repository="git" revision="6f291bf547cf9b1834cfa63a779899f6ede4aeba" Improve point-only GeometryCollection predicate fast paths References #4749 Closes https://github.com/postgis/postgis/pull/966 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 18 22:47:18 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 19 Jun 2026 05:47:18 -0000 Subject: [PostGIS] #6083: Compile error on fuzzing engine on winnie Message-ID: <046.e3a9d81a975b8554135ee3d780854eeb@osgeo.org> #6083: Compile error on fuzzing engine on winnie ---------------------+--------------------------- Reporter: robe | Owner: komzpa Type: defect | Status: assigned Priority: blocker | Milestone: PostGIS 3.7.0 Component: postgis | Version: 3.6.x Keywords: | ---------------------+--------------------------- I thought it was just woodie getting compile failures on fuzzingengine. But it's winnie as well. Output from winnie which started erroring at [746769bc/git] This as of [6f291bf547/git] {{{ mkdir -p "/projects/postgis/tmp/3.7.0dev_pg19_geos3.15_gdal3.9.2w64 /postgis-fuzzer-check.bG7HYY" ar r libFuzzingEngine.a fuzzingengine.o C:\ming64\mingw64\bin\ar.exe: creating libFuzzingEngine.a CC="cc" CXX="g++" CXXFLAGS="-L/projects/postgis/branches/3.7/fuzzers " LDFLAGS="-Wl,--enable-auto-import -L/projects/postgresql/rel/pg19w64/lib -L/projects/lz4/rel-lz4-1.9.3w64/lib -L/projects/rel-libiconv-1.17w64/lib -L/projects/zlib/rel-zlib-1.2.13w64/lib -lm -LE:/jenkins/geos/rel-3.15w64/lib -lgeos_c -LE:/jenkins/proj/rel- proj-8.2.1w64/lib -lproj -LE:/jenkins/json-c/rel-0.16w64/lib -ljson-c " POSTGIS_BUILD_DIR="/projects/postgis/branches/3.7" SRC="/projects/postgis/branches/3.7/fuzzers" OUT="/projects/postgis/tmp/3.7.0dev_pg19_geos3.15_gdal3.9.2w64/postgis- fuzzer-check.bG7HYY" /projects/postgis/branches/3.7/fuzzers/build_google_oss_fuzzers.sh Building fuzzer geojson_import_fuzzer In file included from E:/jenkins/postgis/branches/3.7/fuzzers/geojson_import_fuzzer.cpp:37: E:/jenkins/postgis/branches/3.7/liblwgeom/liblwgeom.h:39:10: fatal error: proj.h: No such file or directory 39 | #include "proj.h" | ^~~~~~~~ compilation terminated. make[2]: *** [Makefile:22: dummyfuzzers] Error 1 make[2]: Leaving directory '/projects/postgis/branches/3.7/fuzzers' make[1]: *** [/projects/postgis/branches/3.7/fuzzers/Makefile:26: check] Error 2 make[1]: Leaving directory '/projects/postgis/branches/3.7/fuzzers' make: *** [GNUmakefile:104: check-fuzzers] Error 2 }}} Woodie seems fixed now as of [965711/git] but winnie is still broken. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 18 22:47:28 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 19 Jun 2026 05:47:28 -0000 Subject: [PostGIS] #6083: Compile error on fuzzing engine on winnie In-Reply-To: <046.e3a9d81a975b8554135ee3d780854eeb@osgeo.org> References: <046.e3a9d81a975b8554135ee3d780854eeb@osgeo.org> Message-ID: <061.1be17064cf1d73462a14040f623229e3@osgeo.org> #6083: Compile error on fuzzing engine on winnie ----------------------+--------------------------- Reporter: robe | Owner: komzpa Type: defect | Status: assigned Priority: blocker | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: | Keywords: ----------------------+--------------------------- Changes (by robe): * version: 3.6.x => master -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Thu Jun 18 22:52:45 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 19 Jun 2026 05:52:45 -0000 Subject: [PostGIS] #6083: Compile error on fuzzing engine on winnie In-Reply-To: <046.e3a9d81a975b8554135ee3d780854eeb@osgeo.org> References: <046.e3a9d81a975b8554135ee3d780854eeb@osgeo.org> Message-ID: <061.9fd54d91cd3b31bcaf56414f780d86e1@osgeo.org> #6083: Compile error on fuzzing engine on winnie ----------------------+--------------------------- Reporter: robe | Owner: komzpa Type: defect | Status: assigned Priority: blocker | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: | Keywords: ----------------------+--------------------------- Comment (by robe): Not sure if related but did get emails from google about fuzzies a couple of hours ago. postgis:wkb_import_fuzzer: Out-of-memory in wkb_import_fuzzer postgis:twkb_import_fuzzer: Stack-overflow in lwgeom_from_twkb_state postgis:twkb_import_fuzzer: Integer-overflow in ptarray_from_twkb_state -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Fri Jun 19 00:37:42 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 19 Jun 2026 00:37:42 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-620-gb8c7b0142 Message-ID: <20260619073742.97D1B1A98F2@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via b8c7b014233d32d61b75dee622fc76c215949427 (commit) from 6f291bf547cf9b1834cfa63a779899f6ede4aeba (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b8c7b014233d32d61b75dee622fc76c215949427 Author: Darafei Praliaskouski Date: Fri Jun 19 10:49:37 2026 +0400 fuzzers: pass configured include paths to smoke builds The standalone fuzzer smoke build compiles liblwgeom headers outside the liblwgeom Makefile, so it also needs the dependency include paths discovered by configure. Reuse the configured CPPFLAGS while dropping liblwgeom-local Make variables that are only valid inside that directory. Closes #6083 Closes https://github.com/postgis/postgis/pull/984 diff --git a/NEWS b/NEWS index 24b7e37b5..080ac74fd 100644 --- a/NEWS +++ b/NEWS @@ -62,6 +62,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Bug Fixes * + - #6083, Pass configured dependency include paths to fuzzer smoke builds + (Darafei Praliaskouski) - #3103, Add regression coverage for exact-schema find_srid and geometry_columns lookups (Darafei Praliaskouski) - #5655, [doc] Skip XML validation during `make check` when xsltproc is diff --git a/fuzzers/Makefile b/fuzzers/Makefile index 51c4ed5e2..ebe7077e2 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -6,7 +6,11 @@ FUZZER_WORK ?= $(FUZZER_OUT)/postgis-fuzzer-check FUZZER_SOURCES := $(notdir $(wildcard $(FUZZER_SRC_DIR)/*_fuzzer.cpp $(FUZZER_SRC_DIR)/*_fuzzer.c)) FUZZER_NAMES := $(basename $(FUZZER_SOURCES)) SEED_CORPORA := $(wildcard $(FUZZER_SRC_DIR)/*_seed_corpus.zip) +# The standalone fuzzer smoke build includes liblwgeom.h outside liblwgeom's +# Makefile, so it must inherit the configured dependency include paths. +POSTGIS_CONFIGURED_CPPFLAGS := $(shell sed -n 's/^CPPFLAGS = //p' $(POSTGIS_BUILD_DIR)/liblwgeom/Makefile 2>/dev/null | sed 's/$$(RYU_INCLUDE)//g; s/-I$$(builddir)//g; s/-I$$(srcdir)//g' | sed 1q) POSTGIS_CONFIGURED_LDFLAGS := $(shell sed -n 's/^LDFLAGS = //p' $(POSTGIS_BUILD_DIR)/liblwgeom/Makefile 2>/dev/null | sed 1q) +POSTGIS_FUZZER_CPPFLAGS = $(POSTGIS_CONFIGURED_CPPFLAGS) $(CPPFLAGS) POSTGIS_FUZZER_LDFLAGS = $(POSTGIS_CONFIGURED_LDFLAGS) $(LDFLAGS) .PHONY: clean dummyfuzzers check check-corpus @@ -20,7 +24,7 @@ fuzzingengine.o: $(FUZZER_SRC_DIR)/fuzzingengine.c dummyfuzzers: fuzzingengine.o mkdir -p "$(FUZZER_OUT)" $(AR) r libFuzzingEngine.a fuzzingengine.o - CC="${CC}" CXX="${CXX}" CXXFLAGS="-L$(CURDIR) ${CXXFLAGS}" LDFLAGS="$(POSTGIS_FUZZER_LDFLAGS)" POSTGIS_BUILD_DIR="$(POSTGIS_BUILD_DIR)" SRC="$(FUZZER_SRC_DIR)" OUT="$(FUZZER_OUT)" $(FUZZER_SRC_DIR)/build_google_oss_fuzzers.sh + CC="${CC}" CXX="${CXX}" CPPFLAGS="$(POSTGIS_FUZZER_CPPFLAGS)" CXXFLAGS="-L$(CURDIR) ${CXXFLAGS}" LDFLAGS="$(POSTGIS_FUZZER_LDFLAGS)" POSTGIS_BUILD_DIR="$(POSTGIS_BUILD_DIR)" SRC="$(FUZZER_SRC_DIR)" OUT="$(FUZZER_OUT)" $(FUZZER_SRC_DIR)/build_google_oss_fuzzers.sh OUT="$(FUZZER_OUT)" $(FUZZER_SRC_DIR)/build_seed_corpus.sh check: diff --git a/fuzzers/build_google_oss_fuzzers.sh b/fuzzers/build_google_oss_fuzzers.sh index 1cc825413..b4161bd69 100755 --- a/fuzzers/build_google_oss_fuzzers.sh +++ b/fuzzers/build_google_oss_fuzzers.sh @@ -33,11 +33,20 @@ GDAL_LIBS=$(gdal-config --libs) POSTGIS_FUZZER_LIBS="$JSON_C_LIBS $GEOS_LIBS $PROJ_XML2_LIBS" POSTGIS_PACKAGE_RUNTIME_LIBS="${POSTGIS_PACKAGE_RUNTIME_LIBS:-1}" +target_local_cflags() +{ + case "$1" in + raster_deserialize_fuzzer) + echo "-I$POSTGIS_SOURCE_DIR/raster/rt_core -I$POSTGIS_BUILD_DIR/raster/rt_core -I$POSTGIS_SOURCE_DIR/raster -I$POSTGIS_BUILD_DIR/raster -I$POSTGIS_SOURCE_DIR -I$POSTGIS_BUILD_DIR" + ;; + esac +} + target_cflags() { case "$1" in raster_deserialize_fuzzer) - echo "-I$POSTGIS_SOURCE_DIR/raster/rt_core -I$POSTGIS_BUILD_DIR/raster/rt_core -I$POSTGIS_SOURCE_DIR/raster -I$POSTGIS_BUILD_DIR/raster -I$POSTGIS_SOURCE_DIR -I$POSTGIS_BUILD_DIR $GDAL_CFLAGS" + echo "$GDAL_CFLAGS" ;; esac } @@ -62,12 +71,12 @@ build_fuzzer() if [ "$extension" = "c" ]; then objectFile=$(mktemp) - "$CC" $CFLAGS -I"$POSTGIS_SOURCE_DIR/liblwgeom" -I"$POSTGIS_BUILD_DIR/liblwgeom" $(target_cflags "$fuzzerName") \ + "$CC" $CFLAGS -I"$POSTGIS_SOURCE_DIR/liblwgeom" -I"$POSTGIS_BUILD_DIR/liblwgeom" $(target_local_cflags "$fuzzerName") $CPPFLAGS $(target_cflags "$fuzzerName") \ -c "$sourceFilename" -o "$objectFile" sourceFilename=$objectFile fi - "$CXX" $CXXFLAGS -std=c++11 -I"$POSTGIS_SOURCE_DIR/liblwgeom" -I"$POSTGIS_BUILD_DIR/liblwgeom" \ + "$CXX" $CXXFLAGS -std=c++11 -I"$POSTGIS_SOURCE_DIR/liblwgeom" -I"$POSTGIS_BUILD_DIR/liblwgeom" $CPPFLAGS \ "$sourceFilename" -o "$OUT/$fuzzerName" \ $LDFLAGS \ -lFuzzingEngine -lstdc++ $(target_libs "$fuzzerName") \ ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ fuzzers/Makefile | 6 +++++- fuzzers/build_google_oss_fuzzers.sh | 15 ++++++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Fri Jun 19 00:37:44 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 19 Jun 2026 07:37:44 -0000 Subject: [PostGIS] #6083: Compile error on fuzzing engine on winnie In-Reply-To: <046.e3a9d81a975b8554135ee3d780854eeb@osgeo.org> References: <046.e3a9d81a975b8554135ee3d780854eeb@osgeo.org> Message-ID: <061.3085cd53a5ea7b737ec21a6b94683770@osgeo.org> #6083: Compile error on fuzzing engine on winnie ----------------------+--------------------------- Reporter: robe | Owner: komzpa Type: defect | Status: closed Priority: blocker | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: assigned => closed Comment: In [changeset:"b8c7b014233d32d61b75dee622fc76c215949427/git" b8c7b014/git]: {{{#!CommitTicketReference repository="git" revision="b8c7b014233d32d61b75dee622fc76c215949427" fuzzers: pass configured include paths to smoke builds The standalone fuzzer smoke build compiles liblwgeom headers outside the liblwgeom Makefile, so it also needs the dependency include paths discovered by configure. Reuse the configured CPPFLAGS while dropping liblwgeom-local Make variables that are only valid inside that directory. Closes #6083 Closes https://github.com/postgis/postgis/pull/984 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Fri Jun 19 11:58:11 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 19 Jun 2026 11:58:11 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-621-g09b3ea63d Message-ID: <20260619185812.30F4A1B4552@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 09b3ea63d5ac7db56787588c618cb7d4149f95a2 (commit) from b8c7b014233d32d61b75dee622fc76c215949427 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 09b3ea63d5ac7db56787588c618cb7d4149f95a2 Author: Darafei Praliaskouski Date: Fri Jun 19 22:56:27 2026 +0400 liblwgeom: harden malformed WKB and TWKB parsing Bound recursive TWKB collection descent to match the WKB parser, reject TWKB delta-coordinate accumulation that would overflow int64_t, and reject malformed WKB NURBSCURVE control-point counts before allocating point and weight arrays. References https://oss-fuzz.com/testcase-detail/5121296892231680 References https://oss-fuzz.com/testcase-detail/4803520482836480 References https://oss-fuzz.com/testcase-detail/5155658945855488 Closes https://github.com/postgis/postgis/pull/985 diff --git a/NEWS b/NEWS index 080ac74fd..0788a58d2 100644 --- a/NEWS +++ b/NEWS @@ -62,6 +62,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Bug Fixes * + - Fix WKB and TWKB parser resource exhaustion on malformed input + (Darafei Praliaskouski) - #6083, Pass configured dependency include paths to fuzzer smoke builds (Darafei Praliaskouski) - #3103, Add regression coverage for exact-schema find_srid and diff --git a/liblwgeom/cunit/cu_in_twkb.c b/liblwgeom/cunit/cu_in_twkb.c index 5fb4197f0..71c38585d 100644 --- a/liblwgeom/cunit/cu_in_twkb.c +++ b/liblwgeom/cunit/cu_in_twkb.c @@ -13,10 +13,12 @@ #include #include #include +#include #include "CUnit/Basic.h" #include "liblwgeom_internal.h" #include "cu_tester.h" +#include "varint.h" /* ** Global variable to hold TWKB strings @@ -306,6 +308,82 @@ test_twkb_in_count_exceeds_payload(void) cu_error_msg_reset(); } +static void +test_twkb_in_deep_collection(void) +{ + const size_t ngeoms = 201; + const size_t twkb_size = ngeoms * 3 + 2; + uint8_t *twkb = lwalloc(twkb_size); + LWGEOM *geom; + size_t i; + + for (i = 0; i < ngeoms; i++) + { + /* GEOMETRYCOLLECTION with default precision and one child. */ + twkb[3 * i] = 0x07; + twkb[3 * i + 1] = 0x00; + twkb[3 * i + 2] = 0x01; + } + twkb[3 * ngeoms] = 0x01; /* POINT with default precision. */ + twkb[3 * ngeoms + 1] = 0x10; /* Empty geometry. */ + + cu_error_msg_reset(); + + geom = lwgeom_from_twkb(twkb, twkb_size, LW_PARSER_CHECK_NONE); + + /* Recursive collection parsing must reject hostile nesting before the C + * stack becomes the effective input validator. + */ + ASSERT_STRING_EQUAL(cu_error_msg, "Geometry has too many chained collections"); + CU_ASSERT_PTR_NULL(geom); + lwfree(twkb); + cu_error_msg_reset(); +} + +static void +test_twkb_in_coordinate_overflow(void) +{ + const uint8_t twkb[] = {0x03, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x2f, 0x00, 0x00, 0x3d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x23, 0x06, 0x02, 0x7e, 0x84, + 0x83, 0x84, 0x84, 0x84, 0x84, 0xae, 0xee, 0xff, 0x01, 0xf9, 0xff, 0xff, 0xff, + 0xff, 0xef, 0x16, 0x16, 0xff, 0x16, 0x16, 0x16, 0x23, 0x06, 0x02, 0x7e, 0x84, + 0x83, 0x84, 0x84, 0x84, 0x84, 0xae, 0xee, 0xff, 0x01, 0xf9, 0xff, 0xff, 0xff, + 0xff, 0xef, 0xff, 0xff, 0x01, 0xff, 0x02, 0x00, 0x79, 0xb0}; + LWGEOM *geom; + + cu_error_msg_reset(); + + geom = lwgeom_from_twkb(twkb, sizeof(twkb), LW_PARSER_CHECK_NONE); + + /* Delta-encoded coordinates must not rely on signed integer overflow to + * wrap hostile inputs into the int64_t accumulator range. + */ + ASSERT_STRING_EQUAL(cu_error_msg, "twkb_parse_state_accum_coord: TWKB coordinate delta overflows int64_t"); + CU_ASSERT_PTR_NULL(geom); + cu_error_msg_reset(); +} + +static void +test_twkb_in_linestring_coordinate_overflow(void) +{ + uint8_t twkb[64] = {0x02, 0x00, 0x02}; + uint8_t *pos = twkb + 3; + LWGEOM *geom; + + pos += varint_s64_encode_buf(INT64_MAX, pos); + pos += varint_s64_encode_buf(0, pos); + pos += varint_s64_encode_buf(1, pos); + pos += varint_s64_encode_buf(0, pos); + + cu_error_msg_reset(); + + geom = lwgeom_from_twkb(twkb, (size_t)(pos - twkb), LW_PARSER_CHECK_NONE); + + ASSERT_STRING_EQUAL(cu_error_msg, "twkb_parse_state_accum_coord: TWKB coordinate delta overflows int64_t"); + CU_ASSERT_PTR_NULL(geom); + cu_error_msg_reset(); +} + /* ** Used by test harness to register the tests in this file. */ @@ -324,4 +402,7 @@ void twkb_in_suite_setup(void) PG_ADD_TEST(suite, test_twkb_in_truncated_extended_dims); PG_ADD_TEST(suite, test_twkb_in_overlong_varint); PG_ADD_TEST(suite, test_twkb_in_count_exceeds_payload); + PG_ADD_TEST(suite, test_twkb_in_deep_collection); + PG_ADD_TEST(suite, test_twkb_in_coordinate_overflow); + PG_ADD_TEST(suite, test_twkb_in_linestring_coordinate_overflow); } diff --git a/liblwgeom/cunit/cu_in_wkb.c b/liblwgeom/cunit/cu_in_wkb.c index c855dccf3..2b9066ae8 100644 --- a/liblwgeom/cunit/cu_in_wkb.c +++ b/liblwgeom/cunit/cu_in_wkb.c @@ -283,6 +283,22 @@ test_wkb_fuzz(void) lwfree(wkb5); } +static void +test_wkb_in_nurbscurve_count_exceeds_payload(void) +{ + const uint8_t wkb[] = { + 0x01, 0x15, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0xc4, 0x0c, 0xb7, 0x07, 0x21, 0xc7}; + LWGEOM *geom; + + cu_error_msg_reset(); + + geom = lwgeom_from_wkb(wkb, sizeof(wkb), LW_PARSER_CHECK_NONE); + + ASSERT_STRING_EQUAL(cu_error_msg, "WKB structure does not match expected size!"); + CU_ASSERT_PTR_NULL(geom); + cu_error_msg_reset(); +} + /* ** Used by test harness to register the tests in this file. */ @@ -304,4 +320,5 @@ void wkb_in_suite_setup(void) PG_ADD_TEST(suite, test_wkb_in_multisurface); PG_ADD_TEST(suite, test_wkb_in_malformed); PG_ADD_TEST(suite, test_wkb_fuzz); + PG_ADD_TEST(suite, test_wkb_in_nurbscurve_count_exceeds_payload); } diff --git a/liblwgeom/lwin_twkb.c b/liblwgeom/lwin_twkb.c index 1262dd999..04261848d 100644 --- a/liblwgeom/lwin_twkb.c +++ b/liblwgeom/lwin_twkb.c @@ -24,11 +24,14 @@ **********************************************************************/ #include +#include #include "liblwgeom_internal.h" #include "lwgeom_log.h" #include "varint.h" #define TWKB_IN_MAXCOORDS 4 +/** Max depth in a geometry. Matches the WKB parser recursion limit. */ +#define LW_PARSER_MAX_DEPTH 200 /** * Used for passing the parse state between the parsing functions. @@ -42,6 +45,8 @@ typedef struct uint32_t check; /* Simple validity checks on geometries */ uint32_t lwtype; /* Current type we are handling */ + uint8_t depth; /* Current recursion level, to prevent stack overflows */ + uint8_t error; /* A hard parse error was found */ uint8_t has_bbox; uint8_t has_size; @@ -157,6 +162,23 @@ twkb_parse_state_has_min_bytes(twkb_parse_state *s, uint32_t count, size_t min_b return LW_TRUE; } +static inline int +twkb_parse_state_accum_coord(twkb_parse_state *s, int coord_index) +{ + const int64_t delta = twkb_parse_state_varint(s); + + if ((delta > 0 && s->coords[coord_index] > INT64_MAX - delta) || + (delta < 0 && s->coords[coord_index] < INT64_MIN - delta)) + { + s->error = LW_TRUE; + lwerror("%s: TWKB coordinate delta overflows int64_t", __func__); + return LW_FALSE; + } + + s->coords[coord_index] += delta; + return LW_TRUE; +} + static uint32_t lwtype_from_twkb_type(uint8_t twkb_type) { switch (twkb_type) @@ -211,7 +233,9 @@ static POINTARRAY* ptarray_from_twkb_state(twkb_parse_state *s, uint32_t npoints POINTARRAY *pa = NULL; uint32_t ndims = s->ndims; uint32_t i; + uint32_t j; double *dlist; + double factors[TWKB_IN_MAXCOORDS]; LWDEBUG(2,"Entering ptarray_from_twkb_state"); LWDEBUGF(4,"Pointarray has %d points", npoints); @@ -223,32 +247,26 @@ static POINTARRAY* ptarray_from_twkb_state(twkb_parse_state *s, uint32_t npoints if (!twkb_parse_state_has_min_bytes(s, npoints, s->ndims)) return NULL; + factors[0] = s->factor; + factors[1] = s->factor; + j = 2; + if (s->has_z) + factors[j++] = s->factor_z; + if (s->has_m) + factors[j++] = s->factor_m; + pa = ptarray_construct(s->has_z, s->has_m, npoints); dlist = (double*)(pa->serialized_pointlist); for( i = 0; i < npoints; i++ ) { - int j = 0; - /* X */ - s->coords[j] += twkb_parse_state_varint(s); - dlist[ndims*i + j] = s->coords[j] / s->factor; - j++; - /* Y */ - s->coords[j] += twkb_parse_state_varint(s); - dlist[ndims*i + j] = s->coords[j] / s->factor; - j++; - /* Z */ - if ( s->has_z ) + for (j = 0; j < ndims; j++) { - s->coords[j] += twkb_parse_state_varint(s); - dlist[ndims*i + j] = s->coords[j] / s->factor_z; - j++; - } - /* M */ - if ( s->has_m ) - { - s->coords[j] += twkb_parse_state_varint(s); - dlist[ndims*i + j] = s->coords[j] / s->factor_m; - j++; + if (!twkb_parse_state_accum_coord(s, j)) + { + ptarray_free(pa); + return NULL; + } + dlist[ndims * i + j] = s->coords[j] / factors[j]; } } @@ -295,7 +313,11 @@ static LWLINE* lwline_from_twkb_state(twkb_parse_state *s) pa = ptarray_from_twkb_state(s, npoints); if( pa == NULL ) + { + if (s->error) + return NULL; return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); + } if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 2 ) { @@ -343,7 +365,14 @@ static LWPOLY* lwpoly_from_twkb_state(twkb_parse_state *s) /* Skip empty rings */ if( pa == NULL ) + { + if (s->error) + { + lwpoly_free(poly); + return NULL; + } continue; + } /* Force first and last points to be the same. */ if( ! ptarray_is_closed_2d(pa) ) @@ -515,6 +544,7 @@ static LWCOLLECTION* lwcollection_from_twkb_state(twkb_parse_state *s) uint32_t ngeoms, i; LWGEOM *geom = NULL; LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m); + uint8_t start_depth = s->depth; LWDEBUG(2,"Entering lwcollection_from_twkb_state"); @@ -539,16 +569,28 @@ static LWCOLLECTION* lwcollection_from_twkb_state(twkb_parse_state *s) if (!twkb_parse_state_has_min_bytes(s, ngeoms, 2)) return col; + s->depth++; + if (s->depth >= LW_PARSER_MAX_DEPTH) + { + lwcollection_free(col); + lwerror("Geometry has too many chained collections"); + s->depth = start_depth; + return NULL; + } + for ( i = 0; i < ngeoms; i++ ) { geom = lwgeom_from_twkb_state(s); - if ( lwcollection_add_lwgeom(col, geom) == NULL ) + if (!geom || lwcollection_add_lwgeom(col, geom) == NULL) { - lwerror("Unable to add geometry (%p) to collection (%p)", (void *) geom, (void *) col); + lwgeom_free(geom); + lwcollection_free(col); + s->depth = start_depth; return NULL; } } + s->depth--; return col; } @@ -702,7 +744,7 @@ LWGEOM* lwgeom_from_twkb_state(twkb_parse_state *s) break; } - if ( has_bbox ) + if (has_bbox && geom) geom->bbox = gbox_clone(&bbox); return geom; diff --git a/liblwgeom/lwin_wkb.c b/liblwgeom/lwin_wkb.c index 762d5cd3a..83acb14c3 100644 --- a/liblwgeom/lwin_wkb.c +++ b/liblwgeom/lwin_wkb.c @@ -831,6 +831,10 @@ static LWNURBSCURVE* lwnurbscurve_from_wkb_state(wkb_parse_state *s) degree, (unsigned long long)degree + 1, npoints); return NULL; } + const size_t min_point_size = 2 + (2 + (s->has_z ? 1 : 0) + (s->has_m ? 1 : 0)) * WKB_DOUBLE_SIZE; + wkb_parse_state_check(s, (size_t)npoints * min_point_size); + if (s->error) + return NULL; /* Initialize points array */ if (npoints > 0) { ----------------------------------------------------------------------- Summary of changes: NEWS | 2 + liblwgeom/cunit/cu_in_twkb.c | 81 +++++++++++++++++++++++++++++++++++++++ liblwgeom/cunit/cu_in_wkb.c | 17 +++++++++ liblwgeom/lwin_twkb.c | 90 ++++++++++++++++++++++++++++++++------------ liblwgeom/lwin_wkb.c | 4 ++ 5 files changed, 170 insertions(+), 24 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Fri Jun 19 12:09:26 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 19 Jun 2026 12:09:26 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-622-gc451c27eb Message-ID: <20260619190926.A2EB51B46C8@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via c451c27eb8cd4e52d66e281f1178d0b542d6be1a (commit) from 09b3ea63d5ac7db56787588c618cb7d4149f95a2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c451c27eb8cd4e52d66e281f1178d0b542d6be1a Author: Darafei Praliaskouski Date: Fri Jun 19 23:02:04 2026 +0400 doc: document ST_AsMVTGeom tile-coordinate simplification Clarify that ST_AsMVTGeom simplifies only within tile coordinate space by snapping to the integer grid, removing repeated points, and removing collinear points after transformation. Direct callers to run explicit map-coordinate simplification before tile conversion when they need broader detail reduction. Closes #6022 Closes https://github.com/postgis/postgis/pull/983 diff --git a/NEWS b/NEWS index 0788a58d2..0190bff69 100644 --- a/NEWS +++ b/NEWS @@ -43,6 +43,7 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #5109, Document the meaning of topology.next_left_edge and topology.next_right_edge links (Darafei Praliaskouski) - #5889, [topology] Include representative locations in topology build errors (Darafei Praliaskouski) - #2614, Use GEOSPreparedDistance and caching to accelerate ST_DWithin (Paul Ramsey) + - #6022, Document ST_AsMVTGeom tile-coordinate simplification (Darafei Praliaskouski) - GH-839, ST_Multi support for TIN and surfaces (Lo?c Bartoletti) - #4398, Add ST_CatmullSmoothing smoothes but retains original vertices (Paul Ramsey) - #4560, ST_3DInterpolatePoint for M interpolation from XYZ inputs (Paul Ramsey) diff --git a/doc/reference_output.xml b/doc/reference_output.xml index f09888e38..7ab16f862 100644 --- a/doc/reference_output.xml +++ b/doc/reference_output.xml @@ -1364,6 +1364,14 @@ SELECT (ST_AsLatLonText('POINT (-302.2342342 -792.32498)')); The function attempts to preserve geometry validity, and corrects it if needed. This may cause the result geometry to collapse to a lower dimension. + The function performs geometry simplification appropriate to the + integer tile coordinate space. After transforming to tile coordinates + it snaps coordinates to the integer grid, removes repeated points, and + removes points that lie on straight lines. It does not perform + general-purpose, scale-dependent simplification such as + . To reduce detail before tile conversion, + simplify the geometry in map coordinates before calling + ST_AsMVTGeom. The rectangular bounds of the tile in the target map coordinate space must be provided, so the geometry can be transformed, and clipped if required. The bounds can be generated using . ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + doc/reference_output.xml | 8 ++++++++ 2 files changed, 9 insertions(+) hooks/post-receive -- PostGIS From trac at osgeo.org Fri Jun 19 12:09:28 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 19 Jun 2026 19:09:28 -0000 Subject: [PostGIS] #6022: Add documentation on simplification performed by ST_AsMVTGeom In-Reply-To: <049.8d06e190fc385292e7a351ca01334593@osgeo.org> References: <049.8d06e190fc385292e7a351ca01334593@osgeo.org> Message-ID: <064.7f44b10f85e37a1a48140a3c838fd1ae@osgeo.org> #6022: Add documentation on simplification performed by ST_AsMVTGeom ----------------------------+--------------------------- Reporter: robintw | Owner: robe Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: documentation | Version: 3.5.x Resolution: fixed | Keywords: ----------------------------+--------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"c451c27eb8cd4e52d66e281f1178d0b542d6be1a/git" c451c27/git]: {{{#!CommitTicketReference repository="git" revision="c451c27eb8cd4e52d66e281f1178d0b542d6be1a" doc: document ST_AsMVTGeom tile-coordinate simplification Clarify that ST_AsMVTGeom simplifies only within tile coordinate space by snapping to the integer grid, removing repeated points, and removing collinear points after transformation. Direct callers to run explicit map- coordinate simplification before tile conversion when they need broader detail reduction. Closes #6022 Closes https://github.com/postgis/postgis/pull/983 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Fri Jun 19 12:28:57 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 19 Jun 2026 12:28:57 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-623-g767201c79 Message-ID: <20260619192857.5FE571B4BD8@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 767201c79e8fdd691b8f244df0b6c74f6118c901 (commit) from c451c27eb8cd4e52d66e281f1178d0b542d6be1a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 767201c79e8fdd691b8f244df0b6c74f6118c901 Author: Darafei Praliaskouski Date: Fri Jun 19 23:17:49 2026 +0400 ptarray_from_twkb_state: avoid signed integer overflow Accumulate TWKB coordinate deltas through explicit unsigned wraparound so malformed inputs cannot trigger undefined signed-overflow behavior. Keep the current generalized dimension loop and existing malformed-input hardening while adding focused regression coverage for the OSS-Fuzz reproducer class. Adapted from Even Rouault's patch in https://github.com/postgis/postgis/pull/982. Closes https://issues.oss-fuzz.com/issues/525554772 Closes https://github.com/postgis/postgis/pull/982 Co-authored-by: Even Rouault diff --git a/liblwgeom/cunit/cu_in_twkb.c b/liblwgeom/cunit/cu_in_twkb.c index 71c38585d..9b2097e0f 100644 --- a/liblwgeom/cunit/cu_in_twkb.c +++ b/liblwgeom/cunit/cu_in_twkb.c @@ -341,7 +341,7 @@ test_twkb_in_deep_collection(void) } static void -test_twkb_in_coordinate_overflow(void) +test_twkb_in_coordinate_delta_wraparound(void) { const uint8_t twkb[] = {0x03, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x2f, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x23, 0x06, 0x02, 0x7e, 0x84, @@ -358,13 +358,14 @@ test_twkb_in_coordinate_overflow(void) /* Delta-encoded coordinates must not rely on signed integer overflow to * wrap hostile inputs into the int64_t accumulator range. */ - ASSERT_STRING_EQUAL(cu_error_msg, "twkb_parse_state_accum_coord: TWKB coordinate delta overflows int64_t"); - CU_ASSERT_PTR_NULL(geom); + CU_ASSERT(strstr(cu_error_msg, "called with n=0 and npoints=0") != NULL); + if (geom != NULL) + lwgeom_free(geom); cu_error_msg_reset(); } static void -test_twkb_in_linestring_coordinate_overflow(void) +test_twkb_in_linestring_coordinate_delta_wraparound(void) { uint8_t twkb[64] = {0x02, 0x00, 0x02}; uint8_t *pos = twkb + 3; @@ -379,8 +380,10 @@ test_twkb_in_linestring_coordinate_overflow(void) geom = lwgeom_from_twkb(twkb, (size_t)(pos - twkb), LW_PARSER_CHECK_NONE); - ASSERT_STRING_EQUAL(cu_error_msg, "twkb_parse_state_accum_coord: TWKB coordinate delta overflows int64_t"); - CU_ASSERT_PTR_NULL(geom); + ASSERT_STRING_EQUAL(cu_error_msg, ""); + CU_ASSERT_PTR_NOT_NULL(geom); + if (geom != NULL) + lwgeom_free(geom); cu_error_msg_reset(); } @@ -403,6 +406,6 @@ void twkb_in_suite_setup(void) PG_ADD_TEST(suite, test_twkb_in_overlong_varint); PG_ADD_TEST(suite, test_twkb_in_count_exceeds_payload); PG_ADD_TEST(suite, test_twkb_in_deep_collection); - PG_ADD_TEST(suite, test_twkb_in_coordinate_overflow); - PG_ADD_TEST(suite, test_twkb_in_linestring_coordinate_overflow); + PG_ADD_TEST(suite, test_twkb_in_coordinate_delta_wraparound); + PG_ADD_TEST(suite, test_twkb_in_linestring_coordinate_delta_wraparound); } diff --git a/liblwgeom/lwin_twkb.c b/liblwgeom/lwin_twkb.c index 04261848d..ad5dcd0c6 100644 --- a/liblwgeom/lwin_twkb.c +++ b/liblwgeom/lwin_twkb.c @@ -25,6 +25,7 @@ #include #include +#include #include "liblwgeom_internal.h" #include "lwgeom_log.h" #include "varint.h" @@ -46,7 +47,6 @@ typedef struct uint32_t check; /* Simple validity checks on geometries */ uint32_t lwtype; /* Current type we are handling */ uint8_t depth; /* Current recursion level, to prevent stack overflows */ - uint8_t error; /* A hard parse error was found */ uint8_t has_bbox; uint8_t has_size; @@ -162,21 +162,23 @@ twkb_parse_state_has_min_bytes(twkb_parse_state *s, uint32_t count, size_t min_b return LW_TRUE; } -static inline int +/** Implements *pa += b using explicit wraparound semantics. */ +#if defined(__clang__) && __clang_major__ >= 4 +__attribute__((no_sanitize("unsigned-integer-overflow"))) +#endif +static inline void +safe_add_int64(int64_t *pa, int64_t b) +{ + uint64_t u_a = (uint64_t)*pa; + uint64_t u_b = (uint64_t)b; + u_a += u_b; + memcpy(pa, &u_a, sizeof(int64_t)); +} + +static inline void twkb_parse_state_accum_coord(twkb_parse_state *s, int coord_index) { - const int64_t delta = twkb_parse_state_varint(s); - - if ((delta > 0 && s->coords[coord_index] > INT64_MAX - delta) || - (delta < 0 && s->coords[coord_index] < INT64_MIN - delta)) - { - s->error = LW_TRUE; - lwerror("%s: TWKB coordinate delta overflows int64_t", __func__); - return LW_FALSE; - } - - s->coords[coord_index] += delta; - return LW_TRUE; + safe_add_int64(&s->coords[coord_index], twkb_parse_state_varint(s)); } static uint32_t lwtype_from_twkb_type(uint8_t twkb_type) @@ -261,11 +263,7 @@ static POINTARRAY* ptarray_from_twkb_state(twkb_parse_state *s, uint32_t npoints { for (j = 0; j < ndims; j++) { - if (!twkb_parse_state_accum_coord(s, j)) - { - ptarray_free(pa); - return NULL; - } + twkb_parse_state_accum_coord(s, j); dlist[ndims * i + j] = s->coords[j] / factors[j]; } } @@ -312,12 +310,8 @@ static LWLINE* lwline_from_twkb_state(twkb_parse_state *s) /* Read coordinates */ pa = ptarray_from_twkb_state(s, npoints); - if( pa == NULL ) - { - if (s->error) - return NULL; + if (pa == NULL) return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); - } if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 2 ) { @@ -364,15 +358,8 @@ static LWPOLY* lwpoly_from_twkb_state(twkb_parse_state *s) POINTARRAY *pa = ptarray_from_twkb_state(s, npoints); /* Skip empty rings */ - if( pa == NULL ) - { - if (s->error) - { - lwpoly_free(poly); - return NULL; - } + if (pa == NULL) continue; - } /* Force first and last points to be the same. */ if( ! ptarray_is_closed_2d(pa) ) ----------------------------------------------------------------------- Summary of changes: liblwgeom/cunit/cu_in_twkb.c | 19 ++++++++++------- liblwgeom/lwin_twkb.c | 51 +++++++++++++++++--------------------------- 2 files changed, 30 insertions(+), 40 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Fri Jun 19 12:45:05 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 19 Jun 2026 12:45:05 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-624-g6f11ffd05 Message-ID: <20260619194506.1F9861B5BA4@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 6f11ffd051915508ef244399043b484a2de46295 (commit) from 767201c79e8fdd691b8f244df0b6c74f6118c901 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6f11ffd051915508ef244399043b484a2de46295 Author: Darafei Praliaskouski Date: Fri Jun 19 23:42:36 2026 +0400 postgis: avoid stale geometry_columns relation lookups Filter stale pg_class rows from geometry_columns by re-resolving visible schema-qualified names before exposing metadata, while keeping inaccessible schemas on OID-based privilege checks that do not resolve hidden names. Require the current SELECT privilege result in both visible and hidden paths so stale snapshots do not keep exposing metadata after relation drops or SELECT revokes. Closes #6038 Closes https://github.com/postgis/postgis/pull/915 diff --git a/NEWS b/NEWS index 0190bff69..c6231dfc7 100644 --- a/NEWS +++ b/NEWS @@ -69,6 +69,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed (Darafei Praliaskouski) - #3103, Add regression coverage for exact-schema find_srid and geometry_columns lookups (Darafei Praliaskouski) + - #6038, Avoid stale relation lookups in geometry_columns after topology + objects are dropped (Darafei Praliaskouski) - #5655, [doc] Skip XML validation during `make check` when xsltproc is unavailable (Darafei Praliaskouski) - #5487, Improve error detail for repeated upgrades after an incomplete diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 3647429c3..8167cbe72 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -6521,7 +6521,40 @@ SELECT current_database()::character varying(256) AS f_table_catalog, ) sr ON sr.connamespace = n.oid AND sr.conrelid = c.oid AND (a.attnum = ANY (sr.conkey)) WHERE (c.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'm'::"char", 'f'::"char", 'p'::"char"])) AND NOT c.relname = 'raster_columns'::name AND t.typname = 'geometry'::name - AND NOT pg_is_other_temp_schema(c.relnamespace) AND has_table_privilege(c.oid, 'SELECT'::text); + AND NOT pg_is_other_temp_schema(c.relnamespace) + -- A stale MVCC snapshot can still see a dropped pg_class row (#6038). + -- Re-resolve the qualified relation name only when the schema is visible, + -- because to_regclass reports permission errors for inaccessible schemas. + -- Without schema visibility, keep the old OID-based privilege semantics. + -- Keep the visible-schema SELECT check in the same CASE branch as the + -- re-resolution guard so PostgreSQL cannot evaluate it for a stale OID. + AND CASE WHEN has_schema_privilege(c.relnamespace, 'USAGE'::text) + THEN CASE WHEN pg_catalog.to_regclass(pg_catalog.format('%I.%I', n.nspname, c.relname)) = c.oid + THEN pg_catalog.has_table_privilege(c.oid, 'SELECT') + ELSE false + END + ELSE pg_catalog.has_table_privilege(c.oid, 'SELECT') + END + AND ( + EXISTS ( + SELECT 1 + FROM pg_roles + WHERE rolname = current_user + AND rolsuper + ) + OR EXISTS ( + SELECT 1 + FROM pg_roles + WHERE rolname = 'pg_read_all_data' + AND pg_has_role(current_user, oid, 'USAGE') + ) + OR EXISTS ( + SELECT 1 + FROM aclexplode(COALESCE(c.relacl, acldefault('r', c.relowner))) AS acl + WHERE acl.privilege_type = 'SELECT' + AND (acl.grantee = 0 OR pg_has_role(acl.grantee, 'USAGE')) + ) + ); -- TODO: support RETURNING and raise a WARNING CREATE OR REPLACE RULE geometry_columns_insert AS diff --git a/regress/core/regress_management.sql b/regress/core/regress_management.sql index c92b7aad0..2b5027bd4 100644 --- a/regress/core/regress_management.sql +++ b/regress/core/regress_management.sql @@ -4,5 +4,65 @@ SET client_min_messages TO warning; CREATE TABLE test_pt(gid SERIAL PRIMARY KEY, geom geometry); INSERT INTO test_pt(geom) VALUES(ST_GeomFromEWKT('SRID=4326;POINT M(1 2 3)')); SELECT populate_geometry_columns('test_pt'::regclass); +SELECT '#6038.before', srid FROM geometry_columns WHERE f_table_schema = 'public' AND f_table_name = 'test_pt' AND f_geometry_column = 'geom'; SELECT 'The result: ' || DropGeometryTable('test_pt'); +SELECT '#6038.after', count(*) FROM geometry_columns WHERE f_table_schema = 'public' AND f_table_name = 'test_pt' AND f_geometry_column = 'geom'; +DO $$ +DECLARE + can_switch_role boolean; +BEGIN + SELECT rolsuper INTO can_switch_role + FROM pg_roles + WHERE rolname = current_user; + + IF can_switch_role THEN + DROP SCHEMA IF EXISTS test6038_private CASCADE; + DROP TABLE IF EXISTS public.test6038_visible_geom; + DROP ROLE IF EXISTS test6038_invisible; + DROP ROLE IF EXISTS test6038_visible; + CREATE ROLE test6038_invisible; + CREATE ROLE test6038_visible; + GRANT test6038_invisible TO CURRENT_USER; + GRANT test6038_visible TO CURRENT_USER; + CREATE TABLE public.test6038_visible_geom(geom geometry(Point, 4326)); + GRANT SELECT ON public.test6038_visible_geom TO test6038_visible; + CREATE SCHEMA test6038_private; + CREATE TABLE test6038_private.hidden_geom(geom geometry(Point, 4326)); + REVOKE ALL ON SCHEMA test6038_private FROM PUBLIC; + GRANT SELECT ON test6038_private.hidden_geom TO test6038_invisible; + + EXECUTE 'SET LOCAL ROLE test6038_visible'; + IF 1 != (SELECT count(*) FROM geometry_columns WHERE f_table_schema = 'public' AND f_table_name = 'test6038_visible_geom') THEN + RAISE EXCEPTION 'geometry_columns did not expose currently selectable table in visible schema'; + END IF; + EXECUTE 'RESET ROLE'; + + REVOKE SELECT ON public.test6038_visible_geom FROM test6038_visible; + EXECUTE 'SET LOCAL ROLE test6038_visible'; + IF 0 != (SELECT count(*) FROM geometry_columns WHERE f_table_schema = 'public' AND f_table_name = 'test6038_visible_geom') THEN + RAISE EXCEPTION 'geometry_columns exposed metadata after SELECT was revoked in visible schema'; + END IF; + EXECUTE 'RESET ROLE'; + + -- The view must not resolve names inside schemas hidden from the caller. + EXECUTE 'SET LOCAL ROLE test6038_invisible'; + IF 1 != (SELECT count(*) FROM geometry_columns WHERE f_table_schema = 'test6038_private') THEN + RAISE EXCEPTION 'geometry_columns did not preserve OID-based SELECT visibility in hidden schema'; + END IF; + EXECUTE 'RESET ROLE'; + + REVOKE SELECT ON test6038_private.hidden_geom FROM test6038_invisible; + EXECUTE 'SET LOCAL ROLE test6038_invisible'; + IF 0 != (SELECT count(*) FROM geometry_columns WHERE f_table_schema = 'test6038_private') THEN + RAISE EXCEPTION 'geometry_columns exposed hidden-schema metadata after SELECT was revoked'; + END IF; + EXECUTE 'RESET ROLE'; + + DROP SCHEMA test6038_private CASCADE; + DROP TABLE public.test6038_visible_geom; + DROP ROLE test6038_invisible; + DROP ROLE test6038_visible; + END IF; +END +$$; SELECT 'Unexistant: ' || DropGeometryTable('unexistent'); -- see ticket #861 diff --git a/regress/core/regress_management_expected b/regress/core/regress_management_expected index e27f7f0ef..ac137e244 100644 --- a/regress/core/regress_management_expected +++ b/regress/core/regress_management_expected @@ -1,3 +1,5 @@ 1 +#6038.before|4326 The result: public.test_pt dropped. +#6038.after|0 Unexistant: public.unexistent dropped. ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ postgis/postgis.sql.in | 35 ++++++++++++++++++- regress/core/regress_management.sql | 60 ++++++++++++++++++++++++++++++++ regress/core/regress_management_expected | 2 ++ 4 files changed, 98 insertions(+), 1 deletion(-) hooks/post-receive -- PostGIS From trac at osgeo.org Fri Jun 19 12:45:07 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 19 Jun 2026 19:45:07 -0000 Subject: [PostGIS] #6038: Using public.geometry_columns causes 'could not open relation with OID 188954716' after drop geometry tables In-Reply-To: <050.410b70db9c436ac53a1e23f89f1c69ff@osgeo.org> References: <050.410b70db9c436ac53a1e23f89f1c69ff@osgeo.org> Message-ID: <065.f01ad4a2449df0cff9bee96bf848b303@osgeo.org> #6038: Using public.geometry_columns causes 'could not open relation with OID 188954716' after drop geometry tables --------------------------------+--------------------------- Reporter: Lars Aksel Opsahl | Owner: strk Type: defect | Status: closed Priority: blocker | Milestone: PostGIS 3.6.5 Component: topology | Version: master Resolution: fixed | Keywords: --------------------------------+--------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"6f11ffd051915508ef244399043b484a2de46295/git" 6f11ffd/git]: {{{#!CommitTicketReference repository="git" revision="6f11ffd051915508ef244399043b484a2de46295" postgis: avoid stale geometry_columns relation lookups Filter stale pg_class rows from geometry_columns by re-resolving visible schema-qualified names before exposing metadata, while keeping inaccessible schemas on OID-based privilege checks that do not resolve hidden names. Require the current SELECT privilege result in both visible and hidden paths so stale snapshots do not keep exposing metadata after relation drops or SELECT revokes. Closes #6038 Closes https://github.com/postgis/postgis/pull/915 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Fri Jun 19 12:51:50 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 19 Jun 2026 12:51:50 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-625-g9aee37109 Message-ID: <20260619195150.BE8A81B6029@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 9aee37109ed245fc322dfec6b1ac7bb1227eb942 (commit) from 6f11ffd051915508ef244399043b484a2de46295 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 9aee37109ed245fc322dfec6b1ac7bb1227eb942 Author: Darafei Praliaskouski Date: Fri Jun 19 23:49:01 2026 +0400 postgis: add coordinate size accessors Add ST_XSize, ST_YSize, and ST_ZSize as box3d dimension helpers that also work for geometry and box2d through existing casts. Add ST_MSize for geometry measures, implemented from ST_MMax and ST_MMin. Closes #2863 Closes https://github.com/postgis/postgis/pull/955 diff --git a/NEWS b/NEWS index c6231dfc7..f0c449087 100644 --- a/NEWS +++ b/NEWS @@ -48,6 +48,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #4398, Add ST_CatmullSmoothing smoothes but retains original vertices (Paul Ramsey) - #4560, ST_3DInterpolatePoint for M interpolation from XYZ inputs (Paul Ramsey) - GT-270, Add NURBSCurve (Lo?c Bartoletti) + - #2863, Add ST_XSize, ST_YSize, ST_ZSize, and ST_MSize dimension helpers + (Darafei Praliaskouski) * Enhancements * diff --git a/doc/reference_bbox.xml b/doc/reference_bbox.xml index 797c36f3d..4a6be9df9 100644 --- a/doc/reference_bbox.xml +++ b/doc/reference_bbox.xml @@ -995,6 +995,165 @@ st_zmin + + + ST_XSize + + Returns the X size of a 2D or 3D bounding box or a geometry. + + + + + + float ST_XSize + box3d aGeomorBox2DorBox3D + + + + + + Description + + Returns the X size of a 2D or 3D bounding box or a geometry, computed as ST_XMax(aGeomorBox2DorBox3D) - ST_XMin(aGeomorBox2DorBox3D). + + + Although this function is only defined for box3d, it also works for box2d and geometry values due to automatic casting. + However it will not accept a geometry or box2d text representation, since those do not auto-cast. + + + &Z_support; + &curve_support; + Availability: 3.7.0 + + + + Examples + + SELECT ST_XSize('BOX3D(1 2 3, 4 5 6)'); +st_xsize +-------- +3 + +SELECT ST_XSize(ST_GeomFromText('LINESTRING(1 3, 5 6)')); +st_xsize +-------- +4 + + + + + See Also + + , , , , + + + + + + ST_YSize + + Returns the Y size of a 2D or 3D bounding box or a geometry. + + + + + + float ST_YSize + box3d aGeomorBox2DorBox3D + + + + + + Description + + Returns the Y size of a 2D or 3D bounding box or a geometry, computed as ST_YMax(aGeomorBox2DorBox3D) - ST_YMin(aGeomorBox2DorBox3D). + + + Although this function is only defined for box3d, it also works for box2d and geometry values due to automatic casting. + However it will not accept a geometry or box2d text representation, since those do not auto-cast. + + + &Z_support; + &curve_support; + Availability: 3.7.0 + + + + Examples + + SELECT ST_YSize('BOX3D(1 2 3, 4 5 6)'); +st_ysize +-------- +3 + +SELECT ST_YSize(ST_GeomFromText('LINESTRING(1 3, 5 6)')); +st_ysize +-------- +3 + + + + + See Also + + , , , , + + + + + + ST_ZSize + + Returns the Z size of a 2D or 3D bounding box or a geometry. + + + + + + float ST_ZSize + box3d aGeomorBox2DorBox3D + + + + + + Description + + Returns the Z size of a 2D or 3D bounding box or a geometry, computed as ST_ZMax(aGeomorBox2DorBox3D) - ST_ZMin(aGeomorBox2DorBox3D). + + + Although this function is only defined for box3d, it also works for box2d and geometry values due to automatic casting. + However it will not accept a geometry or box2d text representation, since those do not auto-cast. + + + &Z_support; + &curve_support; + Availability: 3.7.0 + + + + Examples + + SELECT ST_ZSize('BOX3D(1 2 3, 4 5 6)'); +st_zsize +-------- +3 + +SELECT ST_ZSize(ST_GeomFromEWKT('LINESTRING(1 3 4, 5 6 7)')); +st_zsize +-------- +3 + + + + + See Also + + , , , , + + + ST_MMin @@ -1013,7 +1172,7 @@ st_zmin Description - Returns the M minima of a geometry, or null of the geometry lacks M values. + Returns the M minima of a geometry, or null if the geometry lacks M values. &Z_support; &curve_support; @@ -1032,7 +1191,7 @@ st_mmin See Also - , , , , , , + , , , , , , , @@ -1041,7 +1200,7 @@ st_mmin ST_MMax - Returns the M minima of a geometry. + Returns the M maxima of a geometry. @@ -1054,7 +1213,7 @@ st_mmin Description - Returns the M minima of a geometry, or null of the geometry lacks M values. + Returns the M maxima of a geometry, or null if the geometry lacks M values. &Z_support; &curve_support; @@ -1070,7 +1229,45 @@ st_mmax See Also - , , , , , , + , , , , , , , + + + + + + ST_MSize + + Returns the M size of a geometry. + + + + + + float ST_MSizegeometry geom + + + + + + Description + Returns the M size of a geometry, computed as ST_MMax(geom) - ST_MMin(geom), or null if the geometry lacks M values. + + &Z_support; + &curve_support; + Availability: 3.7.0 + + + + Examples + SELECT ST_MSize('LINESTRING M (1 2 3, 4 6 8)'); +st_msize +-------- +5 + + + + See Also + , , , , diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 8167cbe72..7e5cd081b 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -1130,6 +1130,27 @@ CREATE OR REPLACE FUNCTION ST_ZMax(box3d) LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE _COST_DEFAULT; +-- Availability: 3.7.0 +CREATE OR REPLACE FUNCTION ST_XSize(box3d) + RETURNS FLOAT8 + AS 'SELECT @extschema at .ST_XMax($1) - @extschema at .ST_XMin($1)' + LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE + _COST_DEFAULT; + +-- Availability: 3.7.0 +CREATE OR REPLACE FUNCTION ST_YSize(box3d) + RETURNS FLOAT8 + AS 'SELECT @extschema at .ST_YMax($1) - @extschema at .ST_YMin($1)' + LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE + _COST_DEFAULT; + +-- Availability: 3.7.0 +CREATE OR REPLACE FUNCTION ST_ZSize(box3d) + RETURNS FLOAT8 + AS 'SELECT @extschema at .ST_ZMax($1) - @extschema at .ST_ZMin($1)' + LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE + _COST_DEFAULT; + -- Availability: 3.7.0 CREATE OR REPLACE FUNCTION ST_MMin(geometry) RETURNS FLOAT8 @@ -1144,6 +1165,13 @@ CREATE OR REPLACE FUNCTION ST_MMax(geometry) LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE _COST_DEFAULT; +-- Availability: 3.7.0 +CREATE OR REPLACE FUNCTION ST_MSize(geometry) + RETURNS FLOAT8 + AS 'SELECT @extschema at .ST_MMax($1) - @extschema at .ST_MMin($1)' + LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE + _COST_DEFAULT; + ----------------------------------------------------------------------------- -- BOX2D FUNCTIONS ----------------------------------------------------------------------------- diff --git a/regress/core/tickets.sql b/regress/core/tickets.sql index 413a1b9f1..b31490528 100644 --- a/regress/core/tickets.sql +++ b/regress/core/tickets.sql @@ -123,6 +123,10 @@ SELECT '#175', ST_AsEWKT(ST_GeomFromEWKT('SRID=26915;POINT(482020 4984378.)')); -- #178 -- SELECT '#178a', ST_XMin(ST_MakeBox2D(ST_Point(5, 5), ST_Point(0, 0))); SELECT '#178b', ST_XMax(ST_MakeBox2D(ST_Point(5, 5), ST_Point(0, 0))); +SELECT '#2863a', ST_XSize(ST_MakeBox2D(ST_Point(5, 5), ST_Point(0, 0))); +SELECT '#2863b', ST_YSize('LINESTRING(1 2 3, 4 6 8)'::geometry); +SELECT '#2863c', ST_ZSize('LINESTRING(1 2 3, 4 6 8)'::geometry); +SELECT '#2863d', ST_MSize('LINESTRING M (1 2 3, 4 6 8)'::geometry); -- #179 -- SELECT '#179a', ST_MakeLine(ARRAY[NULL,NULL,NULL,NULL]); diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected index dc67b09d2..9e968e2dd 100644 --- a/regress/core/tickets_expected +++ b/regress/core/tickets_expected @@ -37,6 +37,10 @@ ERROR: Invalid hex string, length (267) has to be a multiple of two! #175|SRID=26915;POINT(482020 4984378) #178a|0 #178b|5 +#2863a|5 +#2863b|4 +#2863c|5 +#2863d|5 NOTICE: No points or linestrings in input array #179a| NOTICE: No points or linestrings in input array ----------------------------------------------------------------------- Summary of changes: NEWS | 2 + doc/reference_bbox.xml | 207 +++++++++++++++++++++++++++++++++++++++++- postgis/postgis.sql.in | 28 ++++++ regress/core/tickets.sql | 4 + regress/core/tickets_expected | 4 + 5 files changed, 240 insertions(+), 5 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Fri Jun 19 12:51:52 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 19 Jun 2026 19:51:52 -0000 Subject: [PostGIS] #2863: ST_Height and ST_Width (or ST_XSize, ST_YSize, ST_ZSize) for geometry In-Reply-To: <046.03185e0efb3b00ea70f42d155b5920d1@osgeo.org> References: <046.03185e0efb3b00ea70f42d155b5920d1@osgeo.org> Message-ID: <061.40ab14e0f6166e6a9a0ea19e6e31d3c4@osgeo.org> #2863: ST_Height and ST_Width (or ST_XSize, ST_YSize, ST_ZSize) for geometry --------------------------+----------------------------- Reporter: robe | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"9aee37109ed245fc322dfec6b1ac7bb1227eb942/git" 9aee371/git]: {{{#!CommitTicketReference repository="git" revision="9aee37109ed245fc322dfec6b1ac7bb1227eb942" postgis: add coordinate size accessors Add ST_XSize, ST_YSize, and ST_ZSize as box3d dimension helpers that also work for geometry and box2d through existing casts. Add ST_MSize for geometry measures, implemented from ST_MMax and ST_MMin. Closes #2863 Closes https://github.com/postgis/postgis/pull/955 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Fri Jun 19 13:14:45 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 19 Jun 2026 13:14:45 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-626-gbdf4f5727 Message-ID: <20260619201445.49F4F1B6BA1@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via bdf4f57279395f82cc323c14f828cbd50b678444 (commit) from 9aee37109ed245fc322dfec6b1ac7bb1227eb942 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit bdf4f57279395f82cc323c14f828cbd50b678444 Author: Darafei Praliaskouski Date: Sat Jun 20 00:13:39 2026 +0400 postgis: support curved rings in ST_MakePolygon Allow ST_MakePolygon to accept closed CircularString, CompoundCurve, and NURBSCurve rings, returning CurvePolygon when any input ring is curved. References #1291 Closes https://github.com/postgis/postgis/pull/961 diff --git a/NEWS b/NEWS index f0c449087..4012eedcf 100644 --- a/NEWS +++ b/NEWS @@ -47,6 +47,7 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - GH-839, ST_Multi support for TIN and surfaces (Lo?c Bartoletti) - #4398, Add ST_CatmullSmoothing smoothes but retains original vertices (Paul Ramsey) - #4560, ST_3DInterpolatePoint for M interpolation from XYZ inputs (Paul Ramsey) + - #1291, ST_MakePolygon support for curved rings (Darafei Praliaskouski) - GT-270, Add NURBSCurve (Lo?c Bartoletti) - #2863, Add ST_XSize, ST_YSize, ST_ZSize, and ST_MSize dimension helpers (Darafei Praliaskouski) diff --git a/doc/reference_constructor.xml b/doc/reference_constructor.xml index 66fbb8b7c..1786be337 100644 --- a/doc/reference_constructor.xml +++ b/doc/reference_constructor.xml @@ -529,7 +529,7 @@ result ST_MakePolygon - Creates a Polygon from a shell and optional list of holes. + Creates a Polygon or CurvePolygon from a shell and optional list of holes. @@ -551,12 +551,14 @@ result Description - Creates a Polygon formed by the given shell and optional array of holes. - Input geometries must be closed LineStrings (rings). + Creates a Polygon or CurvePolygon formed by the given shell and optional array of holes. + Input geometries must be closed LineStrings, CircularStrings, CompoundCurves, or NURBSCurves (rings). + If any input ring is curved, the result is a CurvePolygon. + - Variant 1: Accepts one shell LineString. - Variant 2: Accepts a shell LineString and an array of - inner (hole) LineStrings. A geometry array can be constructed using the PostgreSQL array_agg(), ARRAY[] or + Variant 1: Accepts one shell ring. + Variant 2: Accepts a shell ring and an array of + inner (hole) rings. A geometry array can be constructed using the PostgreSQL array_agg(), ARRAY[] or ARRAY() constructs. This function does not accept MultiLineStrings. @@ -564,6 +566,7 @@ result &Z_support; + Enhanced: 3.7.0 - Support for curved input rings was introduced. @@ -596,6 +599,15 @@ SELECT ST_AsEWKT( ST_MakePolygon( 'LINESTRINGM(75.15 29.53 1,77 29 1,77.6 29.5 2 st_asewkt ---------- POLYGONM((75.15 29.53 1,77 29 1,77.6 29.5 2,75.15 29.53 2)) + + +Create a CurvePolygon from a CircularString shell. + +SELECT ST_AsText( ST_MakePolygon( 'CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0)' )); + + st_astext +---------------------------------------------------- + CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0)) diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c index ec8b3ca18..f12b04b5c 100644 --- a/postgis/lwgeom_functions_basic.c +++ b/postgis/lwgeom_functions_basic.c @@ -20,6 +20,7 @@ * * Copyright 2001-2006 Refractions Research Inc. * Copyright 2017-2018 Daniel Baston + * Copyright 2026 Darafei Praliaskouski * **********************************************************************/ @@ -128,6 +129,23 @@ Datum ST_PointZM(PG_FUNCTION_ARGS); /*------------------------------------------------------------------*/ +static int +lwgeom_is_makepoly_ring_type(uint8_t type) +{ + return type == LINETYPE || type == CIRCSTRINGTYPE || type == COMPOUNDTYPE || type == NURBSCURVETYPE; +} + +static void +lwgeom_makepoly_validate_curve_ring(const LWGEOM *ring, const char *label) +{ + uint32_t vertices_needed = ring->type == LINETYPE ? 4 : 3; + + if (lwgeom_count_vertices(ring) < vertices_needed) + lwerror("%s must have at least %d points", label, vertices_needed); + if (!lwgeom_is_closed(ring)) + lwerror("%s must be closed", label); +} + /** find the size of geometry */ PG_FUNCTION_INFO_V1(LWGEOM_mem_size); Datum LWGEOM_mem_size(PG_FUNCTION_ARGS) @@ -1559,28 +1577,39 @@ Datum LWGEOM_makepoly(PG_FUNCTION_ARGS) GSERIALIZED *pglwg1; ArrayType *array = NULL; GSERIALIZED *result = NULL; - const LWLINE *shell = NULL; + LWGEOM *shell = NULL; + LWGEOM **rings = NULL; const LWLINE **holes = NULL; LWPOLY *outpoly; + LWCURVEPOLY *outcurvepoly; uint32 nholes = 0; uint32 i; size_t offset = 0; + int has_curve_ring = LW_FALSE; + int32_t srid; + int has_z; + int has_m; POSTGIS_DEBUG(2, "LWGEOM_makepoly called."); /* Get input shell */ pglwg1 = PG_GETARG_GSERIALIZED_P(0); - if (gserialized_get_type(pglwg1) != LINETYPE) + if (!lwgeom_is_makepoly_ring_type(gserialized_get_type(pglwg1))) { lwpgerror("Shell is not a line"); } - shell = lwgeom_as_lwline(lwgeom_from_gserialized(pglwg1)); + shell = lwgeom_from_gserialized(pglwg1); + has_curve_ring = shell->type != LINETYPE; + srid = shell->srid; + has_z = FLAGS_GET_Z(shell->flags); + has_m = FLAGS_GET_M(shell->flags); /* Get input holes if any */ if (PG_NARGS() > 1) { array = PG_GETARG_ARRAYTYPE_P(1); nholes = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); + rings = lwalloc(sizeof(LWGEOM *) * (nholes + 1)); holes = lwalloc(sizeof(LWLINE *) * nholes); for (i = 0; i < nholes; i++) { @@ -1592,28 +1621,65 @@ Datum LWGEOM_makepoly(PG_FUNCTION_ARGS) #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif - LWLINE *hole; + LWGEOM *hole; offset += INTALIGN(VARSIZE(g)); - if (gserialized_get_type(g) != LINETYPE) + if (!lwgeom_is_makepoly_ring_type(gserialized_get_type(g))) { lwpgerror("Hole %d is not a line", i); } - hole = lwgeom_as_lwline(lwgeom_from_gserialized(g)); - holes[i] = hole; + hole = lwgeom_from_gserialized(g); + has_curve_ring |= hole->type != LINETYPE; + rings[i + 1] = hole; + holes[i] = lwgeom_as_lwline(hole); } } - outpoly = lwpoly_from_lwlines(shell, nholes, holes); - POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM *)outpoly, 0)); - result = geometry_serialize((LWGEOM *)outpoly); + if (has_curve_ring) + { + if (!rings) + rings = lwalloc(sizeof(LWGEOM *)); + rings[0] = shell; + outcurvepoly = lwcurvepoly_construct_empty(srid, FLAGS_GET_Z(shell->flags), FLAGS_GET_M(shell->flags)); - lwline_free((LWLINE *)shell); + for (i = 0; i <= nholes; i++) + { + if (rings[i]->srid != srid) + lwerror("lwgeom_makepoly: mixed SRIDs in input rings"); + if (FLAGS_GET_Z(rings[i]->flags) != has_z || FLAGS_GET_M(rings[i]->flags) != has_m) + lwerror("lwgeom_makepoly: mixed dimensioned rings"); + lwgeom_makepoly_validate_curve_ring(rings[i], i == 0 ? "Shell" : "Hole"); + if (LW_FAILURE == lwcurvepoly_add_ring(outcurvepoly, rings[i])) + lwerror("lwgeom_makepoly: could not add ring %d to curve polygon", i); + if (i == 0) + shell = NULL; + rings[i] = NULL; + } + + POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM *)outcurvepoly, 0)); + result = geometry_serialize((LWGEOM *)outcurvepoly); + lwgeom_free((LWGEOM *)outcurvepoly); + } + else + { + outpoly = lwpoly_from_lwlines(lwgeom_as_lwline(shell), nholes, holes); + POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM *)outpoly, 0)); + result = geometry_serialize((LWGEOM *)outpoly); + lwpoly_free(outpoly); + } + + if (shell) + lwgeom_free(shell); PG_FREE_IF_COPY(pglwg1, 0); for (i = 0; i < nholes; i++) { - lwline_free((LWLINE *)holes[i]); + if (rings && rings[i + 1]) + lwgeom_free(rings[i + 1]); } + if (rings) + lwfree(rings); + if (holes) + lwfree(holes); PG_RETURN_POINTER(result); } diff --git a/regress/core/ctors.sql b/regress/core/ctors.sql index d4038d44e..2b74d19a1 100644 --- a/regress/core/ctors.sql +++ b/regress/core/ctors.sql @@ -44,3 +44,30 @@ FROM ( ('MULTILINESTRING((1 1, 2 2), (2 2, 3 3))'), ('MULTILINESTRING(EMPTY, (4 4, 5 5))') ) AS geoms(geom); + +SELECT 'ST_MakePolygonLine', ST_AsText(ST_MakePolygon( + 'LINESTRING(0 0, 4 0, 4 4, 0 4, 0 0)'::geometry)); + +SELECT 'ST_MakePolygonCurveShell', ST_AsText(ST_MakePolygon( + 'CIRCULARSTRING(0 0, 1 1, 2 0, 1 -1, 0 0)'::geometry)); + +SELECT 'ST_MakePolygonCurveHole', ST_AsText(ST_MakePolygon( + 'LINESTRING(0 0, 4 0, 4 4, 0 4, 0 0)'::geometry, + ARRAY['CIRCULARSTRING(1 1, 2 2, 3 1, 2 0, 1 1)'::geometry])); + +SELECT 'ST_MakePolygonNurbsShell', ST_AsText(ST_MakePolygon( + 'NURBSCURVE(2, (0 0, 5 10, 10 0, 5 -10, 0 0))'::geometry)); + +SELECT 'ST_MakePolygonNurbsHole', ST_AsText(ST_MakePolygon( + 'LINESTRING(0 0, 4 0, 4 4, 0 4, 0 0)'::geometry, + ARRAY['NURBSCURVE(2, (1 1, 2 2, 3 1, 2 0, 1 1))'::geometry])); + +SELECT ST_MakePolygon('CIRCULARSTRING(0 0, 1 1, 2 0)'::geometry); + +SELECT ST_MakePolygon( + 'CIRCULARSTRING Z (0 0 0, 1 1 0, 2 0 0, 1 -1 0, 0 0 0)'::geometry, + ARRAY['CIRCULARSTRING M (1 1 7, 2 2 7, 3 1 7, 2 0 7, 1 1 7)'::geometry]); + +SELECT ST_MakePolygon( + 'CIRCULARSTRING M (0 0 0, 1 1 0, 2 0 0, 1 -1 0, 0 0 0)'::geometry, + ARRAY['CIRCULARSTRING Z (1 1 7, 2 2 7, 3 1 7, 2 0 7, 1 1 7)'::geometry]); diff --git a/regress/core/ctors_expected b/regress/core/ctors_expected index d18c7100c..bcdf4a5e7 100644 --- a/regress/core/ctors_expected +++ b/regress/core/ctors_expected @@ -10,3 +10,11 @@ ERROR: BOX2D_construct: Operation on mixed SRID geometries (Point, 0) != (Point BOX3D(0 0 0,1 1 0) ERROR: BOX3D_construct: Operation on mixed SRID geometries (Point, 0) != (Point, 3) ST_MakeLine2|LINESTRING(0 0,1 1,2 2,3 3,4 4,5 5) +ST_MakePolygonLine|POLYGON((0 0,4 0,4 4,0 4,0 0)) +ST_MakePolygonCurveShell|CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0)) +ST_MakePolygonCurveHole|CURVEPOLYGON((0 0,4 0,4 4,0 4,0 0),CIRCULARSTRING(1 1,2 2,3 1,2 0,1 1)) +ST_MakePolygonNurbsShell|CURVEPOLYGON(NURBSCURVE(DEGREE 2,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 10),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(10 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 -10),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1)),KNOTS (KNOT(0,3),KNOT(0.333333333333333,1),KNOT(0.666666666666667,1),KNOT(1,3)))) +ST_MakePolygonNurbsHole|CURVEPOLYGON((0 0,4 0,4 4,0 4,0 0),NURBSCURVE(DEGREE 2,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(1 1),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2 2),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(3 1),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(1 1),WEIGHT 1)),KNOTS (KNOT(0,3),KNOT(0.333333333333333,1),KNOT(0.666666666666667,1),KNOT(1,3)))) +ERROR: Shell must be closed +ERROR: lwgeom_makepoly: mixed dimensioned rings +ERROR: lwgeom_makepoly: mixed dimensioned rings ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + doc/reference_constructor.xml | 24 ++++++++--- postgis/lwgeom_functions_basic.c | 90 ++++++++++++++++++++++++++++++++++------ regress/core/ctors.sql | 27 ++++++++++++ regress/core/ctors_expected | 8 ++++ 5 files changed, 132 insertions(+), 18 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Fri Jun 19 13:14:47 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 19 Jun 2026 20:14:47 -0000 Subject: [PostGIS] #1291: Create curve lines and polygons from points, similar to ST_MakeLine In-Reply-To: <055.80484389b53141db417c7ee9b3d4c437@osgeo.org> References: <055.80484389b53141db417c7ee9b3d4c437@osgeo.org> Message-ID: <070.0d63fe544aed2a4a7fc22993cf9e0ebb@osgeo.org> #1291: Create curve lines and polygons from points, similar to ST_MakeLine ----------------------------+----------------------------- Reporter: realityexists | Owner: pramsey Type: enhancement | Status: new Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: 1.5.X Resolution: | Keywords: ----------------------------+----------------------------- Comment (by Darafei Praliaskouski ): In [changeset:"bdf4f57279395f82cc323c14f828cbd50b678444/git" bdf4f572/git]: {{{#!CommitTicketReference repository="git" revision="bdf4f57279395f82cc323c14f828cbd50b678444" postgis: support curved rings in ST_MakePolygon Allow ST_MakePolygon to accept closed CircularString, CompoundCurve, and NURBSCurve rings, returning CurvePolygon when any input ring is curved. References #1291 Closes https://github.com/postgis/postgis/pull/961 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Fri Jun 19 14:18:46 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 19 Jun 2026 14:18:46 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-627-g650756cd2 Message-ID: <20260619211846.619F61B767F@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 650756cd29999db62384b98f1c2e876c6a61efc6 (commit) from bdf4f57279395f82cc323c14f828cbd50b678444 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 650756cd29999db62384b98f1c2e876c6a61efc6 Author: Darafei Praliaskouski Date: Sat Jun 20 01:03:13 2026 +0400 doc: validate manual with DocBook XMLSchema Detect the DocBook 5 XMLSchema during configure and include XMLSchema validation in the documentation check target. References #5532 Closes https://github.com/postgis/postgis/pull/967 diff --git a/NEWS b/NEWS index 4012eedcf..6523cb57e 100644 --- a/NEWS +++ b/NEWS @@ -63,6 +63,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed reprojection support (Darafei Praliaskouski) - #4749, Use point-in-polygon predicate fast paths for point-only GeometryCollections (Darafei Praliaskouski) + - #5532, Validate the manual against DocBook XMLSchema in check-xml + (Darafei Praliaskouski) * Bug Fixes * diff --git a/configure.ac b/configure.ac index 6d84d5568..57157d133 100644 --- a/configure.ac +++ b/configure.ac @@ -397,6 +397,19 @@ else fi AC_SUBST([DOCBOOK5_RNG]) +dnl +dnl Ensure DocBook XMLSchema can be found +dnl +DOCBOOK5_XSD=http://docbook.org/xml/5.0/xsd/docbook.xsd +if test "x$XMLCATALOG" = "x"; then + DOCBOOK5_XSD= +else + if $XMLCATALOG '' "${DOCBOOK5_XSD}" > /dev/null; then : + else DOCBOOK5_XSD= + fi +fi +AC_SUBST([DOCBOOK5_XSD]) + dnl dnl Ensure DocBook DTD can be found dnl diff --git a/doc/Makefile.in b/doc/Makefile.in index 6230b2031..1c792eb0d 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -64,6 +64,7 @@ XMLCATALOG=@XMLCATALOG@ XSLTPROC=@XSLTPROC@ XSLBASE=@XSLBASE@ DOCBOOK5_RNG=@DOCBOOK5_RNG@ +DOCBOOK5_XSD=@DOCBOOK5_XSD@ DOCBOOK5_DTD=@DOCBOOK5_DTD@ CAN_UPDATE_TRANSLATIONS=@CAN_UPDATE_TRANSLATIONS@ XMLLINT=@XMLLINT@ @@ -287,6 +288,11 @@ ifeq ($(DOCBOOK5_RNG),) CAN_CHECK_XML = no endif +ifeq ($(DOCBOOK5_XSD),) +check-xml: requirements_not_met_docbook5_xsd +CAN_CHECK_XML = no +endif + ifeq ($(DOCBOOK5_DTD),) CAN_CHECK_XML = no endif @@ -624,6 +630,9 @@ check-xml: postgis-out.xml --valid --loaddtd \ --relaxng $(DOCBOOK5_RNG) \ $< + $(XMLLINT) --noout --nonet \ + --schema $(DOCBOOK5_XSD) \ + $< check-cheatsheets: cheatsheets for f in $(html_builddir)/*_cheatsheet-en.html; do \ @@ -657,6 +666,13 @@ requirements_not_met_xmlcatalog: @echo @false +requirements_not_met_docbook5_xsd: + @echo + @echo "configure was unable to locate DocBook XMLSchema (docbook.xsd)." + @echo "Install DocBook 5 schemas/catalog entries and then re-run configure." + @echo + @false + requirements_not_met_xslbase: @echo diff --git a/doc/README b/doc/README index 905cbfef1..865190eb3 100644 --- a/doc/README +++ b/doc/README @@ -68,7 +68,8 @@ Make targets XML files. See ``make check-localized`` ``make check`` - check structural correctness of XML documentation + check structural correctness of XML documentation with DocBook DTD, + RelaxNG, and XMLSchema validation ``make check-localized`` check structural correctness of localized (translated) ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ configure.ac | 13 +++++++++++++ doc/Makefile.in | 16 ++++++++++++++++ doc/README | 3 ++- 4 files changed, 33 insertions(+), 1 deletion(-) hooks/post-receive -- PostGIS From trac at osgeo.org Fri Jun 19 14:18:47 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 19 Jun 2026 21:18:47 -0000 Subject: [PostGIS] #5532: Improve validation of PostGIS Manual docbook In-Reply-To: <046.01aba4c7cf04b56a357e187afeae37ac@osgeo.org> References: <046.01aba4c7cf04b56a357e187afeae37ac@osgeo.org> Message-ID: <061.477d28f73553b7d3e9b7e23acc500849@osgeo.org> #5532: Improve validation of PostGIS Manual docbook ----------------------------+--------------------------- Reporter: strk | Owner: strk Type: defect | Status: assigned Priority: medium | Milestone: PostGIS 3.7.0 Component: documentation | Version: master Resolution: | Keywords: ----------------------------+--------------------------- Comment (by Darafei Praliaskouski ): In [changeset:"650756cd29999db62384b98f1c2e876c6a61efc6/git" 650756c/git]: {{{#!CommitTicketReference repository="git" revision="650756cd29999db62384b98f1c2e876c6a61efc6" doc: validate manual with DocBook XMLSchema Detect the DocBook 5 XMLSchema during configure and include XMLSchema validation in the documentation check target. References #5532 Closes https://github.com/postgis/postgis/pull/967 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Fri Jun 19 14:32:07 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 19 Jun 2026 14:32:07 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-628-g3abf37d25 Message-ID: <20260619213207.8B78B1B7C77@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 3abf37d25803fe25c564dd16b7d426f22f8ad18e (commit) from 650756cd29999db62384b98f1c2e876c6a61efc6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 3abf37d25803fe25c564dd16b7d426f22f8ad18e Author: Paul Ramsey Date: Fri Jun 19 14:31:24 2026 -0700 Address WKB fuzzing issues in Nurbs diff --git a/liblwgeom/cunit/cu_in_wkb.c b/liblwgeom/cunit/cu_in_wkb.c index 2b9066ae8..661590504 100644 --- a/liblwgeom/cunit/cu_in_wkb.c +++ b/liblwgeom/cunit/cu_in_wkb.c @@ -240,7 +240,7 @@ test_wkb_fuzz(void) uint8_t wkb[36] = {000, 000, 000, 000, 015, 000, 000, 000, 003, 000, 200, 000, 000, 010, 000, 000, 000, 000, 000, 000, 000, 000, 010, 000, 000, 000, 000, 000, 000, 000, 000, 010, 000, 000, 000, 000}; LWGEOM *g = lwgeom_from_wkb(wkb, 36, LW_PARSER_CHECK_NONE); - lwgeom_free(g); + CU_ASSERT(g == NULL); /* OSS-FUZZ https://trac.osgeo.org/postgis/ticket/4536 */ uint8_t wkb2[319] = { @@ -261,26 +261,31 @@ test_wkb_fuzz(void) 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001}; g = lwgeom_from_wkb(wkb2, 319, LW_PARSER_CHECK_NONE); - lwgeom_free(g); + CU_ASSERT(g == NULL); /* OSS-FUZZ: https://trac.osgeo.org/postgis/ticket/4535 */ uint8_t wkb3[9] = {0x01, 0x03, 0x00, 0x00, 0x10, 0x8d, 0x55, 0xf3, 0xff}; g = lwgeom_from_wkb(wkb3, 9, LW_PARSER_CHECK_NONE); - lwgeom_free(g); + CU_ASSERT(g == NULL); /* OSS-FUZZ: https://trac.osgeo.org/postgis/ticket/4544 */ uint8_t wkb4[22] = {0x01, 0x0f, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x11, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00}; g = lwgeom_from_wkb(wkb4, 22, LW_PARSER_CHECK_NONE); - lwgeom_free(g); + CU_ASSERT(g == NULL); /* OSS-FUZZ: https://trac.osgeo.org/postgis/ticket/4621 */ uint32_t big_size = 20000000; uint8_t *wkb5 = lwalloc(big_size); memset(wkb5, 0x01, big_size); g = lwgeom_from_wkb(wkb5, big_size, LW_PARSER_CHECK_NONE); - lwgeom_free(g); + CU_ASSERT(g == NULL); lwfree(wkb5); + + /* OSS-Fuzz issue 525520951: NURBSCURVE WKB claiming 119M points in 13 bytes ? OOM */ + uint8_t nurbs_oom[13] = {0x01, 0x15, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x07}; + g = lwgeom_from_wkb(nurbs_oom, 13, LW_PARSER_CHECK_NONE); + CU_ASSERT(g == NULL); } static void diff --git a/liblwgeom/lwin_wkb.c b/liblwgeom/lwin_wkb.c index 83acb14c3..f178e9937 100644 --- a/liblwgeom/lwin_wkb.c +++ b/liblwgeom/lwin_wkb.c @@ -122,8 +122,6 @@ uint8_t* bytes_from_hexbytes(const char *hexbuf, size_t hexsize) - - /** * Check that we are not about to read off the end of the WKB * array. @@ -290,6 +288,7 @@ static char byte_from_wkb_state(wkb_parse_state *s) return char_value; } + /** * Int32 * Read 4-byte integer and advance the parse state forward. @@ -348,13 +347,44 @@ static double double_from_wkb_state(wkb_parse_state *s) ((uint8_t*)(&d))[i] = ((uint8_t*)(&d))[WKB_DOUBLE_SIZE - i - 1]; ((uint8_t*)(&d))[WKB_DOUBLE_SIZE - i - 1] = tmp; } - } s->pos += WKB_DOUBLE_SIZE; return d; } + + +/** +* Set the swap bytes flag depending on the endianness +* of the machine and the endianness of the input data. +* If they differ, we must swap, otherwise we can copy. +*/ +static void wkb_swap_bytes(wkb_parse_state *s) +{ + char wkb_little_endian; + + /* Fail when handed incorrect starting byte */ + wkb_little_endian = byte_from_wkb_state(s); + if (s->error) + lwerror("Invalid endian flag value encountered."); + + if( wkb_little_endian != 1 && wkb_little_endian != 0 ) + lwerror("Invalid endian flag value encountered."); + + /* Check the endianness of our input */ + s->swap_bytes = LW_FALSE; + + /* Machine arch is big endian, request is for little */ + if (IS_BIG_ENDIAN && wkb_little_endian) + s->swap_bytes = LW_TRUE; + /* Machine arch is little endian, request is for big */ + else if ((!IS_BIG_ENDIAN) && (!wkb_little_endian)) + s->swap_bytes = LW_TRUE; +} + + + /** * POINTARRAY * Read a dynamically sized point array and advance the parse state forward. @@ -364,9 +394,9 @@ static POINTARRAY* ptarray_from_wkb_state(wkb_parse_state *s) { POINTARRAY *pa = NULL; size_t pa_size; - uint32_t ndims = 2; uint32_t npoints = 0; static uint32_t maxpoints = UINT_MAX / WKB_DOUBLE_SIZE / 4; + uint32_t ndims = 2 + s->has_z + s->has_m; /* Calculate the size of this point array. */ npoints = integer_from_wkb_state(s); @@ -382,15 +412,12 @@ static POINTARRAY* ptarray_from_wkb_state(wkb_parse_state *s) LWDEBUGF(4,"Pointarray has %d points", npoints); - if( s->has_z ) ndims++; - if( s->has_m ) ndims++; - pa_size = (size_t)npoints * ndims * WKB_DOUBLE_SIZE; - /* Empty! */ if( npoints == 0 ) return ptarray_construct(s->has_z, s->has_m, npoints); /* Does the data we want to read exist? */ + pa_size = (size_t)npoints * ndims * WKB_DOUBLE_SIZE; wkb_parse_state_check(s, pa_size); if (s->error) return NULL; @@ -802,10 +829,12 @@ static LWCOLLECTION* lwcollection_from_wkb_state(wkb_parse_state *s) */ static LWNURBSCURVE* lwnurbscurve_from_wkb_state(wkb_parse_state *s) { - uint32_t degree = 0, nknots = 0, npoints = 0; + uint32_t degree = 0, nknots = 0, npoints = 0, ndims; double *weights = NULL, *knots = NULL; POINTARRAY *points = NULL; int all_weights_one = 1; + size_t pa_size; + static const uint32_t MAXPOINTS = (uint32_t)(UINT_MAX / (WKB_DOUBLE_SIZE * 4)); /* ISO/IEC 13249-3:2016 compliant parsing */ degree = integer_from_wkb_state(s); @@ -821,11 +850,11 @@ static LWNURBSCURVE* lwnurbscurve_from_wkb_state(wkb_parse_state *s) if (s->error) return NULL; /* Defensive upper bound (worst-case 4 doubles/point) */ - static const uint32_t MAXPOINTS = (uint32_t)(UINT_MAX / (WKB_DOUBLE_SIZE * 4)); if (npoints > MAXPOINTS) { lwerror("WKB NURBSCURVE: control point count (%u) too large", npoints); return NULL; } + if (npoints > 0 && npoints <= degree) { lwerror("WKB NURBSCURVE: degree %u requires at least %llu control points, got %u", degree, (unsigned long long)degree + 1, npoints); @@ -836,44 +865,33 @@ static LWNURBSCURVE* lwnurbscurve_from_wkb_state(wkb_parse_state *s) if (s->error) return NULL; + /* Does the data we want to read exist? */ + ndims = 2 + s->has_z + s->has_m; + pa_size = (size_t)npoints * ndims * WKB_DOUBLE_SIZE; /* coord */ + pa_size += npoints * sizeof(double); /* weight */ + pa_size += npoints * sizeof(char) * 2; /* endian_byte + weight_byte */ + wkb_parse_state_check(s, pa_size); + if (s->error) + return NULL; + /* Initialize points array */ if (npoints > 0) { + int8_t save_swap_butes = s->swap_bytes; + points = ptarray_construct(s->has_z, s->has_m, npoints); weights = lwalloc(sizeof(double) * npoints); /* ISO format: each control point has structure: * [] */ + for (uint32_t i = 0; i < npoints; i++) { + POINT4D pt = {0, 0, 0, 0}; + /* Read byte order for this point (ISO requirement) */ - uint8_t point_endian = byte_from_wkb_state(s); - if (s->error) { - lwfree(weights); - ptarray_free(points); - return NULL; - } - if (point_endian != 0 && point_endian != 1) { - lwerror("WKB NURBSCURVE: invalid endian flag %u at control point %u", point_endian, i); - lwfree(weights); - ptarray_free(points); - return NULL; - } - - /* Compute whether this point needs byte swapping */ - int8_t point_swap = LW_FALSE; - /* Machine arch is big endian, point is little endian */ - if (IS_BIG_ENDIAN && point_endian) - point_swap = LW_TRUE; - /* Machine arch is little endian, point is big endian */ - else if ((!IS_BIG_ENDIAN) && (!point_endian)) - point_swap = LW_TRUE; - - /* Save original swap state and apply point-specific swapping */ - int8_t original_swap = s->swap_bytes; - s->swap_bytes = point_swap; + wkb_swap_bytes(s); /* Read point coordinates */ - POINT4D pt = {0, 0, 0, 0}; pt.x = double_from_wkb_state(s); if (s->error) { lwfree(weights); @@ -941,9 +959,9 @@ static LWNURBSCURVE* lwnurbscurve_from_wkb_state(wkb_parse_state *s) return NULL; } - /* Restore original swap state */ - s->swap_bytes = original_swap; } + /* Restore original swap state */ + s->swap_bytes = save_swap_butes; } /* Read knots (required by WKB standard) */ @@ -1032,31 +1050,11 @@ static LWNURBSCURVE* lwnurbscurve_from_wkb_state(wkb_parse_state *s) */ LWGEOM* lwgeom_from_wkb_state(wkb_parse_state *s) { - char wkb_little_endian; uint32_t wkb_type; LWDEBUG(4,"Entered function"); - /* Fail when handed incorrect starting byte */ - wkb_little_endian = byte_from_wkb_state(s); - if (s->error) - return NULL; - if( wkb_little_endian != 1 && wkb_little_endian != 0 ) - { - LWDEBUG(4,"Leaving due to bad first byte!"); - lwerror("Invalid endian flag value encountered."); - return NULL; - } - - /* Check the endianness of our input */ - s->swap_bytes = LW_FALSE; - - /* Machine arch is big endian, request is for little */ - if (IS_BIG_ENDIAN && wkb_little_endian) - s->swap_bytes = LW_TRUE; - /* Machine arch is little endian, request is for big */ - else if ((!IS_BIG_ENDIAN) && (!wkb_little_endian)) - s->swap_bytes = LW_TRUE; + wkb_swap_bytes(s); /* Read the type number */ wkb_type = integer_from_wkb_state(s); ----------------------------------------------------------------------- Summary of changes: liblwgeom/cunit/cu_in_wkb.c | 15 ++++-- liblwgeom/lwin_wkb.c | 116 ++++++++++++++++++++++---------------------- 2 files changed, 67 insertions(+), 64 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Fri Jun 19 14:33:20 2026 From: git at osgeo.org (git at osgeo.org) Date: Fri, 19 Jun 2026 14:33:20 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-629-g7a62d652e Message-ID: <20260619213320.9566F1B8909@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 7a62d652e3a3ed1402e633a198f8871464c27c35 (commit) from 3abf37d25803fe25c564dd16b7d426f22f8ad18e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 7a62d652e3a3ed1402e633a198f8871464c27c35 Author: Darafei Praliaskouski Date: Sat Jun 20 01:24:51 2026 +0400 doc: add raster2pgsql man page Install the raster2pgsql(1) manual page and align its examples with the raster loader workflows documented in the main manual. Closes #2386 Closes https://github.com/postgis/postgis/pull/979 diff --git a/NEWS b/NEWS index 6523cb57e..a8b25af45 100644 --- a/NEWS +++ b/NEWS @@ -82,6 +82,7 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed deprecated-function cleanup (Darafei Praliaskouski) - GH-899, [raster] Honor PostgreSQL interrupts in long-running GDAL progress callbacks (Darafei Praliaskouski) + - #2386, Add missing raster2pgsql man page (Darafei Praliaskouski) - #5975, Initialize skipped union-find cluster ids deterministically (Darafei Praliaskouski) - GH-885, [topology] Avoid GMP overflow in ring orientation for very large diff --git a/doc/Makefile.in b/doc/Makefile.in index 1c792eb0d..b7f684108 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -564,7 +564,7 @@ endif comments-uninstall: $(MAKE) -f Makefile.comments uninstall -man-install: man/shp2pgsql.1 man/pgsql2shp.1 man/pgtopo_export.1 man/pgtopo_import.1 man/postgis.1 man/postgis_restore.1 +man-install: man/shp2pgsql.1 man/pgsql2shp.1 man/raster2pgsql.1 man/pgtopo_export.1 man/pgtopo_import.1 man/postgis.1 man/postgis_restore.1 mkdir -p $(DESTDIR)$(mandir)/man1 for f in $^; do \ $(INSTALL_DATA) $$f $(DESTDIR)$(mandir)/man1/`basename $$f`; \ @@ -573,6 +573,7 @@ man-install: man/shp2pgsql.1 man/pgsql2shp.1 man/pgtopo_export.1 man/pgtopo_impo man-uninstall: rm -f $(DESTDIR)$(mandir)/man1/shp2pgsql.1 rm -f $(DESTDIR)$(mandir)/man1/pgsql2shp.1 + rm -f $(DESTDIR)$(mandir)/man1/raster2pgsql.1 rm -f $(DESTDIR)$(mandir)/man1/pgtopo_export.1 rm -f $(DESTDIR)$(mandir)/man1/pgtopo_import.1 rm -f $(DESTDIR)$(mandir)/man1/postgis.1 diff --git a/doc/man/raster2pgsql.1 b/doc/man/raster2pgsql.1 new file mode 100644 index 000000000..f33b9c504 --- /dev/null +++ b/doc/man/raster2pgsql.1 @@ -0,0 +1,171 @@ +.TH "raster2pgsql" "1" "" "" "PostGIS" +.SH "NAME" +.LP +raster2pgsql - raster to postgis loader + +.SH "SYNTAX" +.LP +raster2pgsql [\fIoptions\fR] \fIraster\fR [\fIraster\fR ...] [[\fIschema\fR\fB.\fR]\fItable\fR] + +.SH "DESCRIPTION" +.LP +The raster2pgsql data loader converts raster files supported by GDAL into SQL +suitable for insertion into a PostGIS raster table. Multiple raster files may +be passed on the command line, and shell wildcards can be used to select input +files. + +.SH "OPTIONS" +.LP +The commandline options are: +.TP +\fB\-s\fR [<\fIFROM_SRID\fR>:]<\fISRID\fR> +Set the SRID field. If FROM_SRID is given, the input raster is treated as that +source SRID before being transformed to SRID. If no SRID is provided, or if SRID +is 0, raster metadata is used when possible. +.TP +\fB\-b\fR <\fIband\fR> +Index, starting from 1, of the band to extract from the raster. Separate +multiple band indexes with commas. Ranges can be written with a dash. If this +option is omitted, all bands are extracted. +.TP +\fB\-t\fR <\fItile_size\fR> +Cut each raster into tiles inserted one per table row. The tile size is written +as WIDTHxHEIGHT. Use "auto" to let the loader choose a tile size from the first +raster and apply it to all rasters. +.TP +\fB\-P\fR +Pad right-most and bottom-most tiles so all tiles have the same width and +height. +.TP +\fB\-R\fR +Register the raster as an out-of-db filesystem raster. Input raster paths must +be absolute. +.TP +\fB\-d\fR +Drop the table, recreate it, and populate it with the raster data. +.TP +\fB\-a\fR +Append raster data into the existing table. The target table must have the same +schema. +.TP +\fB\-c\fR +Create a new table and populate it. This is the default mode. +.TP +\fB\-p\fR +Prepare mode. Only emit SQL to create the table. +.TP +\fB\-f\fR <\fIcolumn\fR> +Specify the name of the raster column. +.TP +\fB\-F\fR +Add a column containing the source raster filename. +.TP +\fB\-n\fR <\fIcolumn\fR> +Specify the filename column name. This implies \-F. +.TP +\fB\-l\fR <\fIoverview_factor\fR> +Create overview tables for the raster. Separate multiple factors with commas. +Overview table names follow the pattern o__
. Created +overviews are stored in the database and are not affected by \-R. +.TP +\fB\-q\fR +Wrap PostgreSQL identifiers in quotes. +.TP +\fB\-I\fR +Create a GiST spatial index on the raster column. +.TP +\fB\-M\fR +Run VACUUM ANALYZE on the raster table. This is most useful when appending to an +existing table with \-a. +.TP +\fB\-C\fR +Set the standard raster constraints after the rasters are loaded. Some +constraints may fail if one or more input rasters violate the constraint. +.TP +\fB\-x\fR +Disable setting the max extent constraint. Only applies with \-C. +.TP +\fB\-r\fR +Set spatially unique and coverage tile constraints for regular blocking. Only +applies with \-C. +.TP +\fB\-T\fR <\fItablespace\fR> +Specify the tablespace for the new table. +.TP +\fB\-X\fR <\fItablespace\fR> +Specify the tablespace for the new table's indexes. This applies to the primary +key and the spatial index when \-I is used. +.TP +\fB\-N\fR <\fInodata\fR> +NODATA value to use on bands without a NODATA value. +.TP +\fB\-k\fR +Keep empty tiles by skipping NODATA value checks for each raster band. +.TP +\fB\-E\fR <\fIendian\fR> +Control endianness of generated binary raster output. Use 0 for XDR and 1 for +NDR. Only NDR is currently supported. +.TP +\fB\-V\fR <\fIversion\fR> +Specify the output WKB format version. Only version 0 is currently supported. +.TP +\fB\-e\fR +Execute each statement individually instead of wrapping the load in a +transaction. +.TP +\fB\-Y\fR [<\fImax_rows_per_copy\fR>] +Use COPY statements instead of INSERT statements. If no row limit is provided, +50 rows are written per COPY. +.TP +\fB\-G\fR +Print the supported GDAL raster formats. +.TP +\fB\-?\fR +Display version and usage information. + +.SH "EXAMPLES" +.LP +Load one projected population raster using COPY statements, automatic tiling, +and post-load VACUUM ANALYZE: + +# \fBpsql \-c "drop table if exists ghs_globe_population_raster;"\fR +.br +# \fBraster2pgsql \-M \-Y \-s 54009 data/mid/ghs/GHS_POP.tif \-t auto ghs_globe_population_raster | psql \-q\fR + +.LP +Create an empty raster table first, then append many rasters in parallel. This +pattern is useful when loading large raster collections: + +# \fBpsql \-c "drop table if exists hrsl_population_raster;"\fR +.br +# \fBraster2pgsql \-p \-Y \-s 4326 data/in/hrsl/*.tif \-t auto hrsl_population_raster | psql \-q\fR +.br +# \fBfind data/in/hrsl \-name "*.tif" \-type f | parallel --eta 'GDAL_CACHEMAX=10000 GDAL_NUM_THREADS=4 raster2pgsql \-a \-Y \-s 4326 {} \-t auto hrsl_population_raster | psql \-q'\fR +.br +# \fBpsql \-c "create index hrsl_population_raster_rast_idx on hrsl_population_raster using gist (ST_ConvexHull(rast));"\fR +.br +# \fBpsql \-c "vacuum analyze hrsl_population_raster;"\fR + +.LP +Create and append a tiled raster set from pre-cut tiles. The first tile creates +the table definition; the remaining tiles append into it: + +# \fBls data/mid/night_lights/*.tif | head \-1 | parallel 'raster2pgsql \-p \-Y \-s 4326 {} \-t auto night_lights_raster | psql \-q'\fR +.br +# \fBls data/mid/night_lights/*.tif | parallel --eta 'GDAL_CACHEMAX=10000 GDAL_NUM_THREADS=4 raster2pgsql \-a \-Y \-s 4326 {} \-t auto night_lights_raster | psql \-q'\fR + +.LP +List the raster formats supported by the GDAL library used by raster2pgsql: + +# \fBraster2pgsql \-G\fR + +.SH "AUTHORS" +.LP +Originally written by WKTRaster/PostGIS Raster contributors. +Improved and maintained by the PostGIS project. + +.SH "SEE ALSO" +.LP +shp2pgsql(1), pgsql2shp(1) + +More information is available at http://postgis.net ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + doc/Makefile.in | 3 +- doc/man/raster2pgsql.1 | 171 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 doc/man/raster2pgsql.1 hooks/post-receive -- PostGIS From trac at osgeo.org Fri Jun 19 14:33:21 2026 From: trac at osgeo.org (PostGIS) Date: Fri, 19 Jun 2026 21:33:21 -0000 Subject: [PostGIS] #2386: [raster] raster2pgsql misses man page In-Reply-To: <049.a71bcf3f0930afe5cfd69e569d623fa4@osgeo.org> References: <049.a71bcf3f0930afe5cfd69e569d623fa4@osgeo.org> Message-ID: <064.b264b8686d7fc7d499a72a783d262b7e@osgeo.org> #2386: [raster] raster2pgsql misses man page ----------------------+----------------------------- Reporter: mwanner | Owner: dustymugs Type: defect | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: raster | Version: 2.0.x Resolution: fixed | Keywords: ----------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"7a62d652e3a3ed1402e633a198f8871464c27c35/git" 7a62d652/git]: {{{#!CommitTicketReference repository="git" revision="7a62d652e3a3ed1402e633a198f8871464c27c35" doc: add raster2pgsql man page Install the raster2pgsql(1) manual page and align its examples with the raster loader workflows documented in the main manual. Closes #2386 Closes https://github.com/postgis/postgis/pull/979 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sat Jun 20 05:47:35 2026 From: git at osgeo.org (git at osgeo.org) Date: Sat, 20 Jun 2026 05:47:35 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-630-g6c7ab193e Message-ID: <20260620124735.725AF1C3558@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 6c7ab193ea99ea6dabd5fb05dac9a995f4aa6be4 (commit) from 7a62d652e3a3ed1402e633a198f8871464c27c35 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6c7ab193ea99ea6dabd5fb05dac9a995f4aa6be4 Author: Darafei Praliaskouski Date: Sat Jun 20 16:45:34 2026 +0400 raster2pgsql: avoid padding single-tile overviews Trim overview edge tiles whenever padding is disabled, including the case where the overview fits in one tile. Compute overview tile counts independently for each axis so one matching dimension does not suppress tiling on the other. Add a loader regression that builds a single-tile overview with a larger requested tile size and verifies the generated overview keeps the unpadded dimensions and extent. Closes #2832 Closes https://github.com/postgis/postgis/pull/995 diff --git a/NEWS b/NEWS index a8b25af45..42f7dbaa8 100644 --- a/NEWS +++ b/NEWS @@ -68,6 +68,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Bug Fixes * + - #2832, [raster] Avoid padding single-tile raster2pgsql overviews + when padding is not requested (Darafei Praliaskouski) - Fix WKB and TWKB parser resource exhaustion on malformed input (Darafei Praliaskouski) - #6083, Pass configured dependency include paths to fuzzer smoke builds diff --git a/raster/loader/raster2pgsql.c b/raster/loader/raster2pgsql.c index 68f68b526..e8ddcc478 100644 --- a/raster/loader/raster2pgsql.c +++ b/raster/loader/raster2pgsql.c @@ -1424,13 +1424,10 @@ build_overview(int idx, RTLOADERCFG *config, RASTERINFO *info, uint32_t ovx, STR tile_size[1] = config->tile_size[1]; /* number of tiles */ - if ( - tile_size[0] != dimOv[0] && - tile_size[1] != dimOv[1] - ) { + if (tile_size[0] != dimOv[0]) ntiles[0] = (dimOv[0] + tile_size[0] - 1) / tile_size[0]; - ntiles[1] = (dimOv[1] + tile_size[1] - 1) / tile_size[1]; - } + if (tile_size[1] != dimOv[1]) + ntiles[1] = (dimOv[1] + tile_size[1] - 1) / tile_size[1]; /* working copy of geotransform matrix */ memcpy(gt, gtOv, sizeof(double) * 6); @@ -1440,7 +1437,7 @@ build_overview(int idx, RTLOADERCFG *config, RASTERINFO *info, uint32_t ovx, STR for (ytile = 0; ytile < ntiles[1]; ytile++) { /* edge y tile */ - if (!config->pad_tile && ntiles[1] > 1 && (ytile + 1) == ntiles[1]) + if (!config->pad_tile && (ytile + 1) == ntiles[1]) _tile_size[1] = dimOv[1] - (ytile * tile_size[1]); else _tile_size[1] = tile_size[1]; @@ -1452,7 +1449,7 @@ build_overview(int idx, RTLOADERCFG *config, RASTERINFO *info, uint32_t ovx, STR */ /* edge x tile */ - if (!config->pad_tile && ntiles[0] > 1 && (xtile + 1) == ntiles[0]) + if (!config->pad_tile && (xtile + 1) == ntiles[0]) _tile_size[0] = dimOv[0] - (xtile * tile_size[0]); else _tile_size[0] = tile_size[0]; diff --git a/raster/test/regress/loader/OverviewNoPadding-post.sql b/raster/test/regress/loader/OverviewNoPadding-post.sql new file mode 100644 index 000000000..5739609f6 --- /dev/null +++ b/raster/test/regress/loader/OverviewNoPadding-post.sql @@ -0,0 +1,2 @@ +-- "loadedrast" is removed automatically ! +DROP TABLE o_16_loadedrast; diff --git a/raster/test/regress/loader/OverviewNoPadding.opts b/raster/test/regress/loader/OverviewNoPadding.opts new file mode 100644 index 000000000..e8044640c --- /dev/null +++ b/raster/test/regress/loader/OverviewNoPadding.opts @@ -0,0 +1 @@ +-l 16 -t 256x256 diff --git a/raster/test/regress/loader/OverviewNoPadding.select.expected b/raster/test/regress/loader/OverviewNoPadding.select.expected new file mode 100644 index 000000000..ebb6336f3 --- /dev/null +++ b/raster/test/regress/loader/OverviewNoPadding.select.expected @@ -0,0 +1,3 @@ +1 +6|3 +POLYGON((0 0,96 0,96 -48,0 -48,0 0)) diff --git a/raster/test/regress/loader/OverviewNoPadding.select.sql b/raster/test/regress/loader/OverviewNoPadding.select.sql new file mode 100644 index 000000000..1ba47a441 --- /dev/null +++ b/raster/test/regress/loader/OverviewNoPadding.select.sql @@ -0,0 +1,3 @@ +SELECT count(*) FROM o_16_loadedrast; +SELECT ST_Width(rast), ST_Height(rast) FROM o_16_loadedrast; +SELECT ST_AsText(ST_Envelope(rast)) FROM o_16_loadedrast; diff --git a/raster/test/regress/loader/OverviewNoPadding.tif.ref b/raster/test/regress/loader/OverviewNoPadding.tif.ref new file mode 100644 index 000000000..1e1cc0fc8 --- /dev/null +++ b/raster/test/regress/loader/OverviewNoPadding.tif.ref @@ -0,0 +1 @@ +testraster.tif diff --git a/raster/test/regress/tests.mk.in b/raster/test/regress/tests.mk.in index 111be04e7..996f26583 100644 --- a/raster/test/regress/tests.mk.in +++ b/raster/test/regress/tests.mk.in @@ -130,6 +130,7 @@ RASTER_TEST_BUGS = \ RASTER_TEST_LOADER = \ $(top_srcdir)/raster/test/regress/loader/Basic \ $(top_srcdir)/raster/test/regress/loader/Projected \ + $(top_srcdir)/raster/test/regress/loader/OverviewNoPadding \ $(top_srcdir)/raster/test/regress/loader/BasicCopy \ $(top_srcdir)/raster/test/regress/loader/BasicFilename \ $(top_srcdir)/raster/test/regress/loader/BasicOutDB \ ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ raster/loader/raster2pgsql.c | 13 +++++-------- .../{Projected-post.sql => OverviewNoPadding-post.sql} | 2 +- raster/test/regress/loader/OverviewNoPadding.opts | 1 + .../test/regress/loader/OverviewNoPadding.select.expected | 3 +++ raster/test/regress/loader/OverviewNoPadding.select.sql | 3 +++ .../loader/{Basic.tif.ref => OverviewNoPadding.tif.ref} | 0 raster/test/regress/tests.mk.in | 1 + 8 files changed, 16 insertions(+), 9 deletions(-) copy raster/test/regress/loader/{Projected-post.sql => OverviewNoPadding-post.sql} (60%) create mode 100644 raster/test/regress/loader/OverviewNoPadding.opts create mode 100644 raster/test/regress/loader/OverviewNoPadding.select.expected create mode 100644 raster/test/regress/loader/OverviewNoPadding.select.sql copy raster/test/regress/loader/{Basic.tif.ref => OverviewNoPadding.tif.ref} (100%) hooks/post-receive -- PostGIS From trac at osgeo.org Sat Jun 20 05:47:36 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 12:47:36 -0000 Subject: [PostGIS] #2832: [raster] raster2pgsql pads overviews with single tiles In-Reply-To: <046.0f7875322653f25dd79166d5196b29be@osgeo.org> References: <046.0f7875322653f25dd79166d5196b29be@osgeo.org> Message-ID: <061.5c3018f634e461bf82bfe2c59f2e8cad@osgeo.org> #2832: [raster] raster2pgsql pads overviews with single tiles ---------------------+----------------------------- Reporter: strk | Owner: dustymugs Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: master Resolution: fixed | Keywords: ---------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"6c7ab193ea99ea6dabd5fb05dac9a995f4aa6be4/git" 6c7ab193/git]: {{{#!CommitTicketReference repository="git" revision="6c7ab193ea99ea6dabd5fb05dac9a995f4aa6be4" raster2pgsql: avoid padding single-tile overviews Trim overview edge tiles whenever padding is disabled, including the case where the overview fits in one tile. Compute overview tile counts independently for each axis so one matching dimension does not suppress tiling on the other. Add a loader regression that builds a single-tile overview with a larger requested tile size and verifies the generated overview keeps the unpadded dimensions and extent. Closes #2832 Closes https://github.com/postgis/postgis/pull/995 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sat Jun 20 06:05:36 2026 From: git at osgeo.org (git at osgeo.org) Date: Sat, 20 Jun 2026 06:05:36 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-631-g177963ca6 Message-ID: <20260620130536.3C3BD1C43A8@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 177963ca6c91740aea1ab0000637017f9ad5dda5 (commit) from 6c7ab193ea99ea6dabd5fb05dac9a995f4aa6be4 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 177963ca6c91740aea1ab0000637017f9ad5dda5 Author: Darafei Praliaskouski Date: Sat Jun 20 17:03:54 2026 +0400 loader: test index creation during data loads Enable index creation in existing shapefile and raster loader regression fixtures, and verify the resulting GiST indexes after the loads complete. Pin the shapefile loader SQL so the regression also covers the unnamed CREATE INDEX form. Closes #2820 Closes https://github.com/postgis/postgis/pull/994 diff --git a/raster/test/regress/loader/Basic.opts b/raster/test/regress/loader/Basic.opts index d51cca218..d02bb6a13 100644 --- a/raster/test/regress/loader/Basic.opts +++ b/raster/test/regress/loader/Basic.opts @@ -1 +1 @@ --C +-I -C diff --git a/raster/test/regress/loader/Basic.select.expected b/raster/test/regress/loader/Basic.select.expected index 484721c35..0e7dc191e 100644 --- a/raster/test/regress/loader/Basic.select.expected +++ b/raster/test/regress/loader/Basic.select.expected @@ -2,3 +2,4 @@ POLYGON((0 0,1 0,1 -1,0 -1,0 0))|255 POLYGON((89 -49,90 -49,90 -50,89 -50,89 -49))|0 POLYGON((44 -24,45 -24,45 -25,44 -25,44 -24))|0 +1 diff --git a/raster/test/regress/loader/Basic.select.sql b/raster/test/regress/loader/Basic.select.sql index bc0434c08..a412b8314 100644 --- a/raster/test/regress/loader/Basic.select.sql +++ b/raster/test/regress/loader/Basic.select.sql @@ -2,3 +2,8 @@ SELECT srid, scale_x::numeric(16, 10), scale_y::numeric(16, 10), blocksize_x, bl SELECT ST_AsEWKT(geom), val FROM (SELECT (ST_PixelAsPolygons(rast, 1)).* FROM loadedrast WHERE rid = 1) foo WHERE x = 1 AND y = 1; SELECT ST_AsEWKT(geom), val FROM (SELECT (ST_PixelAsPolygons(rast, 2)).* FROM loadedrast WHERE rid = 1) foo WHERE x = 90 AND y = 50; SELECT ST_AsEWKT(geom), val FROM (SELECT (ST_PixelAsPolygons(rast, 3)).* FROM loadedrast WHERE rid = 1) foo WHERE x = 45 AND y = 25; +SELECT COUNT(*) +FROM pg_indexes +WHERE schemaname = 'public' + AND tablename = 'loadedrast' + AND indexdef LIKE 'CREATE INDEX % ON public.loadedrast USING gist (st_convexhull(rast))'; diff --git a/regress/loader/TestANALYZE.opts b/regress/loader/TestANALYZE.opts index d82cb4c58..c865f6dca 100644 --- a/regress/loader/TestANALYZE.opts +++ b/regress/loader/TestANALYZE.opts @@ -1,2 +1,2 @@ -# Test with ANALYZE --g the_geom {regdir}/loader/TestSkipANALYZE loadedshp +# Test with ANALYZE and index creation +-I -g the_geom {regdir}/loader/TestSkipANALYZE loadedshp diff --git a/regress/loader/TestANALYZE.select.expected b/regress/loader/TestANALYZE.select.expected index d00491fd7..6ed281c75 100644 --- a/regress/loader/TestANALYZE.select.expected +++ b/regress/loader/TestANALYZE.select.expected @@ -1 +1,2 @@ 1 +1 diff --git a/regress/loader/TestANALYZE.select.sql b/regress/loader/TestANALYZE.select.sql index de569878f..90227e331 100644 --- a/regress/loader/TestANALYZE.select.sql +++ b/regress/loader/TestANALYZE.select.sql @@ -2,3 +2,8 @@ SELECT COUNT(stanumbers1) FROM pg_statistic WHERE starelid = 'public.loadedshp'::regclass AND stanumbers1 IS NOT NULL; +SELECT COUNT(*) +FROM pg_indexes +WHERE schemaname = 'public' + AND tablename = 'loadedshp' + AND indexdef LIKE 'CREATE INDEX % ON public.loadedshp USING gist (the_geom)'; diff --git a/regress/loader/TestANALYZE.sql.expected b/regress/loader/TestANALYZE.sql.expected new file mode 100644 index 000000000..fe56dd4b1 --- /dev/null +++ b/regress/loader/TestANALYZE.sql.expected @@ -0,0 +1,12 @@ +SET CLIENT_ENCODING TO UTF8; +SET STANDARD_CONFORMING_STRINGS TO ON; +BEGIN; +CREATE TABLE "loadedshp" (gid serial); +ALTER TABLE "loadedshp" ADD PRIMARY KEY (gid); +SELECT AddGeometryColumn('','loadedshp','the_geom','0','POINT',2); +INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000000000000000000000F03F'); +INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000002240000000000000F0BF'); +INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000002240000000000000F0BF'); +CREATE INDEX ON "loadedshp" USING GIST ("the_geom"); +COMMIT; +ANALYZE "loadedshp"; ----------------------------------------------------------------------- Summary of changes: raster/test/regress/loader/Basic.opts | 2 +- raster/test/regress/loader/Basic.select.expected | 1 + raster/test/regress/loader/Basic.select.sql | 5 +++++ regress/loader/TestANALYZE.opts | 4 ++-- regress/loader/TestANALYZE.select.expected | 1 + regress/loader/TestANALYZE.select.sql | 5 +++++ regress/loader/TestANALYZE.sql.expected | 12 ++++++++++++ 7 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 regress/loader/TestANALYZE.sql.expected hooks/post-receive -- PostGIS From trac at osgeo.org Sat Jun 20 06:05:37 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 13:05:37 -0000 Subject: [PostGIS] #2820: Add automated tests for index creation at loading time In-Reply-To: <046.9cbd969f87141e9164bbf0d32c5951c8@osgeo.org> References: <046.9cbd969f87141e9164bbf0d32c5951c8@osgeo.org> Message-ID: <061.4e60305ba51ee4ac69b10352540bcb64@osgeo.org> #2820: Add automated tests for index creation at loading time ---------------------------+----------------------------- Reporter: strk | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: QA/testsuite | Version: 2.1.x Resolution: fixed | Keywords: ---------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"177963ca6c91740aea1ab0000637017f9ad5dda5/git" 177963c/git]: {{{#!CommitTicketReference repository="git" revision="177963ca6c91740aea1ab0000637017f9ad5dda5" loader: test index creation during data loads Enable index creation in existing shapefile and raster loader regression fixtures, and verify the resulting GiST indexes after the loads complete. Pin the shapefile loader SQL so the regression also covers the unnamed CREATE INDEX form. Closes #2820 Closes https://github.com/postgis/postgis/pull/994 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sat Jun 20 11:16:43 2026 From: git at osgeo.org (git at osgeo.org) Date: Sat, 20 Jun 2026 11:16:43 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-633-g6ce331f4e Message-ID: <20260620181643.EDC931C6DC2@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 6ce331f4e2bfd2054f56ba09c43907621259bffc (commit) via 4ec0a1dd0a311af57c593656637f5c98ac7a1799 (commit) from 177963ca6c91740aea1ab0000637017f9ad5dda5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6ce331f4e2bfd2054f56ba09c43907621259bffc Author: Darafei Praliaskouski Date: Sat Jun 20 21:47:07 2026 +0400 Add raster2pgsql --if-not-exists modifier Add a loader modifier that emits CREATE TABLE IF NOT EXISTS in create and prepare modes, allowing -c --if-not-exists to create a missing target table or continue loading into an existing compatible table. Represent the short operation modes as explicit internal actions for dropping tables, creating tables, loading data, and creating indexes. When -I is used with --if-not-exists, emit CREATE INDEX IF NOT EXISTS with stable loader index names; plain -I keeps its existing create-index behavior. Closes #4659 Closes https://github.com/postgis/postgis/pull/1000 diff --git a/NEWS b/NEWS index 52fafcd05..e668c7a62 100644 --- a/NEWS +++ b/NEWS @@ -63,6 +63,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed (Sandro Santilli) - #3743, [raster] Document and test raster2pgsql -s FROM_SRID:SRID reprojection support (Darafei Praliaskouski) + - #4659, [raster] Add raster2pgsql --if-not-exists creation modifier + (Darafei Praliaskouski) - #4749, Use point-in-polygon predicate fast paths for point-only GeometryCollections (Darafei Praliaskouski) - #5532, Validate the manual against DocBook XMLSchema in check-xml diff --git a/doc/man/raster2pgsql.1 b/doc/man/raster2pgsql.1 index f33b9c504..10adc8d9e 100644 --- a/doc/man/raster2pgsql.1 +++ b/doc/man/raster2pgsql.1 @@ -54,6 +54,11 @@ Create a new table and populate it. This is the default mode. \fB\-p\fR Prepare mode. Only emit SQL to create the table. .TP +\fB\-\-if\-not\-exists\fR +Use IF NOT EXISTS for table creation in \-c and \-p modes. When \-I is also +specified, use IF NOT EXISTS for index creation too. This option cannot be used +with \-a or \-d. +.TP \fB\-f\fR <\fIcolumn\fR> Specify the name of the raster column. .TP diff --git a/doc/using_raster_dataman.xml b/doc/using_raster_dataman.xml index 2f8773895..64973efc0 100644 --- a/doc/using_raster_dataman.xml +++ b/doc/using_raster_dataman.xml @@ -137,6 +137,20 @@ Available GDAL raster formats: + + + + + Use IF NOT EXISTS for table creation in + and modes. When + is also specified, use + IF NOT EXISTS for index creation too. This + option cannot be used with or + . + + + + Raster processing: Applying constraints for proper registering in raster catalogs diff --git a/raster/loader/raster2pgsql.c b/raster/loader/raster2pgsql.c index e8ddcc478..85508bb67 100644 --- a/raster/loader/raster2pgsql.c +++ b/raster/loader/raster2pgsql.c @@ -371,16 +371,18 @@ usage() { " -R Register the raster as an out-of-db (filesystem) raster. Provided\n" " raster should have absolute path to the file\n" )); - printf(_( - " (-d|a|c|p) These are mutually exclusive options:\n" - " -d Drops the table, then recreates it and populates\n" - " it with current raster data.\n" - " -a Appends raster into current table, must be\n" - " exactly the same table schema.\n" - " -c Creates a new table and populates it, this is the\n" - " default if you do not specify any options.\n" - " -p Prepare mode, only creates the table.\n" - )); + printf( + _(" (-d|a|c|p) These are mutually exclusive options:\n" + " -d Drops the table, then recreates it and populates\n" + " it with current raster data.\n" + " -a Appends raster into current table, must be\n" + " exactly the same table schema.\n" + " -c Creates a new table and populates it, this is the\n" + " default if you do not specify any options.\n" + " -p Prepare mode, only creates the table.\n")); + printf( + _(" --if-not-exists Use IF NOT EXISTS for table creation in -c and -p\n" + " modes. With -I, also use IF NOT EXISTS for index creation.\n")); printf(_( " -f Specify the name of the raster column\n" )); @@ -690,7 +692,11 @@ init_config(RTLOADERCFG *config) { config->pad_tile = 0; config->outdb = 0; config->opt = 'c'; - config->idx = 0; + config->if_not_exists = 0; + config->drop_table = 0; + config->create_table = CREATE_TABLE_ALWAYS; + config->load_data = 1; + config->create_index = CREATE_INDEX_NONE; config->maintenance = 0; config->constraints = 0; config->max_extent = 1; @@ -707,6 +713,52 @@ init_config(RTLOADERCFG *config) { config->max_tiles_per_copy = 50; } +static int +apply_action_presets(RTLOADERCFG *config) +{ + config->drop_table = 0; + config->create_table = CREATE_TABLE_NONE; + config->load_data = 0; + + switch (config->opt) + { + case 'd': + config->drop_table = 1; + config->create_table = CREATE_TABLE_ALWAYS; + config->load_data = 1; + break; + case 'a': + config->load_data = 1; + break; + case 'c': + config->create_table = CREATE_TABLE_ALWAYS; + config->load_data = 1; + break; + case 'p': + config->create_table = CREATE_TABLE_ALWAYS; + break; + default: + rterror(_("Unknown loader operation: -%c"), config->opt); + return 0; + } + + if (config->if_not_exists) + { + if (config->opt == 'd' || config->opt == 'a') + { + rterror(_("--if-not-exists can only modify create and prepare modes")); + return 0; + } + + if (config->create_table == CREATE_TABLE_ALWAYS) + config->create_table = CREATE_TABLE_IF_NOT_EXISTS; + if (config->create_index == CREATE_INDEX_ALWAYS) + config->create_index = CREATE_INDEX_IF_NOT_EXISTS; + } + + return 1; +} + static void rtdealloc_config(RTLOADERCFG *config) { int i = 0; @@ -1000,19 +1052,23 @@ drop_table(const char *schema, const char *table, STRINGBUFFER *buffer) { } static int -create_table( - const char *schema, const char *table, const char *column, - const int file_column, const char *file_column_name, - const char *tablespace, const char *idx_tablespace, - STRINGBUFFER *buffer -) { +create_table(const char *schema, + const char *table, + const char *column, + const int file_column, + const char *file_column_name, + const char *tablespace, + const char *idx_tablespace, + int if_not_exists, + STRINGBUFFER *buffer) +{ char *sql = NULL; uint32_t len = 0; assert(table != NULL); assert(column != NULL); - len = strlen("CREATE TABLE (\"rid\" serial PRIMARY KEY, raster);") + 1; + len = strlen("CREATE TABLE IF NOT EXISTS (\"rid\" serial PRIMARY KEY, raster);") + 1; if (schema != NULL) len += strlen(schema); len += strlen(table); @@ -1029,7 +1085,9 @@ create_table( rterror(_("create_table: Could not allocate memory for CREATE TABLE statement")); return 0; } - sprintf(sql, "CREATE TABLE %s%s (\"rid\" serial PRIMARY KEY%s%s,%s raster%s%s%s)%s%s;", + sprintf(sql, + "CREATE TABLE %s%s%s (\"rid\" serial PRIMARY KEY%s%s,%s raster%s%s%s)%s%s;", + (if_not_exists ? "IF NOT EXISTS " : ""), (schema != NULL ? schema : ""), table, (idx_tablespace != NULL ? " USING INDEX TABLESPACE " : ""), @@ -1039,8 +1097,7 @@ create_table( (file_column ? file_column_name : ""), (file_column ? " text" : ""), (tablespace != NULL ? " TABLESPACE " : ""), - (tablespace != NULL ? tablespace : "") - ); + (tablespace != NULL ? tablespace : "")); append_sql_to_buffer(buffer, sql); @@ -1048,11 +1105,13 @@ create_table( } static int -create_index( - const char *schema, const char *table, const char *column, - const char *tablespace, - STRINGBUFFER *buffer -) { +create_index(const char *schema, + const char *table, + const char *column, + const char *tablespace, + int if_not_exists, + STRINGBUFFER *buffer) +{ char *sql = NULL; uint32_t len = 0; char *_table = NULL; @@ -1065,7 +1124,7 @@ create_index( _column = chartrim(column, "\""); /* create index */ - len = strlen("CREATE INDEX \"__gist\" ON USING gist (st_convexhull());") + 1; + len = strlen("CREATE INDEX IF NOT EXISTS \"__gist\" ON USING gist (st_convexhull());") + 1; if (schema != NULL) len += strlen(schema); len += strlen(_table); @@ -1082,13 +1141,28 @@ create_index( rtdealloc(_column); return 0; } - sprintf(sql, "CREATE INDEX ON %s%s USING gist (st_convexhull(%s))%s%s;", - (schema != NULL ? schema : ""), - table, - column, - (tablespace != NULL ? " TABLESPACE " : ""), - (tablespace != NULL ? tablespace : "") - ); + if (if_not_exists) + { + sprintf(sql, + "CREATE INDEX IF NOT EXISTS \"%s_%s_gist\" ON %s%s USING gist (st_convexhull(%s))%s%s;", + _table, + _column, + (schema != NULL ? schema : ""), + table, + column, + (tablespace != NULL ? " TABLESPACE " : ""), + (tablespace != NULL ? tablespace : "")); + } + else + { + sprintf(sql, + "CREATE INDEX ON %s%s USING gist (st_convexhull(%s))%s%s;", + (schema != NULL ? schema : ""), + table, + column, + (tablespace != NULL ? " TABLESPACE " : ""), + (tablespace != NULL ? tablespace : "")); + } rtdealloc(_table); rtdealloc(_column); @@ -2006,7 +2080,8 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* drop table */ - if (config->opt == 'd') { + if (config->drop_table) + { if (!drop_table(config->schema, config->table, buffer)) { rterror(_("process_rasters: Could not add DROP TABLE statement to string buffer")); return 0; @@ -2023,25 +2098,34 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* create table */ - if (config->opt != 'a') { - if (!create_table( - config->schema, config->table, config->raster_column, - config->file_column, config->file_column_name, - config->tablespace, config->idx_tablespace, - buffer - )) { + if (config->create_table != CREATE_TABLE_NONE) + { + if (!create_table(config->schema, + config->table, + config->raster_column, + config->file_column, + config->file_column_name, + config->tablespace, + config->idx_tablespace, + config->create_table == CREATE_TABLE_IF_NOT_EXISTS, + buffer)) + { rterror(_("process_rasters: Could not add CREATE TABLE statement to string buffer")); return 0; } if (config->overview_count) { for (i = 0; i < config->overview_count; i++) { - if (!create_table( - config->schema, config->overview_table[i], config->raster_column, - config->file_column, config->file_column_name, - config->tablespace, config->idx_tablespace, - buffer - )) { + if (!create_table(config->schema, + config->overview_table[i], + config->raster_column, + config->file_column, + config->file_column_name, + config->tablespace, + config->idx_tablespace, + config->create_table == CREATE_TABLE_IF_NOT_EXISTS, + buffer)) + { rterror(_("process_rasters: Could not add an overview's CREATE TABLE statement to string buffer")); return 0; } @@ -2049,8 +2133,9 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } } - /* no need to run if opt is 'p' */ - if (config->opt != 'p') { + /* no need to load data in prepare mode */ + if (config->load_data) + { RASTERINFO refinfo; init_rastinfo(&refinfo); @@ -2138,19 +2223,23 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* index */ - if (config->idx) { + if (config->create_index != CREATE_INDEX_NONE) + { /* create index */ - if (!create_index( - config->schema, config->table, config->raster_column, - config->idx_tablespace, - buffer - )) { + if (!create_index(config->schema, + config->table, + config->raster_column, + config->idx_tablespace, + config->create_index == CREATE_INDEX_IF_NOT_EXISTS, + buffer)) + { rterror(_("process_rasters: Could not add CREATE INDEX statement to string buffer")); return 0; } /* analyze */ - if (config->opt != 'p') { + if (config->load_data) + { if (!analyze_table( config->schema, config->table, buffer @@ -2163,17 +2252,20 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { if (config->overview_count) { for (i = 0; i < config->overview_count; i++) { /* create index */ - if (!create_index( - config->schema, config->overview_table[i], config->raster_column, - config->idx_tablespace, - buffer - )) { + if (!create_index(config->schema, + config->overview_table[i], + config->raster_column, + config->idx_tablespace, + config->create_index == CREATE_INDEX_IF_NOT_EXISTS, + buffer)) + { rterror(_("process_rasters: Could not add an overview's CREATE INDEX statement to string buffer")); return 0; } /* analyze */ - if (config->opt != 'p') { + if (config->load_data) + { if (!analyze_table( config->schema, config->overview_table[i], buffer @@ -2234,7 +2326,8 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* maintenance */ - if (config->opt != 'p' && config->maintenance) { + if (config->load_data && config->maintenance) + { if (!vacuum_table( config->schema, config->table, buffer @@ -2254,7 +2347,6 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } } } - } return 1; @@ -2464,6 +2556,11 @@ main(int argc, char **argv) { else if (CSEQUAL(argv[argit], "-p")) { config->opt = 'p'; } + /* make creation statements idempotent */ + else if (CSEQUAL(argv[argit], "--if-not-exists")) + { + config->if_not_exists = 1; + } /* raster column name */ else if (CSEQUAL(argv[argit], "-f") && argit < argc - 1) { const size_t len = (strlen(argv[++argit]) + 1); @@ -2531,7 +2628,7 @@ main(int argc, char **argv) { } /* create index */ else if (CSEQUAL(argv[argit], "-I")) { - config->idx = 1; + config->create_index = CREATE_INDEX_ALWAYS; } /* maintenance */ else if (CSEQUAL(argv[argit], "-M")) { @@ -2664,6 +2761,12 @@ main(int argc, char **argv) { } } + if (!apply_action_presets(config)) + { + rtdealloc_config(config); + exit(1); + } + /* register GDAL drivers */ GDALAllRegister(); diff --git a/raster/loader/raster2pgsql.h b/raster/loader/raster2pgsql.h index 8a5cbb195..96f674191 100644 --- a/raster/loader/raster2pgsql.h +++ b/raster/loader/raster2pgsql.h @@ -69,6 +69,20 @@ #define RCSID "$Id$" +typedef enum raster_loader_create_table_action +{ + CREATE_TABLE_NONE = 0, + CREATE_TABLE_ALWAYS, + CREATE_TABLE_IF_NOT_EXISTS +} CREATE_TABLE_ACTION; + +typedef enum raster_loader_create_index_action +{ + CREATE_INDEX_NONE = 0, + CREATE_INDEX_ALWAYS, + CREATE_INDEX_IF_NOT_EXISTS +} CREATE_INDEX_ACTION; + typedef struct raster_loader_config { /* raster filename */ uint32_t rt_file_count; @@ -118,8 +132,14 @@ typedef struct raster_loader_config { /* type of operation, (d|a|c|p) */ char opt; - /* create index, 1 = yes, 0 = no (default) */ - int idx; + /* make creation actions idempotent */ + int if_not_exists; + + /* actions derived from operation presets */ + int drop_table; + CREATE_TABLE_ACTION create_table; + int load_data; + CREATE_INDEX_ACTION create_index; /* maintenance statements, 1 = yes, 0 = no (default) */ int maintenance; diff --git a/raster/test/regress/loader/IfNotExists-pre.sql b/raster/test/regress/loader/IfNotExists-pre.sql new file mode 100644 index 000000000..76dd4370d --- /dev/null +++ b/raster/test/regress/loader/IfNotExists-pre.sql @@ -0,0 +1,3 @@ +DROP TABLE IF EXISTS loadedrast; +CREATE TABLE loadedrast ("rid" serial PRIMARY KEY, rast raster); +CREATE INDEX loadedrast_rast_gist ON loadedrast USING gist (st_convexhull(rast)); diff --git a/raster/test/regress/loader/IfNotExists.opts b/raster/test/regress/loader/IfNotExists.opts new file mode 100644 index 000000000..5189c54d2 --- /dev/null +++ b/raster/test/regress/loader/IfNotExists.opts @@ -0,0 +1 @@ +-c --if-not-exists -I diff --git a/raster/test/regress/loader/IfNotExists.select.expected b/raster/test/regress/loader/IfNotExists.select.expected new file mode 100644 index 000000000..47e5ca813 --- /dev/null +++ b/raster/test/regress/loader/IfNotExists.select.expected @@ -0,0 +1,4 @@ +1 +90|50|3 +255 +1 diff --git a/raster/test/regress/loader/IfNotExists.select.sql b/raster/test/regress/loader/IfNotExists.select.sql new file mode 100644 index 000000000..0ffca6a0a --- /dev/null +++ b/raster/test/regress/loader/IfNotExists.select.sql @@ -0,0 +1,8 @@ +SELECT count(*) FROM loadedrast; +SELECT ST_Width(rast), ST_Height(rast), ST_NumBands(rast) FROM loadedrast WHERE rid = 1; +SELECT ST_Value(rast, 1, 1, 1) FROM loadedrast WHERE rid = 1; +SELECT COUNT(*) +FROM pg_indexes +WHERE schemaname = 'public' + AND tablename = 'loadedrast' + AND indexdef LIKE 'CREATE INDEX loadedrast_rast_gist ON public.loadedrast USING gist (st_convexhull(rast))'; diff --git a/raster/test/regress/loader/IfNotExists.tif.ref b/raster/test/regress/loader/IfNotExists.tif.ref new file mode 100644 index 000000000..1e1cc0fc8 --- /dev/null +++ b/raster/test/regress/loader/IfNotExists.tif.ref @@ -0,0 +1 @@ +testraster.tif diff --git a/raster/test/regress/tests.mk.in b/raster/test/regress/tests.mk.in index 996f26583..8fa0cf6d2 100644 --- a/raster/test/regress/tests.mk.in +++ b/raster/test/regress/tests.mk.in @@ -131,6 +131,7 @@ RASTER_TEST_LOADER = \ $(top_srcdir)/raster/test/regress/loader/Basic \ $(top_srcdir)/raster/test/regress/loader/Projected \ $(top_srcdir)/raster/test/regress/loader/OverviewNoPadding \ + $(top_srcdir)/raster/test/regress/loader/IfNotExists \ $(top_srcdir)/raster/test/regress/loader/BasicCopy \ $(top_srcdir)/raster/test/regress/loader/BasicFilename \ $(top_srcdir)/raster/test/regress/loader/BasicOutDB \ commit 4ec0a1dd0a311af57c593656637f5c98ac7a1799 Author: Darafei Praliaskouski Date: Sat Jun 20 17:16:59 2026 +0400 Improve raster MapAlgebra callback arity handling Allow n-raster ST_MapAlgebra callbacks to omit the variadic userargs parameter, matching the existing callback arity flexibility in adjacent MapAlgebra variants. Size raster MapAlgebra FunctionCallInfo storage to the callback arities used instead of allocating FUNC_MAX_ARGS slots. Track the owned empty userargs array used for strict three-argument callbacks so it can be released with the MapAlgebra argument state. Closes #2804 Closes #4315 Closes https://github.com/postgis/postgis/pull/1035 diff --git a/NEWS b/NEWS index 42f7dbaa8..52fafcd05 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Enhancements * + - #2804, #4315, [raster] Support two-argument ST_MapAlgebra callbacks + and pass callback call data as actual arguments (Darafei Praliaskouski) - #2898, Document SQL function cost tiers for contributors (Darafei Praliaskouski) - #6062, [topology] Stop using recursive snapping, for improved robustness (Sandro Santilli) diff --git a/doc/reference_raster.xml b/doc/reference_raster.xml index 3ddd3e373..04d059ffc 100644 --- a/doc/reference_raster.xml +++ b/doc/reference_raster.xml @@ -10276,7 +10276,7 @@ CREATE OR REPLACE FUNCTION sample_callbackfunc(value double precision[][][], pos - The callbackfunc must have three arguments: a 3-dimension double precision array, a 2-dimension integer array and a variadic 1-dimension text array. The first argument value is the set of values (as double precision) from all input rasters. The three dimensions (where indexes are 1-based) are: raster #, row y, column x. The second argument position is the set of pixel positions from the output raster and input rasters. The outer dimension (where indexes are 0-based) is the raster #. The position at outer dimension index 0 is the output raster's pixel position. For each outer dimension, there are two elements in the inner dimension for X and Y. The third argument userargs is for passing through any user-specified arguments. + The callbackfunc must have two or three arguments: a 3-dimension double precision array, a 2-dimension integer array and, optionally, a variadic 1-dimension text array. The first argument value is the set of values (as double precision) from all input rasters. The three dimensions (where indexes are 1-based) are: raster #, row y, column x. The second argument position is the set of pixel positions from the output raster and input rasters. The outer dimension (where indexes are 0-based) is the raster #. The position at outer dimension index 0 is the output raster's pixel position. For each outer dimension, there are two elements in the inner dimension for X and Y. The optional third argument userargs is for passing through any user-specified arguments. @@ -10364,7 +10364,7 @@ CREATE OR REPLACE FUNCTION sample_callbackfunc(value double precision[][][], pos userargs - The third argument to the callbackfunc is a variadic text array. All trailing text arguments are passed through to the specified callbackfunc, and are contained in the userargs argument. + If the callbackfunc declares a third argument, that argument is a variadic text array. All trailing text arguments are passed through to the specified callbackfunc, and are contained in the userargs argument. @@ -10376,12 +10376,6 @@ CREATE OR REPLACE FUNCTION sample_callbackfunc(value double precision[][][], pos - - - The text[] argument to the callbackfunc is required, regardless of whether you choose to pass any arguments to the callback function for processing or not. - - - Variant 1 accepts an array of rastbandarg allowing the use of a map algebra operation on many rasters and/or many bands. See example Variant 1. diff --git a/raster/rt_pg/rtpg_mapalgebra.c b/raster/rt_pg/rtpg_mapalgebra.c index ba34e6323..f2109a30d 100644 --- a/raster/rt_pg/rtpg_mapalgebra.c +++ b/raster/rt_pg/rtpg_mapalgebra.c @@ -91,9 +91,10 @@ typedef struct { /* copied from LOCAL_FCINFO in fmgr.h */ union { FunctionCallInfoBaseData fcinfo; - char fcinfo_data[SizeForFunctionCallInfo(FUNC_MAX_ARGS)]; /* Could be optimized */ + char fcinfo_data[SizeForFunctionCallInfo(3)]; } ufc_info_data; FunctionCallInfo ufc_info; + ArrayType *empty_userargs; } rtpg_nmapalgebra_callback_arg; #if defined(__clang__) @@ -157,6 +158,7 @@ static rtpg_nmapalgebra_arg rtpg_nmapalgebra_arg_init(void) { arg->callback.ufc_noid = InvalidOid; arg->callback.ufc_rettype = InvalidOid; + arg->callback.empty_userargs = NULL; return arg; } @@ -183,6 +185,8 @@ static void rtpg_nmapalgebra_arg_destroy(rtpg_nmapalgebra_arg arg) { rt_raster_destroy(arg->cextent); if( arg->mask != NULL ) pfree(arg->mask); + if (arg->callback.empty_userargs != NULL) + pfree(arg->callback.empty_userargs); pfree(arg); } @@ -803,7 +807,8 @@ Datum RASTER_nMapAlgebra(PG_FUNCTION_ARGS) noerr = 1; } /* function should have correct # of args */ - else if (arg->callback.ufl_info.fn_nargs != 3) { + else if (arg->callback.ufl_info.fn_nargs < 2 || arg->callback.ufl_info.fn_nargs > 3) + { noerr = 2; } @@ -842,7 +847,9 @@ Datum RASTER_nMapAlgebra(PG_FUNCTION_ARGS) elog(ERROR, "RASTER_nMapAlgebra: Function provided must return scalar (double precision, float, int, smallint)"); break; case 2: - elog(ERROR, "RASTER_nMapAlgebra: Function provided must have three input parameters"); + elog( + ERROR, + "RASTER_nMapAlgebra: Function provided must have two or three input parameters"); break; case 1: elog(ERROR, "RASTER_nMapAlgebra: Function provided must return double precision, not resultset"); @@ -864,20 +871,26 @@ Datum RASTER_nMapAlgebra(PG_FUNCTION_ARGS) arg->callback.ufc_info->args[0].isnull = FALSE; arg->callback.ufc_info->args[1].isnull = FALSE; - arg->callback.ufc_info->args[2].isnull = FALSE; - /* userargs (7) */ - if (!PG_ARGISNULL(9)) - arg->callback.ufc_info->args[2].value = PG_GETARG_DATUM(9); - else { - if (arg->callback.ufl_info.fn_strict) { - /* build and assign an empty TEXT array */ - /* TODO: manually free the empty array? */ - arg->callback.ufc_info->args[2].value = PointerGetDatum(construct_empty_array(TEXTOID)); - arg->callback.ufc_info->args[2].isnull = FALSE; - } - else { - arg->callback.ufc_info->args[2].value = (Datum)NULL; - arg->callback.ufc_info->args[2].isnull = TRUE; + if (arg->callback.ufl_info.fn_nargs == 3) + { + arg->callback.ufc_info->args[2].isnull = FALSE; + /* userargs (7) */ + if (!PG_ARGISNULL(9)) + arg->callback.ufc_info->args[2].value = PG_GETARG_DATUM(9); + else + { + if (arg->callback.ufl_info.fn_strict) + { + arg->callback.empty_userargs = construct_empty_array(TEXTOID); + arg->callback.ufc_info->args[2].value = + PointerGetDatum(arg->callback.empty_userargs); + arg->callback.ufc_info->args[2].isnull = FALSE; + } + else + { + arg->callback.ufc_info->args[2].value = (Datum)NULL; + arg->callback.ufc_info->args[2].isnull = TRUE; + } } } } @@ -5280,7 +5293,7 @@ Datum RASTER_mapAlgebraFct(PG_FUNCTION_ARGS) int ret = -1; Oid oid; FmgrInfo cbinfo; - LOCAL_FCINFO(cbdata, FUNC_MAX_ARGS); /* Could be optimized */ + LOCAL_FCINFO(cbdata, 3); Datum tmpnewval; char * strFromText = NULL; @@ -5521,11 +5534,12 @@ Datum RASTER_mapAlgebraFct(PG_FUNCTION_ARGS) } /* prep function call data */ - InitFunctionCallInfoData(*cbdata, &cbinfo, 2, InvalidOid, NULL, NULL); + InitFunctionCallInfoData(*cbdata, &cbinfo, cbinfo.fn_nargs, InvalidOid, NULL, NULL); cbdata->args[0].isnull = FALSE; cbdata->args[1].isnull = FALSE; - cbdata->args[2].isnull = FALSE; + if (cbinfo.fn_nargs == 3) + cbdata->args[2].isnull = FALSE; /* check that the function isn't strict if the args are null. */ if (PG_ARGISNULL(4)) { @@ -5706,7 +5720,7 @@ Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS) int ret = -1; Oid oid; FmgrInfo cbinfo; - LOCAL_FCINFO(cbdata, FUNC_MAX_ARGS); /* Could be optimized */ + LOCAL_FCINFO(cbdata, 3); Datum tmpnewval; ArrayType * neighborDatum; char * strFromText = NULL; @@ -5953,7 +5967,7 @@ Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS) } /* prep function call data */ - InitFunctionCallInfoData(*cbdata, &cbinfo, 3, InvalidOid, NULL, NULL); + InitFunctionCallInfoData(*cbdata, &cbinfo, cbinfo.fn_nargs, InvalidOid, NULL, NULL); cbdata->args[0].isnull = FALSE; cbdata->args[1].isnull = FALSE; cbdata->args[2].isnull = FALSE; @@ -6332,7 +6346,7 @@ Datum RASTER_mapAlgebra2(PG_FUNCTION_ARGS) Oid ufc_noid = InvalidOid; FmgrInfo ufl_info; - LOCAL_FCINFO(ufc_info, FUNC_MAX_ARGS); /* Could be optimized */ + LOCAL_FCINFO(ufc_info, 4); int ufc_nullcount = 0; diff --git a/raster/test/regress/rt_mapalgebra.sql b/raster/test/regress/rt_mapalgebra.sql index a2810ae06..a3ad1e527 100644 --- a/raster/test/regress/rt_mapalgebra.sql +++ b/raster/test/regress/rt_mapalgebra.sql @@ -34,6 +34,15 @@ CREATE OR REPLACE FUNCTION raster_nmapalgebra_test( END; $$ LANGUAGE 'plpgsql' IMMUTABLE; +CREATE OR REPLACE FUNCTION raster_nmapalgebra_test_no_userargs( + value double precision[][][], + pos int[][] +) + RETURNS double precision + AS $$ + SELECT $1[1][1][1] + $2[0][1] + $2[0][2]; + $$ LANGUAGE 'sql' IMMUTABLE STRICT; + SET client_min_messages TO notice; SELECT @@ -60,6 +69,18 @@ SELECT FROM raster_nmapalgebra_in WHERE rid IN (2,3,4); +SELECT + rid, + ST_Value( + ST_MapAlgebra( + ARRAY[ROW(rast, 1)]::rastbandarg[], + 'raster_nmapalgebra_test_no_userargs(double precision[], int[])'::regprocedure + ), + 1, 1, 1 + ) = 3 +FROM raster_nmapalgebra_in +WHERE rid = 2; + SELECT rid, round(ST_Value( @@ -594,5 +615,6 @@ FROM raster_nmapalgebra_in WHERE rid IN (2); DROP FUNCTION IF EXISTS raster_nmapalgebra_test(double precision[], int[], text[]); +DROP FUNCTION IF EXISTS raster_nmapalgebra_test_no_userargs(double precision[], int[]); DROP FUNCTION IF EXISTS raster_nmapalgebra_test_bad_return(double precision[], int[], text[]); DROP TABLE IF EXISTS raster_nmapalgebra_in; diff --git a/raster/test/regress/rt_mapalgebra_expected b/raster/test/regress/rt_mapalgebra_expected index a7753a70e..407d368be 100644 --- a/raster/test/regress/rt_mapalgebra_expected +++ b/raster/test/regress/rt_mapalgebra_expected @@ -43,6 +43,7 @@ NOTICE: userargs = 2|t 3|t 4|t +2|t NOTICE: value = {{{20}}} NOTICE: pos = [0:1][1:2]={{1,1},{1,1}} NOTICE: userargs = {3.14} ----------------------------------------------------------------------- Summary of changes: NEWS | 4 + doc/man/raster2pgsql.1 | 5 + doc/reference_raster.xml | 10 +- doc/using_raster_dataman.xml | 14 ++ raster/loader/raster2pgsql.c | 235 +++++++++++++++------ raster/loader/raster2pgsql.h | 24 ++- raster/rt_pg/rtpg_mapalgebra.c | 60 ++++-- raster/test/regress/loader/IfNotExists-pre.sql | 3 + raster/test/regress/loader/IfNotExists.opts | 1 + .../regress/loader/IfNotExists.select.expected | 4 + raster/test/regress/loader/IfNotExists.select.sql | 8 + .../loader/{Basic.tif.ref => IfNotExists.tif.ref} | 0 raster/test/regress/rt_mapalgebra.sql | 22 ++ raster/test/regress/rt_mapalgebra_expected | 1 + raster/test/regress/tests.mk.in | 1 + 15 files changed, 293 insertions(+), 99 deletions(-) create mode 100644 raster/test/regress/loader/IfNotExists-pre.sql create mode 100644 raster/test/regress/loader/IfNotExists.opts create mode 100644 raster/test/regress/loader/IfNotExists.select.expected create mode 100644 raster/test/regress/loader/IfNotExists.select.sql copy raster/test/regress/loader/{Basic.tif.ref => IfNotExists.tif.ref} (100%) hooks/post-receive -- PostGIS From trac at osgeo.org Sat Jun 20 11:16:54 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 18:16:54 -0000 Subject: [PostGIS] #2804: [raster] ST_MapAlgebra support for user callbacks without userarg parameter In-Reply-To: <051.795f502ef74ec7bea384a80a9ad68cf0@osgeo.org> References: <051.795f502ef74ec7bea384a80a9ad68cf0@osgeo.org> Message-ID: <066.5966e27801fdc21155a9f3ee2b42eaf6@osgeo.org> #2804: [raster] ST_MapAlgebra support for user callbacks without userarg parameter --------------------------+----------------------------- Reporter: dustymugs | Owner: dustymugs Type: enhancement | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: raster | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"4ec0a1dd0a311af57c593656637f5c98ac7a1799/git" 4ec0a1d/git]: {{{#!CommitTicketReference repository="git" revision="4ec0a1dd0a311af57c593656637f5c98ac7a1799" Improve raster MapAlgebra callback arity handling Allow n-raster ST_MapAlgebra callbacks to omit the variadic userargs parameter, matching the existing callback arity flexibility in adjacent MapAlgebra variants. Size raster MapAlgebra FunctionCallInfo storage to the callback arities used instead of allocating FUNC_MAX_ARGS slots. Track the owned empty userargs array used for strict three-argument callbacks so it can be released with the MapAlgebra argument state. Closes #2804 Closes #4315 Closes https://github.com/postgis/postgis/pull/1035 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Sat Jun 20 11:16:54 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 18:16:54 -0000 Subject: [PostGIS] #4315: PG12: Optimize FunctionCall parameter size in rtpg_mapalgebra.c In-Reply-To: <052.a4497d9d8fe6ef329b875d65f8f7d485@osgeo.org> References: <052.a4497d9d8fe6ef329b875d65f8f7d485@osgeo.org> Message-ID: <067.b997fc9a7d860edb674c0437aa032ed4@osgeo.org> #4315: PG12: Optimize FunctionCall parameter size in rtpg_mapalgebra.c --------------------------+----------------------------- Reporter: Algunenano | Owner: dustymugs Type: enhancement | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: raster | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"4ec0a1dd0a311af57c593656637f5c98ac7a1799/git" 4ec0a1d/git]: {{{#!CommitTicketReference repository="git" revision="4ec0a1dd0a311af57c593656637f5c98ac7a1799" Improve raster MapAlgebra callback arity handling Allow n-raster ST_MapAlgebra callbacks to omit the variadic userargs parameter, matching the existing callback arity flexibility in adjacent MapAlgebra variants. Size raster MapAlgebra FunctionCallInfo storage to the callback arities used instead of allocating FUNC_MAX_ARGS slots. Track the owned empty userargs array used for strict three-argument callbacks so it can be released with the MapAlgebra argument state. Closes #2804 Closes #4315 Closes https://github.com/postgis/postgis/pull/1035 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Sat Jun 20 11:16:54 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 18:16:54 -0000 Subject: [PostGIS] #4659: raster2pgsql option to create or append In-Reply-To: <054.d8e8c491bae5338c14c83abf05e6913c@osgeo.org> References: <054.d8e8c491bae5338c14c83abf05e6913c@osgeo.org> Message-ID: <069.f5b7d584a5e8193dbf87a5f352258bdf@osgeo.org> #4659: raster2pgsql option to create or append ---------------------------+----------------------------- Reporter: andrewharvey | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: 2.5.x -- EOL Resolution: fixed | Keywords: ---------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"6ce331f4e2bfd2054f56ba09c43907621259bffc/git" 6ce331f/git]: {{{#!CommitTicketReference repository="git" revision="6ce331f4e2bfd2054f56ba09c43907621259bffc" Add raster2pgsql --if-not-exists modifier Add a loader modifier that emits CREATE TABLE IF NOT EXISTS in create and prepare modes, allowing -c --if-not-exists to create a missing target table or continue loading into an existing compatible table. Represent the short operation modes as explicit internal actions for dropping tables, creating tables, loading data, and creating indexes. When -I is used with --if-not-exists, emit CREATE INDEX IF NOT EXISTS with stable loader index names; plain -I keeps its existing create-index behavior. Closes #4659 Closes https://github.com/postgis/postgis/pull/1000 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sat Jun 20 12:33:56 2026 From: git at osgeo.org (git at osgeo.org) Date: Sat, 20 Jun 2026 12:33:56 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-634-g47224001d Message-ID: <20260620193356.3DFC11C7652@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 47224001d6fdd5e6443a6db1114419fd5b7d5d81 (commit) from 6ce331f4e2bfd2054f56ba09c43907621259bffc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 47224001d6fdd5e6443a6db1114419fd5b7d5d81 Author: Darafei Praliaskouski Date: Sat Jun 20 22:45:48 2026 +0400 Add ST_Value boundary resample modes Add nearest-neighbor boundary resample modes for ST_Value so callers can choose upper-left, upper-right, lower-left, or lower-right pixels when a point lies on a pixel edge or corner. Snap near-integer raster coordinates before applying boundary rounding, and reject non-exact resample names instead of accepting prefixes. Closes #2116 Closes https://github.com/postgis/postgis/pull/1039 diff --git a/NEWS b/NEWS index e668c7a62..395493674 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Enhancements * + - #2116, [raster] Add ST_Value nearest-neighbor boundary options + (Darafei Praliaskouski) - #2804, #4315, [raster] Support two-argument ST_MapAlgebra callbacks and pass callback call data as actual arguments (Darafei Praliaskouski) - #2898, Document SQL function cost tiers for contributors diff --git a/doc/reference_raster.xml b/doc/reference_raster.xml index 04d059ffc..00206e352 100644 --- a/doc/reference_raster.xml +++ b/doc/reference_raster.xml @@ -4815,8 +4815,9 @@ SELECT x, y, val, ST_AsText(geom) Returns the value of a given band in a given columnx, rowy pixel or at a given geometry point. Band numbers start at 1 and band is assumed to be 1 if not specified. If exclude_nodata_value is set to true, then only non nodata pixels are considered. If exclude_nodata_value is set to false, then all pixels are considered. - The allowed values of the resample parameter are "nearest" which performs the default nearest-neighbor resampling, and "bilinear" which performs a bilinear interpolation to estimate the value between pixel centers. + The allowed values of the resample parameter are "nearest" which performs the default nearest-neighbor resampling, "bilinear" which performs a bilinear interpolation to estimate the value between pixel centers, and the nearest-neighbor boundary options "nearest-UL", "nearest-UR", "nearest-LL", and "nearest-LR". Boundary options choose which pixel is returned when the point lies on a horizontal or vertical pixel boundary, including corner intersections. + Enhanced: 3.7.0 resample accepts nearest-neighbor boundary options "nearest-UL", "nearest-UR", "nearest-LL", and "nearest-LR". Enhanced: 3.2.0 resample optional argument was added. Enhanced: 2.0.0 exclude_nodata_value optional argument was added. diff --git a/raster/rt_core/librtcore.h b/raster/rt_core/librtcore.h index 618d1292d..97cc83bff 100644 --- a/raster/rt_core/librtcore.h +++ b/raster/rt_core/librtcore.h @@ -1475,8 +1475,13 @@ rt_errorstate rt_band_get_pixel_bilinear( double *r_value, int *r_nodata ); -typedef enum { +typedef enum +{ RT_NEAREST, + RT_NEAREST_UL, + RT_NEAREST_UR, + RT_NEAREST_LL, + RT_NEAREST_LR, RT_BILINEAR } rt_resample_type; @@ -1487,7 +1492,7 @@ typedef enum { * @param band : the band to read for values * @param xr : x unrounded raster coordinate * @param yr : y unrounded raster coordinate - * @param resample : algorithm for reading raster (nearest or bilinear) + * @param resample : algorithm for reading raster * @param r_value : return pointer for point value * @param r_nodata : return pointer for if this is a nodata * diff --git a/raster/rt_core/rt_band.c b/raster/rt_core/rt_band.c index 0fb95d1f8..cace34bfc 100644 --- a/raster/rt_core/rt_band.c +++ b/raster/rt_core/rt_band.c @@ -1386,6 +1386,18 @@ rt_errorstate rt_band_get_pixel_line( return ES_NONE; } +static double +rt_band_snap_pixel_coordinate(double coordinate) +{ + double nearest = round(coordinate); + double tolerance = DBL_EPSILON * fmax(fabs(coordinate), 1.0) * 16.0; + + if (fabs(coordinate - nearest) <= tolerance) + return nearest; + + return coordinate; +} + /** * Retrieve a point value from the raster using a world coordinate * and selected interpolation. @@ -1411,11 +1423,25 @@ rt_band_get_pixel_resample( band, xr, yr, r_value, r_nodata ); } - else if (resample == RT_NEAREST) { - return rt_band_get_pixel( - band, floor(xr), floor(yr), - r_value, r_nodata - ); + else if (resample == RT_NEAREST || resample == RT_NEAREST_UL || resample == RT_NEAREST_UR || + resample == RT_NEAREST_LL || resample == RT_NEAREST_LR) + { + int x, y; + + xr = rt_band_snap_pixel_coordinate(xr); + yr = rt_band_snap_pixel_coordinate(yr); + + if (resample == RT_NEAREST_UL || resample == RT_NEAREST_LL) + x = ceil(xr) - 1; + else + x = floor(xr); + + if (resample == RT_NEAREST_UL || resample == RT_NEAREST_UR) + y = ceil(yr) - 1; + else + y = floor(yr); + + return rt_band_get_pixel(band, x, y, r_value, r_nodata); } else { rtwarn("Invalid resample type requested %d", resample); diff --git a/raster/rt_pg/rtpg_pixel.c b/raster/rt_pg/rtpg_pixel.c index 9aa65ebea..3791353f3 100644 --- a/raster/rt_pg/rtpg_pixel.c +++ b/raster/rt_pg/rtpg_pixel.c @@ -141,16 +141,27 @@ Datum RASTER_getPixelValue(PG_FUNCTION_ARGS) static rt_resample_type resample_text_to_type(text *txt) { + rt_resample_type resample_type = RT_NEAREST; char *resample = asc_tolower(VARDATA(txt), VARSIZE_ANY_EXHDR(txt)); - if (strncmp(resample, "bilinear", 8) == 0) - return RT_BILINEAR; - else if (strncmp(resample, "nearest", 7) == 0) - return RT_NEAREST; + + if (strcmp(resample, "bilinear") == 0) + resample_type = RT_BILINEAR; + else if (strcmp(resample, "nearest-ul") == 0) + resample_type = RT_NEAREST_UL; + else if (strcmp(resample, "nearest-ur") == 0) + resample_type = RT_NEAREST_UR; + else if (strcmp(resample, "nearest-ll") == 0) + resample_type = RT_NEAREST_LL; + else if (strcmp(resample, "nearest-lr") == 0) + resample_type = RT_NEAREST_LR; + else if (strcmp(resample, "nearest") == 0) + resample_type = RT_NEAREST; else { elog(ERROR, "Unknown resample type '%s' requested", resample); } + pfree(resample); - return RT_NEAREST; + return resample_type; } /* @@ -2506,4 +2517,3 @@ Datum RASTER_neighborhood(PG_FUNCTION_ARGS) PG_RETURN_ARRAYTYPE_P(mdArray); } - diff --git a/raster/test/regress/rt_pixelvalue.sql b/raster/test/regress/rt_pixelvalue.sql index 2842e47d4..00071db9a 100644 --- a/raster/test/regress/rt_pixelvalue.sql +++ b/raster/test/regress/rt_pixelvalue.sql @@ -367,6 +367,57 @@ round(ST_Value(rast, 1, 'SRID=4326;POINT(0.5 0.5)'::geometry, resample => 'neare round(ST_Value(rast, 1, 'SRID=4326;POINT(1.0 1.0)'::geometry, resample => 'bilinear')) as nearest_10_10, round(ST_Value(rast, 1, 'SRID=4326;POINT(1.0 0.1)'::geometry, resample => 'bilinear')) as nearest_10_00, round(ST_Value(rast, 1, 'SRID=4326;POINT(1.0 1.9)'::geometry, resample => 'bilinear')) as nearest_10_20 -FROM r +FROM r; +WITH r AS ( +SELECT +ST_SetValues( + ST_AddBand( + ST_MakeEmptyRaster(width => 2, height => 2, + upperleftx => 0, upperlefty => 2, + scalex => 1.0, scaley => -1.0, + skewx => 0, skewy => 0, srid => 4326), + index => 1, pixeltype => '16BSI', + initialvalue => 0, + nodataval => -999), + 1,1,1, + newvalueset =>ARRAY[ARRAY[10.0::float8, 50.0::float8], ARRAY[40.0::float8, 20.0::float8]]) AS rast +) +SELECT +'#2116', +round(ST_Value(rast, 1, 'SRID=4326;POINT(1.0 1.0)'::geometry, resample => 'nearest-ul')) as nearest_ul, +round(ST_Value(rast, 1, 'SRID=4326;POINT(1.0 1.0)'::geometry, resample => 'nearest-ur')) as nearest_ur, +round(ST_Value(rast, 1, 'SRID=4326;POINT(1.0 1.0)'::geometry, resample => 'nearest-ll')) as nearest_ll, +round(ST_Value(rast, 1, 'SRID=4326;POINT(1.0 1.0)'::geometry, resample => 'nearest-lr')) as nearest_lr, +round(ST_Value(rast, 1, 'SRID=4326;POINT(1.0 1.0)'::geometry, resample => 'nearest')) as nearest_default +FROM r; +WITH r AS ( +SELECT +ST_SetValues( + ST_AddBand( + ST_MakeEmptyRaster(width => 2, height => 2, + upperleftx => 0, upperlefty => 2, + scalex => 1.0, scaley => -1.0, + skewx => 0, skewy => 0, srid => 4326), + index => 1, pixeltype => '16BSI', + initialvalue => 0, + nodataval => -999), + 1,1,1, + newvalueset =>ARRAY[ARRAY[10.0::float8, 50.0::float8], ARRAY[40.0::float8, 20.0::float8]]) AS rast +) +SELECT +'#2116.snap', +round(ST_Value(rast, 1, 'SRID=4326;POINT(1.0000000000000004 0.9999999999999996)'::geometry, resample => 'nearest-ul')) as nearest_ul, +round(ST_Value(rast, 1, 'SRID=4326;POINT(0.9999999999999997 1.0000000000000002)'::geometry, resample => 'nearest-lr')) as nearest_lr +FROM r; + +WITH r AS ( +SELECT ST_AddBand(ST_MakeEmptyRaster(1, 1, 0, 1, 1, -1, 0, 0, 4326), '16BSI'::text, 1, -999) AS rast +) +SELECT ST_Value(rast, 1, 'SRID=4326;POINT(0.5 0.5)'::geometry, resample => 'nearest-foo') FROM r; + +WITH r AS ( +SELECT ST_AddBand(ST_MakeEmptyRaster(1, 1, 0, 1, 1, -1, 0, 0, 4326), '16BSI'::text, 1, -999) AS rast +) +SELECT ST_Value(rast, 1, 'SRID=4326;POINT(0.5 0.5)'::geometry, resample => 'bilinearXYZ') FROM r; diff --git a/raster/test/regress/rt_pixelvalue_expected b/raster/test/regress/rt_pixelvalue_expected index 7576caaff..989a306b4 100644 --- a/raster/test/regress/rt_pixelvalue_expected +++ b/raster/test/regress/rt_pixelvalue_expected @@ -11,3 +11,7 @@ NOTICE: Raster do not have a nodata value defined. Set band nodata value first. NOTICE: Raster do not have a nodata value defined. Set band nodata value first. Nodata value not set. Returning original raster NOTICE: Raster do not have a nodata value defined. Set band nodata value first. Nodata value not set. Returning original raster Test 5|50|40|30|26|38 +#2116|10|50|40|20|20 +#2116.snap|10|20 +ERROR: Unknown resample type 'nearest-foo' requested +ERROR: Unknown resample type 'bilinearxyz' requested ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ doc/reference_raster.xml | 3 +- raster/rt_core/librtcore.h | 9 +++-- raster/rt_core/rt_band.c | 36 +++++++++++++++++--- raster/rt_pg/rtpg_pixel.c | 22 +++++++++---- raster/test/regress/rt_pixelvalue.sql | 53 +++++++++++++++++++++++++++++- raster/test/regress/rt_pixelvalue_expected | 4 +++ 7 files changed, 114 insertions(+), 15 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sat Jun 20 12:33:57 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 19:33:57 -0000 Subject: [PostGIS] #2116: [raster] ST_Value(rast, point) should have an option for when the geometry is at the edge of a pixel. In-Reply-To: <049.184b021042a2a264232009fc82a49b97@osgeo.org> References: <049.184b021042a2a264232009fc82a49b97@osgeo.org> Message-ID: <064.fa7d52665c1a5938e1402bcd54b30c1c@osgeo.org> #2116: [raster] ST_Value(rast, point) should have an option for when the geometry is at the edge of a pixel. --------------------------+----------------------------- Reporter: pracine | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"47224001d6fdd5e6443a6db1114419fd5b7d5d81/git" 4722400/git]: {{{#!CommitTicketReference repository="git" revision="47224001d6fdd5e6443a6db1114419fd5b7d5d81" Add ST_Value boundary resample modes Add nearest-neighbor boundary resample modes for ST_Value so callers can choose upper-left, upper-right, lower-left, or lower-right pixels when a point lies on a pixel edge or corner. Snap near-integer raster coordinates before applying boundary rounding, and reject non-exact resample names instead of accepting prefixes. Closes #2116 Closes https://github.com/postgis/postgis/pull/1039 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sat Jun 20 12:53:39 2026 From: git at osgeo.org (git at osgeo.org) Date: Sat, 20 Jun 2026 12:53:39 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-635-gea6edb5d5 Message-ID: <20260620195339.8B0FE1A03CB@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via ea6edb5d5a44804bd0e3d2d05d76b220134fae1f (commit) from 47224001d6fdd5e6443a6db1114419fd5b7d5d81 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit ea6edb5d5a44804bd0e3d2d05d76b220134fae1f Author: Darafei Praliaskouski Date: Sat Jun 20 23:50:49 2026 +0400 raster: preserve missing NODATA in map algebra ST_MapAlgebra no longer injects an output NODATA value when the selected input band has none. Expression and callback variants now raise an error if they produce NULL without an output NODATA value available. Keep ST_Grayscale explicit about its own NODATA contract so later RGB-band NODATA values still become output NODATA pixels even when the first band has no NODATA value. Closes #2807 Closes https://github.com/postgis/postgis/pull/1056 diff --git a/NEWS b/NEWS index 395493674..e84f23d2a 100644 --- a/NEWS +++ b/NEWS @@ -74,6 +74,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Bug Fixes * + - #2807, [raster] Preserve missing NODATA values in ST_MapAlgebra outputs + (Darafei Praliaskouski) - #2832, [raster] Avoid padding single-tile raster2pgsql overviews when padding is not requested (Darafei Praliaskouski) - Fix WKB and TWKB parser resource exhaustion on malformed input diff --git a/raster/rt_pg/rtpg_mapalgebra.c b/raster/rt_pg/rtpg_mapalgebra.c index f2109a30d..36aad8f02 100644 --- a/raster/rt_pg/rtpg_mapalgebra.c +++ b/raster/rt_pg/rtpg_mapalgebra.c @@ -88,6 +88,7 @@ typedef struct { Oid ufc_noid; Oid ufc_rettype; FmgrInfo ufl_info; + int hasnodata; /* copied from LOCAL_FCINFO in fmgr.h */ union { FunctionCallInfoBaseData fcinfo; @@ -159,6 +160,7 @@ static rtpg_nmapalgebra_arg rtpg_nmapalgebra_arg_init(void) { arg->callback.ufc_noid = InvalidOid; arg->callback.ufc_rettype = InvalidOid; arg->callback.empty_userargs = NULL; + arg->callback.hasnodata = 1; return arg; } @@ -518,8 +520,13 @@ static int rtpg_nmapalgebra_callback( break; } } - else + else if (callback->hasnodata) *nodata = 1; + else + { + elog(ERROR, "RASTER_nMapAlgebra: Callback returned NULL but output raster has no NODATA value"); + return 0; + } return 1; } @@ -929,8 +936,9 @@ Datum RASTER_nMapAlgebra(PG_FUNCTION_ARGS) arg->pixtype = rt_band_get_pixtype(band); /* set hasnodata and nodataval */ - arg->hasnodata = 1; - if (rt_band_get_hasnodata_flag(band)) + arg->hasnodata = rt_band_get_hasnodata_flag(band); + arg->callback.hasnodata = arg->hasnodata; + if (arg->hasnodata) rt_band_get_nodata(band, &(arg->nodataval)); else arg->nodataval = rt_band_get_min_value(band); @@ -1009,6 +1017,8 @@ typedef struct { double val; } nodatanodata; + int hasnodata; + struct { int count; char **val; @@ -1058,6 +1068,7 @@ static rtpg_nmapalgebraexpr_arg rtpg_nmapalgebraexpr_arg_init(int cnt, char **kw arg->callback.nodatanodata.hasval = 0; arg->callback.nodatanodata.val = 0; + arg->callback.hasnodata = 1; return arg; } @@ -1122,13 +1133,15 @@ static int rtpg_nmapalgebraexpr_callback( *nodata = 1; } /* expression */ - else { + else + { id = 0; if (callback->expr[id].hasval) *value = callback->expr[id].val; else if (callback->expr[id].spi_plan) plan = callback->expr[id].spi_plan; - else { + else + { if (callback->nodatanodata.hasval) *value = callback->nodatanodata.val; else @@ -1301,6 +1314,12 @@ static int rtpg_nmapalgebraexpr_callback( if (SPI_tuptable) SPI_freetuptable(tuptable); } + if (*nodata && !callback->hasnodata) + { + elog(ERROR, "RASTER_nMapAlgebraExpr: Expression returned NULL but output raster has no NODATA value"); + return 0; + } + POSTGIS_RT_DEBUGF(4, "(value, nodata) = (%f, %d)", *value, *nodata); return 1; } @@ -1622,8 +1641,9 @@ Datum RASTER_nMapAlgebraExpr(PG_FUNCTION_ARGS) arg->bandarg->pixtype = rt_band_get_pixtype(band); /* set hasnodata and nodataval */ - arg->bandarg->hasnodata = 1; - if (rt_band_get_hasnodata_flag(band)) + arg->bandarg->hasnodata = rt_band_get_hasnodata_flag(band); + arg->callback.hasnodata = arg->bandarg->hasnodata; + if (arg->bandarg->hasnodata) rt_band_get_nodata(band, &(arg->bandarg->nodataval)); else arg->bandarg->nodataval = rt_band_get_min_value(band); diff --git a/raster/rt_pg/rtpostgis.sql.in b/raster/rt_pg/rtpostgis.sql.in index 5a1bfc085..96bb55ed8 100644 --- a/raster/rt_pg/rtpostgis.sql.in +++ b/raster/rt_pg/rtpostgis.sql.in @@ -4429,6 +4429,13 @@ CREATE OR REPLACE FUNCTION _st_grayscale4ma(value double precision[][][], pos in green := _value[2][1][1]; blue := _value[3][1][1]; + -- ST_Grayscale uses 255 as its output NODATA sentinel. Returning the + -- sentinel here lets the wrapper mark it as NODATA only when one of + -- the source RGB bands has a NODATA value. + IF red IS NULL OR green IS NULL OR blue IS NULL THEN + RETURN 255; + END IF; + gray = round(0.2989 * red + 0.5870 * green + 0.1140 * blue); RETURN gray; @@ -4459,6 +4466,8 @@ CREATE OR REPLACE FUNCTION st_grayscale( nodata double precision; nodataval integer; reclassexpr text; + hasnodata boolean DEFAULT FALSE; + grayscale @extschema at .raster; BEGIN @@ -4483,11 +4492,16 @@ CREATE OR REPLACE FUNCTION st_grayscale( RAISE EXCEPTION 'Band at index ''%'' not found for raster ''%''', nband, idx; - -- check that each band is 8BUI. if not, reclassify to 8BUI - ELSIF @extschema at .ST_BandPixelType(rast, nband) != _PIXTYPE THEN + END IF; + nodata := @extschema at .ST_BandNoDataValue(rast, nband); + IF nodata IS NOT NULL THEN + hasnodata := TRUE; + END IF; + + -- check that each band is 8BUI. if not, reclassify to 8BUI + IF @extschema at .ST_BandPixelType(rast, nband) != _PIXTYPE THEN stats := @extschema at .ST_SummaryStats(rast, nband); - nodata := @extschema at .ST_BandNoDataValue(rast, nband); IF nodata IS NOT NULL THEN nodataval := _NODATA; @@ -4513,13 +4527,19 @@ CREATE OR REPLACE FUNCTION st_grayscale( END LOOP; -- call map algebra with _st_grayscale4ma - RETURN @extschema at .ST_MapAlgebra( + grayscale := @extschema at .ST_MapAlgebra( _set, '@extschema at ._ST_Grayscale4MA(double precision[][][], integer[][], text[])'::regprocedure, '8BUI', extenttype ); + IF hasnodata THEN + grayscale := @extschema at .ST_SetBandNoDataValue(grayscale, 1, _NODATA); + END IF; + + RETURN grayscale; + END; $$ LANGUAGE 'plpgsql' IMMUTABLE PARALLEL SAFE; diff --git a/raster/test/regress/rt_grayscale.sql b/raster/test/regress/rt_grayscale.sql index b85b95c67..d65e7547e 100644 --- a/raster/test/regress/rt_grayscale.sql +++ b/raster/test/regress/rt_grayscale.sql @@ -125,6 +125,41 @@ SELECT FROM raster_grayscale_out ORDER BY 1, 2, nband; +-- #2807: ST_Grayscale is implemented through ST_MapAlgebra. Source rasters 1, +-- 2, and 5 have no NODATA value, so zero-valued pixels in the dump above are +-- real pixel values. Source rasters 3 and 4 have explicit NODATA values, so +-- their matching output pixels remain NULL. +SELECT + '#2807.grayscale', + testid, + rid, + (ST_BandMetadata(rast, 1)).nodatavalue +FROM raster_grayscale_out +WHERE rid IN (1, 3, 5) +ORDER BY testid, rid; + +-- The first RGB band controls generic n-raster MapAlgebra output metadata. +-- ST_Grayscale still needs to preserve NODATA from later RGB bands when the +-- first band has no NODATA value. +WITH mixed AS ( + SELECT ST_Grayscale(ARRAY[ + ROW(red.rast, 1)::rastbandarg, + ROW(green.rast, 1)::rastbandarg, + ROW(blue.rast, 1)::rastbandarg + ]::rastbandarg[]) AS rast + FROM raster_grayscale_in red + CROSS JOIN raster_grayscale_in green + CROSS JOIN raster_grayscale_in blue + WHERE red.rid = 1 + AND green.rid = 3 + AND blue.rid = 3 +) +SELECT + '#2807.grayscale.mixed', + (ST_BandMetadata(rast, 1)).nodatavalue, + (ST_DumpValues(rast)).valarray +FROM mixed; + -- error because of insufficient bands BEGIN; SELECT diff --git a/raster/test/regress/rt_grayscale_expected b/raster/test/regress/rt_grayscale_expected index 22e121d27..6ab88ba52 100644 --- a/raster/test/regress/rt_grayscale_expected +++ b/raster/test/regress/rt_grayscale_expected @@ -5,21 +5,31 @@ WARNING: Only the first three elements of 'rastbandargset' will be used WARNING: Only the first three elements of 'rastbandargset' will be used WARNING: Only the first three elements of 'rastbandargset' will be used WARNING: Only the first three elements of 'rastbandargset' will be used -1|1|1|{{NULL,128},{254,255}} -1|2|1|{{NULL,128},{254,255}} +1|1|1|{{0,128},{254,255}} +1|2|1|{{0,128},{254,255}} 1|3|1|{{NULL,0},{254,254}} 1|4|1|{{NULL,0},{254,254}} -1|5|1|{{NULL,NULL},{128,128},{255,255}} -2|1|1|{{NULL,128},{254,255}} -2|2|1|{{NULL,128},{254,255}} +1|5|1|{{0,0},{128,128},{255,255}} +2|1|1|{{0,128},{254,255}} +2|2|1|{{0,128},{254,255}} 2|3|1|{{NULL,0},{254,254}} 2|4|1|{{NULL,0},{254,254}} -2|5|1|{{NULL,NULL},{128,128},{255,255}} -3|1|1|{{NULL,128},{254,255}} -3|2|1|{{NULL,128},{254,255}} +2|5|1|{{0,0},{128,128},{255,255}} +3|1|1|{{0,128},{254,255}} +3|2|1|{{0,128},{254,255}} 3|3|1|{{NULL,0},{254,254}} 3|4|1|{{NULL,0},{254,254}} -3|5|1|{{NULL,NULL},{128,128},{255,255}} +3|5|1|{{0,0},{128,128},{255,255}} +#2807.grayscale|1|1| +#2807.grayscale|1|3|255 +#2807.grayscale|1|5| +#2807.grayscale|2|1| +#2807.grayscale|2|3|255 +#2807.grayscale|2|5| +#2807.grayscale|3|1| +#2807.grayscale|3|3|255 +#2807.grayscale|3|5| +#2807.grayscale.mixed|255|{{NULL,38},{254,254}} ERROR: 'rastbandargset' must have three bands for red, green and blue ERROR: Band at index '2' not found for raster '2' ERROR: Band at index '2' not found for raster '2' diff --git a/raster/test/regress/rt_mapalgebra.sql b/raster/test/regress/rt_mapalgebra.sql index a3ad1e527..879db364a 100644 --- a/raster/test/regress/rt_mapalgebra.sql +++ b/raster/test/regress/rt_mapalgebra.sql @@ -588,6 +588,85 @@ SELECT FROM raster_nmapalgebra_in WHERE rid IN (2); +-- Ticket #2807 +-- https://trac.osgeo.org/postgis/ticket/2807 +CREATE OR REPLACE FUNCTION raster_nmapalgebra_one( + value double precision[][][], + pos int[][], + VARIADIC userargs text[] +) + RETURNS double precision + AS $$ SELECT 1::double precision $$ + LANGUAGE 'sql' IMMUTABLE; + +CREATE OR REPLACE FUNCTION raster_nmapalgebra_null( + value double precision[][][], + pos int[][], + VARIADIC userargs text[] +) + RETURNS double precision + AS $$ SELECT NULL::double precision $$ + LANGUAGE 'sql' IMMUTABLE; + +SET client_min_messages TO warning; + +WITH src AS ( + SELECT ST_AddBand( + ST_MakeEmptyRaster(2, 2, 0, 0, 1), + '8BUI', 255.0 + ) AS rast +) +SELECT + '#2807.expr', + (ST_BandMetadata(ST_MapAlgebra(rast, 1, '8BUI', '0'), 1)), + ST_Value(ST_MapAlgebra(rast, 1, '8BUI', '0'), 1, 1) +FROM src; + +WITH src AS ( + SELECT ST_AddBand( + ST_MakeEmptyRaster(2, 2, 0, 0, 1), + '8BUI', 255.0 + ) AS rast +) +SELECT + '#2807.callback', + (ST_BandMetadata(ST_MapAlgebra( + rast, 1, + 'raster_nmapalgebra_one(double precision[], int[], text[])'::regprocedure + ), 1)), + ST_Value(ST_MapAlgebra( + rast, 1, + 'raster_nmapalgebra_one(double precision[], int[], text[])'::regprocedure + ), 1, 1) +FROM src; + +WITH src AS ( + SELECT ST_AddBand( + ST_MakeEmptyRaster(2, 2, 0, 0, 1), + '8BUI', 255.0 + ) AS rast +) +SELECT + '#2807.expr.null', + (ST_BandMetadata(ST_MapAlgebra(rast, 1, '8BUI', 'NULL'), 1)) +FROM src; + +WITH src AS ( + SELECT ST_AddBand( + ST_MakeEmptyRaster(2, 2, 0, 0, 1), + '8BUI', 255.0 + ) AS rast +) +SELECT + '#2807.callback.null', + (ST_BandMetadata(ST_MapAlgebra( + rast, 1, + 'raster_nmapalgebra_null(double precision[], int[], text[])'::regprocedure + ), 1)) +FROM src; + +SET client_min_messages TO notice; + -- Ticket #2802 -- http://trac.osgeo.org/postgis/ticket/2802 CREATE OR REPLACE FUNCTION raster_nmapalgebra_test_bad_return( @@ -614,6 +693,8 @@ SELECT FROM raster_nmapalgebra_in WHERE rid IN (2); +DROP FUNCTION IF EXISTS raster_nmapalgebra_one(double precision[], int[], text[]); +DROP FUNCTION IF EXISTS raster_nmapalgebra_null(double precision[], int[], text[]); DROP FUNCTION IF EXISTS raster_nmapalgebra_test(double precision[], int[], text[]); DROP FUNCTION IF EXISTS raster_nmapalgebra_test_no_userargs(double precision[], int[]); DROP FUNCTION IF EXISTS raster_nmapalgebra_test_bad_return(double precision[], int[], text[]); diff --git a/raster/test/regress/rt_mapalgebra_expected b/raster/test/regress/rt_mapalgebra_expected index 407d368be..ed0092046 100644 --- a/raster/test/regress/rt_mapalgebra_expected +++ b/raster/test/regress/rt_mapalgebra_expected @@ -353,4 +353,8 @@ NOTICE: value = {{{1}}} NOTICE: pos = [0:1][1:2]={{2,2},{2,2}} NOTICE: userargs = {} 2| +#2807.expr|(8BUI,,f,,,,)|0 +#2807.callback|(8BUI,,f,,,,)|1 +ERROR: RASTER_nMapAlgebraExpr: Expression returned NULL but output raster has no NODATA value +ERROR: RASTER_nMapAlgebra: Callback returned NULL but output raster has no NODATA value ERROR: RASTER_nMapAlgebra: Function provided must return a double precision, float, int or smallint ----------------------------------------------------------------------- Summary of changes: NEWS | 2 + raster/rt_pg/rtpg_mapalgebra.c | 34 ++++++++++--- raster/rt_pg/rtpostgis.sql.in | 28 +++++++++-- raster/test/regress/rt_grayscale.sql | 35 +++++++++++++ raster/test/regress/rt_grayscale_expected | 28 +++++++---- raster/test/regress/rt_mapalgebra.sql | 81 ++++++++++++++++++++++++++++++ raster/test/regress/rt_mapalgebra_expected | 4 ++ 7 files changed, 192 insertions(+), 20 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sat Jun 20 12:53:41 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 19:53:41 -0000 Subject: [PostGIS] #2807: [raster] ST_MapAlgebra injecting a default NODATA value of 0 In-Reply-To: <046.1965290ce97ad43b1fe6ec491356dc1b@osgeo.org> References: <046.1965290ce97ad43b1fe6ec491356dc1b@osgeo.org> Message-ID: <061.07e0cef5b129fd3a524047becf8a775a@osgeo.org> #2807: [raster] ST_MapAlgebra injecting a default NODATA value of 0 ---------------------+----------------------------- Reporter: strk | Owner: dustymugs Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: master Resolution: fixed | Keywords: ---------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"ea6edb5d5a44804bd0e3d2d05d76b220134fae1f/git" ea6edb5/git]: {{{#!CommitTicketReference repository="git" revision="ea6edb5d5a44804bd0e3d2d05d76b220134fae1f" raster: preserve missing NODATA in map algebra ST_MapAlgebra no longer injects an output NODATA value when the selected input band has none. Expression and callback variants now raise an error if they produce NULL without an output NODATA value available. Keep ST_Grayscale explicit about its own NODATA contract so later RGB-band NODATA values still become output NODATA pixels even when the first band has no NODATA value. Closes #2807 Closes https://github.com/postgis/postgis/pull/1056 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Sat Jun 20 12:54:47 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 19:54:47 -0000 Subject: [PostGIS] #6084: Winnie failing on fuzzy tests Message-ID: <046.33dbafa47b32d323f8a574c0f8223aeb@osgeo.org> #6084: Winnie failing on fuzzy tests --------------------------+--------------------------- Reporter: robe | Owner: robe Type: defect | Status: new Priority: medium | Milestone: PostGIS 3.7.0 Component: QA/buildbots | Version: 3.6.x Keywords: | --------------------------+--------------------------- After #6083 winnie can now run fuzzy tests, however she is failing to compile the geojson one. This looks like it might be a configuration issue because I don't have libs installed as system and hook them in as needed so I can flip the versions I am running against. https://winnie.postgis.net/job/PostGIS_EDB_Regress_winnie/22641/console {{{ fuzzers/build_google_oss_fuzzers.sh Building fuzzer geojson_import_fuzzer C:/ming64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lxml2: No such file or directory collect2.exe: error: ld returned 1 exit status make[2]: *** [/projects/postgis/branches/3.7/fuzzers/Makefile:27: dummyfuzzers] Error 1 make[2]: Leaving directory '/projects/postgis/branches/3.7/fuzzers' make[1]: *** [/projects/postgis/branches/3.7/fuzzers/Makefile:31: check] Error 2 make[1]: Leaving directory '/projects/postgis/branches/3.7/fuzzers' make: *** [GNUmakefile:104: check-fuzzers] Error 2 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sat Jun 20 13:09:35 2026 From: git at osgeo.org (git at osgeo.org) Date: Sat, 20 Jun 2026 13:09:35 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-636-g986bb6a1a Message-ID: <20260620200935.85EDB1A03B4@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 986bb6a1a6a133be10c234b8b04bd7bf1025fa05 (commit) from ea6edb5d5a44804bd0e3d2d05d76b220134fae1f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 986bb6a1a6a133be10c234b8b04bd7bf1025fa05 Author: Darafei Praliaskouski Date: Sat Jun 20 23:58:59 2026 +0400 Clarify newer component script version reporting Compare installed topology, raster, and SFCGAL script versions against the core script version using PostGIS version suffix ordering: dev < alpha < beta < rc < final. When component scripts are newer than core scripts, report that direction explicitly instead of saying the component procs need upgrade. Closes #2808 Closes https://github.com/postgis/postgis/pull/1057 diff --git a/NEWS b/NEWS index e84f23d2a..121538c26 100644 --- a/NEWS +++ b/NEWS @@ -106,6 +106,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - GH-888, [sfcgal] Avoid stale detoasted geometry access in CG_Visibility empty-input handling for SFCGAL < 2.2 (Darafei Praliaskouski) + - #2808, Clarify postgis_full_version() output when installed component + scripts are newer than core scripts (Darafei Praliaskouski) - #3179, Mark truncated libpgcommon PostgreSQL messages instead of silently dropping the tail (Darafei Praliaskouski) - #6003, Avoid size_t formats in liblwgeom logging/error wrappers for diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 7e5cd081b..8abfd90a2 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -3153,6 +3153,42 @@ CREATE OR REPLACE FUNCTION postgis_scripts_released() RETURNS text AS 'MODULE_PATHNAME' LANGUAGE 'c' IMMUTABLE; +CREATE OR REPLACE FUNCTION _postgis_scripts_version_cmp_key(ver text) + RETURNS int[] + AS $$ + DECLARE + ver_match text[]; + BEGIN + ver_match := pg_catalog.regexp_match( + pg_catalog.lower(ver), + '^([0-9]+)\.([0-9]+)\.([0-9]+)(dev|alpha|beta|rc)?([0-9]*)([^0-9a-z].*)?$' + ); + IF ver_match IS NULL THEN + RETURN NULL; + END IF; + + RETURN ARRAY[ + ver_match[1]::int, + ver_match[2]::int, + ver_match[3]::int, + CASE coalesce(ver_match[4], '') + WHEN 'dev' THEN 0 + WHEN 'alpha' THEN 1 + WHEN 'beta' THEN 2 + WHEN 'rc' THEN 3 + ELSE 4 + END, + CASE coalesce(ver_match[5], '') + WHEN '' THEN 0 + ELSE ver_match[5]::int + END + ]; + EXCEPTION WHEN OTHERS THEN + RETURN NULL; + END + $$ + LANGUAGE 'plpgsql' IMMUTABLE STRICT; + CREATE OR REPLACE FUNCTION postgis_geos_version() RETURNS text AS 'MODULE_PATHNAME' LANGUAGE 'c' IMMUTABLE; @@ -3326,6 +3362,8 @@ DECLARE rast_lib_ver text := NULL; rast_scr_ver text := NULL; topo_scr_ver text := NULL; + relproc_int int[]; + scr_ver_int int[]; json_lib_ver text; protobuf_lib_ver text; wagyu_lib_ver text; @@ -3368,6 +3406,7 @@ BEGIN SELECT @extschema at .postgis_scripts_installed() INTO dbproc; SELECT @extschema at .postgis_scripts_released() INTO relproc; SELECT @extschema at .postgis_lib_revision() INTO librev; + SELECT @extschema at ._postgis_scripts_version_cmp_key(relproc) INTO relproc_int; BEGIN SELECT topology.postgis_topology_scripts_installed() INTO topo_scr_ver; EXCEPTION @@ -3471,7 +3510,18 @@ BEGIN IF topo_scr_ver IS NOT NULL THEN fullver = fullver || ' TOPOLOGY'; IF topo_scr_ver != relproc THEN - fullver = fullver || ' (topology procs from "' || topo_scr_ver || '" need upgrade)'; + SELECT @extschema at ._postgis_scripts_version_cmp_key(topo_scr_ver) INTO scr_ver_int; + + IF scr_ver_int IS NOT NULL AND relproc_int IS NOT NULL AND scr_ver_int > relproc_int THEN + fullver = pg_catalog.format( + '%s (topology procs from "%s" are newer than core procs from "%s")', + fullver, + topo_scr_ver, + relproc + ); + ELSE + fullver = fullver || ' (topology procs from "' || topo_scr_ver || '" need upgrade)'; + END IF; END IF; IF core_is_extension AND NOT EXISTS ( SELECT * FROM pg_catalog.pg_extension @@ -3495,11 +3545,33 @@ BEGIN END IF; IF rast_scr_ver IS NOT NULL AND rast_scr_ver != relproc THEN - fullver = fullver || ' (raster procs from "' || rast_scr_ver || '" need upgrade)'; + SELECT @extschema at ._postgis_scripts_version_cmp_key(rast_scr_ver) INTO scr_ver_int; + + IF scr_ver_int IS NOT NULL AND relproc_int IS NOT NULL AND scr_ver_int > relproc_int THEN + fullver = pg_catalog.format( + '%s (raster procs from "%s" are newer than core procs from "%s")', + fullver, + rast_scr_ver, + relproc + ); + ELSE + fullver = fullver || ' (raster procs from "' || rast_scr_ver || '" need upgrade)'; + END IF; END IF; IF sfcgal_scr_ver IS NOT NULL AND sfcgal_scr_ver != relproc THEN - fullver = fullver || ' (sfcgal procs from "' || sfcgal_scr_ver || '" need upgrade)'; + SELECT @extschema at ._postgis_scripts_version_cmp_key(sfcgal_scr_ver) INTO scr_ver_int; + + IF scr_ver_int IS NOT NULL AND relproc_int IS NOT NULL AND scr_ver_int > relproc_int THEN + fullver = pg_catalog.format( + '%s (sfcgal procs from "%s" are newer than core procs from "%s")', + fullver, + sfcgal_scr_ver, + relproc + ); + ELSE + fullver = fullver || ' (sfcgal procs from "' || sfcgal_scr_ver || '" need upgrade)'; + END IF; END IF; -- Check for the presence of deprecated functions diff --git a/regress/core/postgis_full_version.sql b/regress/core/postgis_full_version.sql new file mode 100644 index 000000000..88e9a3c62 --- /dev/null +++ b/regress/core/postgis_full_version.sql @@ -0,0 +1,76 @@ +BEGIN; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM pg_catalog.pg_namespace + WHERE nspname = 'topology' + ) THEN + CREATE SCHEMA topology; + END IF; +END; +$$; + +CREATE OR REPLACE FUNCTION postgis_scripts_released() +RETURNS text +AS $$ SELECT '3.7.0rc1'::text AS version $$ +LANGUAGE 'sql' IMMUTABLE; + +CREATE OR REPLACE FUNCTION topology.postgis_topology_scripts_installed() +RETURNS text +AS $$ SELECT '1.0.0'::text AS version $$ +LANGUAGE 'sql' IMMUTABLE; + +-- Older component script versions still mean the installed procs need upgrade. +SELECT 'topology_old_scripts', + postgis_full_version() ~ + 'TOPOLOGY \(topology procs from "1\.0\.0" need upgrade\)'; + +CREATE OR REPLACE FUNCTION topology.postgis_topology_scripts_installed() +RETURNS text +AS $$ SELECT '3.7.0'::text AS version $$ +LANGUAGE 'sql' IMMUTABLE; + +CREATE OR REPLACE FUNCTION postgis_raster_scripts_installed() +RETURNS text +AS $$ SELECT '3.7.0rc2'::text AS version $$ +LANGUAGE 'sql' IMMUTABLE; + +CREATE OR REPLACE FUNCTION postgis_sfcgal_full_version() +RETURNS text +AS $$ SELECT '999.0.0dev'::text AS version $$ +LANGUAGE 'sql' IMMUTABLE; + +CREATE OR REPLACE FUNCTION postgis_sfcgal_scripts_installed() +RETURNS text +AS $$ SELECT '3.7.0beta1'::text AS version $$ +LANGUAGE 'sql' IMMUTABLE; + +-- Newer component script versions are intentional in mixed-script installs: +-- report them as newer than core, not as something that needs upgrade. This +-- includes final releases newer than release candidates and later RCs. +SELECT 'topology_newer_scripts', + postgis_full_version() ~ + 'TOPOLOGY \(topology procs from "3\.7\.0" are newer than core procs from "3\.7\.0rc1"\)'; + +SELECT 'raster_newer_scripts', + postgis_full_version() ~ + '\(raster procs from "3\.7\.0rc2" are newer than core procs from "3\.7\.0rc1"\)'; + +-- A prerelease older than the core prerelease is still reported as needing +-- upgrade, even when its numeric major/minor/micro components match. +SELECT 'sfcgal_older_prerelease', + postgis_full_version() ~ + '\(sfcgal procs from "3\.7\.0beta1" need upgrade\)'; + +CREATE OR REPLACE FUNCTION postgis_sfcgal_scripts_installed() +RETURNS text +AS $$ SELECT '3.7.0'::text AS version $$ +LANGUAGE 'sql' IMMUTABLE; + +SELECT 'sfcgal_newer_scripts', + postgis_full_version() ~ + '\(sfcgal procs from "3\.7\.0" are newer than core procs from "3\.7\.0rc1"\)'; + +ROLLBACK; diff --git a/regress/core/postgis_full_version_expected b/regress/core/postgis_full_version_expected new file mode 100644 index 000000000..8e3e2c8cd --- /dev/null +++ b/regress/core/postgis_full_version_expected @@ -0,0 +1,5 @@ +topology_old_scripts|t +topology_newer_scripts|t +raster_newer_scripts|t +sfcgal_older_prerelease|t +sfcgal_newer_scripts|t diff --git a/regress/core/tests.mk.in b/regress/core/tests.mk.in index b6a87b629..73426ab2a 100644 --- a/regress/core/tests.mk.in +++ b/regress/core/tests.mk.in @@ -91,6 +91,7 @@ TESTS += \ $(top_srcdir)/regress/core/point_coordinates \ $(top_srcdir)/regress/core/polygonize \ $(top_srcdir)/regress/core/polyhedralsurface \ + $(top_srcdir)/regress/core/postgis_full_version \ $(top_srcdir)/regress/core/postgis_type_name \ $(top_srcdir)/regress/core/quantize_coordinates \ $(top_srcdir)/regress/core/regress \ ----------------------------------------------------------------------- Summary of changes: NEWS | 2 + postgis/postgis.sql.in | 78 ++++++++++++++++++++++++++++-- regress/core/postgis_full_version.sql | 76 +++++++++++++++++++++++++++++ regress/core/postgis_full_version_expected | 5 ++ regress/core/tests.mk.in | 1 + 5 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 regress/core/postgis_full_version.sql create mode 100644 regress/core/postgis_full_version_expected hooks/post-receive -- PostGIS From trac at osgeo.org Sat Jun 20 13:09:37 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 20:09:37 -0000 Subject: [PostGIS] #2808: Installing newer topology than version of PostGIS gives misleading upgrade message In-Reply-To: <046.c0afbf5cfe4dd7adadf3c1a5bdc2fd9e@osgeo.org> References: <046.c0afbf5cfe4dd7adadf3c1a5bdc2fd9e@osgeo.org> Message-ID: <061.b21fe31f42211ef58a87d153a6a5fa90@osgeo.org> #2808: Installing newer topology than version of PostGIS gives misleading upgrade message -----------------------+----------------------------- Reporter: robe | Owner: strk Type: defect | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: topology | Version: master Resolution: fixed | Keywords: -----------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"986bb6a1a6a133be10c234b8b04bd7bf1025fa05/git" 986bb6a/git]: {{{#!CommitTicketReference repository="git" revision="986bb6a1a6a133be10c234b8b04bd7bf1025fa05" Clarify newer component script version reporting Compare installed topology, raster, and SFCGAL script versions against the core script version using PostGIS version suffix ordering: dev < alpha < beta < rc < final. When component scripts are newer than core scripts, report that direction explicitly instead of saying the component procs need upgrade. Closes #2808 Closes https://github.com/postgis/postgis/pull/1057 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Sat Jun 20 14:14:45 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 21:14:45 -0000 Subject: [PostGIS] #2808: Installing newer topology than version of PostGIS gives misleading upgrade message In-Reply-To: <046.c0afbf5cfe4dd7adadf3c1a5bdc2fd9e@osgeo.org> References: <046.c0afbf5cfe4dd7adadf3c1a5bdc2fd9e@osgeo.org> Message-ID: <061.3d7519a891a3bf93c55e17de41061959@osgeo.org> #2808: Installing newer topology than version of PostGIS gives misleading upgrade message -----------------------+--------------------------- Reporter: robe | Owner: strk Type: defect | Status: reopened Priority: low | Milestone: PostGIS 3.7.0 Component: topology | Version: master Resolution: | Keywords: -----------------------+--------------------------- Changes (by robe): * milestone: PostGIS Fund Me => PostGIS 3.7.0 * resolution: fixed => * status: closed => reopened Comment: Getting error on woodie, which runs with standard_conforming_strings set to false. https://woodie.osgeo.org/repos/30/pipeline/4511/13 {{{ sql:/woodpecker/src/gitea.osgeo.org/postgis/postgis/build/pg14/regress/00 -regress-install/share/contrib/postgis/postgis.sql:3210: WARNING: nonstandard use of escape in a string literal LINE 9: '^([0-9]+)\.([0-9]+)\.([0-9]+)(dev|alpha|beta|rc)?([0-9]*... ^ HINT: Use the escape string syntax for escapes, e.g., E'\r\n'. psql:/woodpecker/src/gitea.osgeo.org/postgis/postgis/build/pg14/regress/00 -regress-install/share/contrib/postgis/postgis.sql:3210: WARNING: nonstandard use of escape in a string literal LINE 9: '^([0-9]+)\.([0-9]+)\.([0-9]+)(dev|alpha|beta|rc)?([0-9]*... ^ HINT: Use the escape string syntax for escapes, e.g., E'\r\n'. failed (Warnings encountered loading /woodpecker/src/gitea.osgeo.org/postgis/postgis/build/pg14/regress/00 -regress-install/share/contrib/postgis/postgis.sql: /tmp/pgis_reg/regress_log.tmp) ----------------------------------------------------------------------------- NOTICE: schema "public" already exists, skipping psql:/woodpecker/src/gitea.osgeo.org/postgis/postgis/build/pg14/regress/00 -regress-install/share/contrib/postgis/postgis.sql:3210: WARNING: nonstandard use of escape in a string literal LINE 9: '^([0-9]+)\.([0-9]+)\.([0-9]+)(dev|alpha|beta|rc)?([0-9]*... ^ HINT: Use the escape string syntax for escapes, e.g., E'\r\n'. psql:/woodpecker/src/gitea.osgeo.org/postgis/postgis/build/pg14/regress/00 -regress-install/share/contrib/postgis/postgis.sql:3210: WARNING: nonstandard use of escape in a string literal LINE 9: '^([0-9]+)\.([0-9]+)\.([0-9]+)(dev|alpha|beta|rc)?([0-9]*... ^ HINT: Use the escape string syntax for escapes, e.g., E'\r\n'. ----------------------------------------------------------------------------- make: *** [/woodpecker/src/gitea.osgeo.org/postgis/postgis/regress/runtest.mk:24: check-regress] Error }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Sat Jun 20 14:35:57 2026 From: trac at osgeo.org (PostGIS) Date: Sat, 20 Jun 2026 21:35:57 -0000 Subject: [PostGIS] #2807: [raster] ST_MapAlgebra injecting a default NODATA value of 0 In-Reply-To: <046.1965290ce97ad43b1fe6ec491356dc1b@osgeo.org> References: <046.1965290ce97ad43b1fe6ec491356dc1b@osgeo.org> Message-ID: <061.04b44373079e1c811c3d45bf77d9f51b@osgeo.org> #2807: [raster] ST_MapAlgebra injecting a default NODATA value of 0 ---------------------+--------------------------- Reporter: strk | Owner: dustymugs Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: raster | Version: master Resolution: fixed | Keywords: ---------------------+--------------------------- Changes (by robe): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 06:06:02 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 06:06:02 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-638-g0482d073a Message-ID: <20260621130603.820B01ACDC0@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 0482d073a2d174a544428664fa7cebcd36b7d96a (commit) via 37db33a47b8d380d6b58f8fcdf4824bfa0f2c847 (commit) from 986bb6a1a6a133be10c234b8b04bd7bf1025fa05 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 0482d073a2d174a544428664fa7cebcd36b7d96a Author: Darafei Praliaskouski Date: Sun Jun 21 00:56:01 2026 +0400 Expose loader action long options Add a shared loader action vocabulary and normalize raster2pgsql and shp2pgsql options into final LoaderPlan values. Short mode flags remain compatibility presets, and long action flags overlay the selected preset, defaulting to create/load when no mode is specified. Support idempotent table and index creation with the single --if-not-exists modifier on active creation actions. Keep --no-transaction as the public transaction modifier, reject invalid append/drop/load-without-create action sets, and preserve stable names for idempotent index creation. Inline shp2pgsql geometry/geography column DDL so table creation no longer needs AddGeometryColumn or DropGeometryColumn helper calls. diff --git a/NEWS b/NEWS index 495b17930..a9843c1aa 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed (Darafei Praliaskouski) - #2935, shp2pgsql --drop-table can emit DROP TABLE before prepare output (Darafei Praliaskouski) + - raster2pgsql and shp2pgsql expose loader actions as long options + (Darafei Praliaskouski) - #4208, Add single-geometry variants of ST_MaxDistance and ST_LongestLine (Darafei Praliaskouski) - [topology] FindVertexSegmentPairsBelowDistance function (Sandro Santilli) @@ -67,7 +69,7 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed (Sandro Santilli) - #3743, [raster] Document and test raster2pgsql -s FROM_SRID:SRID reprojection support (Darafei Praliaskouski) - - #4659, [raster] Add raster2pgsql --if-not-exists creation modifier + - #4659, [raster] Add raster2pgsql and shp2pgsql long loader action options (Darafei Praliaskouski) - #4749, Use point-in-polygon predicate fast paths for point-only GeometryCollections (Darafei Praliaskouski) diff --git a/doc/man/raster2pgsql.1 b/doc/man/raster2pgsql.1 index 10adc8d9e..5fd3e3f0d 100644 --- a/doc/man/raster2pgsql.1 +++ b/doc/man/raster2pgsql.1 @@ -57,7 +57,18 @@ Prepare mode. Only emit SQL to create the table. \fB\-\-if\-not\-exists\fR Use IF NOT EXISTS for table creation in \-c and \-p modes. When \-I is also specified, use IF NOT EXISTS for index creation too. This option cannot be used -with \-a or \-d. +with \-d. Append mode requires an explicit creation action. +.TP +\fB\-\-drop\-table\fR +Drop the target table before other actions. With no mode specified, the default +create/load actions still apply. In append mode this requires +\-\-create\-table when data is loaded. +.TP +\fB\-\-create\-table\fR +Create the target table. +.TP +\fB\-\-load\-data\fR +Load raster data into the target table. .TP \fB\-f\fR <\fIcolumn\fR> Specify the name of the raster column. @@ -79,14 +90,26 @@ Wrap PostgreSQL identifiers in quotes. \fB\-I\fR Create a GiST spatial index on the raster column. .TP +\fB\-\-create\-index\fR +Create a GiST spatial index on the raster column. +.TP \fB\-M\fR Run VACUUM ANALYZE on the raster table. This is most useful when appending to an existing table with \-a. .TP +\fB\-\-vacuum\fR +Run VACUUM on the raster table. +.TP +\fB\-\-analyze\fR +Run ANALYZE on the raster table. +.TP \fB\-C\fR Set the standard raster constraints after the rasters are loaded. Some constraints may fail if one or more input rasters violate the constraint. .TP +\fB\-\-add\-constraints\fR +Set the standard raster constraints after the rasters are loaded. +.TP \fB\-x\fR Disable setting the max extent constraint. Only applies with \-C. .TP @@ -118,6 +141,9 @@ Specify the output WKB format version. Only version 0 is currently supported. Execute each statement individually instead of wrapping the load in a transaction. .TP +\fB\-\-no\-transaction\fR +Execute statements individually, without using a transaction. +.TP \fB\-Y\fR [<\fImax_rows_per_copy\fR>] Use COPY statements instead of INSERT statements. If no row limit is provided, 50 rows are written per COPY. diff --git a/doc/man/shp2pgsql.1 b/doc/man/shp2pgsql.1 index 8ccc5d1bb..c840c60f9 100644 --- a/doc/man/shp2pgsql.1 +++ b/doc/man/shp2pgsql.1 @@ -49,8 +49,15 @@ This can be used if you need to completely separate the table creation and data loading steps. .TP \fB\-\-drop\-table\fR -Emits a DROP TABLE IF EXISTS statement before table creation. This can be -combined with \-c or \-p, but not with \-a. +Drop the target table before the selected actions. With no mode specified, the +default create/load actions still apply. +.TP +\fB\-\-create\-table\fR +Create the target table. This can be combined with \-a to build a custom +create-and-load action set. +.TP +\fB\-\-load\-data\fR +Load Shape file rows into the target table. .TP \fB\-D\fR Use the PostgreSQL "dump" format for the output data. This can be combined @@ -66,7 +73,10 @@ Execute each statement on its own, without using a transaction. This allows loading of the majority of good data when there are some bad geometries that generate errors. Note that this cannot be used with the \-D flag as the "dump" format always uses a transaction. -.TP +.TP +\fB\-\-no\-transaction\fR +Execute each statement individually, without using a transaction. +.TP \fB\-s\fR [<\fIFROM_SRID\fR>:]<\fISRID\fR> Creates and populates the geometry tables with the specified SRID. If FROM_SRID is given, the geometries will be reprojected. @@ -79,6 +89,9 @@ lat/lon data. At the moment the only spatial reference supported is 4326. \fB\-g\fR <\fIgeometry_column\fR> Specify the name of the geometry column (mostly useful in append mode). .TP +\fB\-\-create\-index\fR +Create a spatial index on the geometry column. +.TP \fB\-k\fR Keep identifiers case (column, schema and attributes). Note that attributes in Shapefile are usually all UPPERCASE. @@ -112,6 +125,15 @@ If this option is used the output will be encoded in UTF-8. \fB\-I\fR Create a GiST index on the geometry column. .TP +\fB\-\-if\-not\-exists\fR +Make active table and index creation actions use IF NOT EXISTS. +.TP +\fB\-\-analyze\fR +Analyze the table after loading. +.TP +\fB\-\-no\-analyze\fR +Prevent tables from being analyzed. +.TP \fB\-u\fR Create the target table as UNLOGGED. This can speed up loading transient staging data, but PostgreSQL does not preserve unlogged table contents after diff --git a/doc/using_raster_dataman.xml b/doc/using_raster_dataman.xml index 64973efc0..7568d3ada 100644 --- a/doc/using_raster_dataman.xml +++ b/doc/using_raster_dataman.xml @@ -145,8 +145,28 @@ Available GDAL raster formats: and modes. When is also specified, use IF NOT EXISTS for index creation too. This - option cannot be used with or - . + option cannot be used with . Append mode + requires an explicit creation action. + + + + + + Atomic loader actions + + + The short modes are presets over explicit actions. The equivalent + long options are , + , , + , + , , + , and . + Add + to make active creation actions use IF NOT EXISTS. + emits + DROP TABLE IF EXISTS before the selected + actions. With no mode specified, the default create/load actions + still apply. diff --git a/loader/Makefile.in b/loader/Makefile.in index c17fbce6b..657207cad 100644 --- a/loader/Makefile.in +++ b/loader/Makefile.in @@ -99,7 +99,7 @@ shp2pgsql-gui.res: shp2pgsql-gui.rc shp2pgsql-gui.ico $(LIBLWGEOM): $(MAKE) -C ../liblwgeom -shp2pgsql-core.o: shp2pgsql-core.c shp2pgsql-core.h shpcommon.h +shp2pgsql-core.o: shp2pgsql-core.c shp2pgsql-core.h shpcommon.h loader_actions.h $(CC) $(CPPFLAGS) $(CFLAGS) -c $< pgsql2shp-core.o: pgsql2shp-core.c pgsql2shp-core.h shpcommon.h @@ -119,7 +119,7 @@ $(SHP2PGSQL-CLI): $(SHPLIB_OBJS) shp2pgsql-core.o shp2pgsql-cli.o $(LIBLWGEOM) $(LIBTOOL) --mode=link \ $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(GETTEXT_LDFLAGS) $(ICONV_LDFLAGS) -shp2pgsql-gui.o: shp2pgsql-gui.c shp2pgsql-core.h shpcommon.h +shp2pgsql-gui.o: shp2pgsql-gui.c shp2pgsql-core.h shpcommon.h loader_actions.h $(CC) $(CPPFLAGS) $(CFLAGS) $(GTK_CFLAGS) $(PGSQL_FE_CPPFLAGS) -o $@ -c $< $(SHP2PGSQL-GUI): $(SHPLIB_OBJS) shp2pgsql-core.o shp2pgsql-gui.o pgsql2shp-core.o $(LIBLWGEOM) $(GTK_WIN32_RES) diff --git a/loader/README.shp2pgsql b/loader/README.shp2pgsql index d5afc8e19..0fd7685d8 100644 --- a/loader/README.shp2pgsql +++ b/loader/README.shp2pgsql @@ -49,8 +49,18 @@ OPTIONS rate the table creation and data loading steps. --drop-table - Emits a DROP TABLE IF EXISTS statement before table creation. - This can be combined with -c or -p, but not with -a. + Drop the target table before the selected actions. With no mode + specified, the default create/load actions still apply. + + --create-table + Create the target table. This can be combined with -a to build a + custom create-and-load action set. + + --if-not-exists + Make active table and index creation actions use IF NOT EXISTS. + + --load-data + Load Shape file rows into the target table. -D Use the PostgreSQL "dump" format for the output data. This can be combined with -a, -c and -d. It is much faster to load than @@ -68,6 +78,9 @@ OPTIONS Specify the name of the geometry column (mostly useful in append mode). + --create-index + Create a spatial index on the geometry column. + -k Keep identifiers case (column, schema and attributes). Note that attributes in Shapefile are usually all UPPERCASE. @@ -98,6 +111,15 @@ OPTIONS -? Display version and usage information. + --analyze + Analyze the table after loading. + + --no-analyze + Prevent tables from being analyzed. + + --no-transaction + Execute each statement individually, without using a transaction. + INSTALLATION To compile the program from source, simply run "make" in the source diff --git a/loader/cunit/Makefile.in b/loader/cunit/Makefile.in index e5ee4df2f..9798d1ba1 100644 --- a/loader/cunit/Makefile.in +++ b/loader/cunit/Makefile.in @@ -112,6 +112,8 @@ cu_tester: $(LOADER_OBJS) $(OBJS) $(OBJS): %.o: %.c $(CC) $(CFLAGS) $(CUNIT_CPPFLAGS) $(GTK_CFLAGS) $(PGSQL_FE_CPPFLAGS) -c -o $@ $< +cu_shp2pgsql.o: ../shp2pgsql-core.h ../loader_actions.h + # Clean target clean: rm -f $(OBJS) diff --git a/loader/cunit/cu_shp2pgsql.c b/loader/cunit/cu_shp2pgsql.c index 0eefab957..01be2be03 100644 --- a/loader/cunit/cu_shp2pgsql.c +++ b/loader/cunit/cu_shp2pgsql.c @@ -18,6 +18,8 @@ void test_ShpLoaderCreate(void); void test_ShpLoaderDestroy(void); void test_ShpLoaderGetSQLHeader_drop_prepare(void); +void test_ShpLoaderGetSQLHeader_if_not_exists_table_modifier(void); +void test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier(void); SHPLOADERCONFIG *loader_config; SHPLOADERSTATE *loader_state; @@ -37,8 +39,15 @@ CU_pSuite register_shp2pgsql_suite(void) if ((NULL == CU_add_test(pSuite, "test_ShpLoaderCreate()", test_ShpLoaderCreate)) || (NULL == CU_add_test(pSuite, "test_ShpLoaderDestroy()", test_ShpLoaderDestroy)) || - (NULL == - CU_add_test(pSuite, "test_ShpLoaderGetSQLHeader_drop_prepare()", test_ShpLoaderGetSQLHeader_drop_prepare))) + (NULL == CU_add_test(pSuite, + "test_ShpLoaderGetSQLHeader_drop_prepare()", + test_ShpLoaderGetSQLHeader_drop_prepare)) || + (NULL == CU_add_test(pSuite, + "test_ShpLoaderGetSQLHeader_if_not_exists_table_modifier()", + test_ShpLoaderGetSQLHeader_if_not_exists_table_modifier)) || + (NULL == CU_add_test(pSuite, + "test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier()", + test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier))) { CU_cleanup_registry(); return NULL; @@ -87,14 +96,19 @@ test_ShpLoaderGetSQLHeader_drop_prepare(void) loader_config = (SHPLOADERCONFIG *)calloc(1, sizeof(SHPLOADERCONFIG)); set_loader_config_defaults(loader_config); - loader_config->opt = 'p'; - loader_config->drop_table = 1; + loader_config->actions.mode = 'p'; + loader_config->actions.drop_table = 1; /* This header-only test does not open a shapefile, so avoid geometry metadata. */ loader_config->readshape = 0; loader_config->table = "loadedshp"; loader_config->geo_col = "the_geom"; loader_state = ShpLoaderCreate(loader_config); + loader_state->pgtype = "POINT"; + loader_state->pgdims = 2; + loader_state->to_srid = 0; + loader_state->num_fields = 0; + CU_ASSERT_EQUAL(ShpLoaderGetSQLHeader(loader_state, &header), SHPLOADEROK); CU_ASSERT_PTR_NOT_NULL(header); @@ -108,3 +122,56 @@ test_ShpLoaderGetSQLHeader_drop_prepare(void) free(header); ShpLoaderDestroy(loader_state); } + +void +test_ShpLoaderGetSQLHeader_if_not_exists_table_modifier(void) +{ + char *header = NULL; + + loader_config = (SHPLOADERCONFIG *)calloc(1, sizeof(SHPLOADERCONFIG)); + set_loader_config_defaults(loader_config); + loader_config->actions.mode = 'p'; + loader_config->actions.create_table = LOADER_CREATE_IF_NOT_EXISTS; + loader_config->actions.create_table_set = 1; + loader_config->table = "loadedshp"; + loader_config->geo_col = "the_geom"; + + loader_state = ShpLoaderCreate(loader_config); + loader_state->pgtype = "POINT"; + loader_state->pgdims = 2; + loader_state->to_srid = 0; + loader_state->num_fields = 0; + + CU_ASSERT_EQUAL(ShpLoaderGetSQLHeader(loader_state, &header), SHPLOADEROK); + CU_ASSERT_PTR_NOT_NULL(header); + CU_ASSERT_PTR_NOT_NULL(strstr(header, + "CREATE TABLE IF NOT EXISTS \"loadedshp\" " + "(gid serial PRIMARY KEY,\n" + "\"the_geom\" geometry(POINT,0));")); + CU_ASSERT_PTR_NULL(strstr(header, "AddGeometryColumn")); + CU_ASSERT_PTR_NULL(strstr(header, "ALTER TABLE")); + + free(header); + ShpLoaderDestroy(loader_state); +} + +void +test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier(void) +{ + char *footer = NULL; + + loader_config = (SHPLOADERCONFIG *)calloc(1, sizeof(SHPLOADERCONFIG)); + set_loader_config_defaults(loader_config); + loader_config->table = "loadedshp"; + loader_config->geo_col = "the_geom"; + loader_config->actions.create_index = LOADER_CREATE_IF_NOT_EXISTS; + loader_config->actions.create_index_set = 1; + + loader_state = ShpLoaderCreate(loader_config); + CU_ASSERT_EQUAL(ShpLoaderGetSQLFooter(loader_state, &footer), SHPLOADEROK); + CU_ASSERT_PTR_NOT_NULL(footer); + CU_ASSERT_PTR_NOT_NULL(strstr(footer, "CREATE INDEX IF NOT EXISTS \"loadedshp_the_geom_gist\"")); + + free(footer); + ShpLoaderDestroy(loader_state); +} diff --git a/loader/loader_actions.h b/loader/loader_actions.h new file mode 100644 index 000000000..ec0c4c095 --- /dev/null +++ b/loader/loader_actions.h @@ -0,0 +1,67 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.net + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public Licence. See the COPYING file. + * + **********************************************************************/ + +#ifndef LOADER_ACTIONS_H +#define LOADER_ACTIONS_H 1 + +#include + +typedef enum loader_create_mode +{ + LOADER_CREATE_NONE = 0, + LOADER_CREATE_ALWAYS, + LOADER_CREATE_IF_NOT_EXISTS +} LoaderCreateMode; + +typedef enum loader_transaction_mode +{ + LOADER_TRANSACTION_OFF = 0, + LOADER_TRANSACTION_ON +} LoaderTransactionMode; + +typedef struct loader_plan { + int drop_table; + LoaderCreateMode create_table; + int load_data; + LoaderCreateMode create_index; + int add_constraints; + int vacuum; + int analyze; + LoaderTransactionMode transaction; +} LoaderPlan; + +typedef struct loader_action_options { + char mode; + int mode_set; + int if_not_exists; + int drop_table; + LoaderCreateMode create_table; + int create_table_set; + int load_data; + int load_data_set; + LoaderCreateMode create_index; + int create_index_set; + int add_constraints; + int vacuum; + int analyze; +} LoaderActionOptions; + +static inline bool +loader_action_set_create_mode(LoaderCreateMode *current_mode, int *is_set, LoaderCreateMode new_mode) +{ + if (*is_set && *current_mode != new_mode) + return false; + + *current_mode = new_mode; + *is_set = true; + return true; +} + +#endif /* LOADER_ACTIONS_H */ diff --git a/loader/shp2pgsql-cli.c b/loader/shp2pgsql-cli.c index 28d1a1c25..bcd03e516 100644 --- a/loader/shp2pgsql-cli.c +++ b/loader/shp2pgsql-cli.c @@ -47,6 +47,7 @@ usage() printf(_( " -k Keep postgresql identifiers case.\n" )); printf(_( " -i Use int4 type for all integer dbf fields.\n" )); printf(_( " -I Create a spatial index on the geocolumn.\n" )); + printf(_(" --create-index Create a spatial index on the geocolumn.\n")); printf(_( " -u Create the table as UNLOGGED.\n" )); printf(_(" -m Specify a file containing a set of mappings of (long) column\n" " names to 10 character DBF column names. The content of the file is one or\n" @@ -63,7 +64,10 @@ usage() " attribute column. (default: \"UTF-8\")\n" )); printf(_( " -N NULL geometries handling policy (insert*,skip,abort).\n" )); printf(_( " -n Only import DBF file.\n" )); - printf(_(" --drop-table Emit DROP TABLE IF EXISTS before create or prepare output.\n")); + printf(_(" --drop-table Drop the target table before the selected actions.\n")); + printf(_(" --create-table Create the target table.\n")); + printf(_(" --if-not-exists Make active creation actions use IF NOT EXISTS.\n")); + printf(_(" --load-data Load shapefile rows into the target table.\n")); printf(_( " -T Specify the tablespace for the new table.\n" " Note that indexes will still use the default tablespace unless the\n" " -X flag is also used.\n")); @@ -71,13 +75,15 @@ usage() " This applies to the primary key, and the spatial index if\n" " the -I flag is used.\n" )); printf(_( " -Z Prevent tables from being analyzed.\n" )); + printf(_(" --analyze Analyze the table after loading.\n")); + printf(_(" --no-analyze Prevent tables from being analyzed.\n")); + printf(_(" --no-transaction Execute each statement individually.\n")); printf(_( " -? Display this help screen.\n" )); printf( "\n" ); printf(_( " An argument of `--' disables further option processing.\n" )); printf(_( " (useful for unusual file names starting with '-')\n" )); } - int main (int argc, char **argv) { @@ -109,12 +115,79 @@ main (int argc, char **argv) /* Keep the flag list alphabetic so it's easy to see what's left. */ while (pgis_optind < argc) { + if (strcmp(argv[pgis_optind], "--") == 0) + { + pgis_optind++; + break; + } + if (strcmp(argv[pgis_optind], "--drop-table") == 0) { - config->drop_table = 1; + config->actions.drop_table = 1; pgis_optind++; continue; } + if (strcmp(argv[pgis_optind], "--create-table") == 0) + { + if (!loader_action_set_create_mode( + &config->actions.create_table, &config->actions.create_table_set, LOADER_CREATE_ALWAYS)) + { + fprintf(stderr, + "Invalid argument combination - conflicting table creation semantics\n"); + exit(1); + } + pgis_optind++; + continue; + } + if (strcmp(argv[pgis_optind], "--load-data") == 0) + { + config->actions.load_data = 1; + config->actions.load_data_set = 1; + pgis_optind++; + continue; + } + if (strcmp(argv[pgis_optind], "--create-index") == 0) + { + if (!loader_action_set_create_mode( + &config->actions.create_index, &config->actions.create_index_set, LOADER_CREATE_ALWAYS)) + { + fprintf(stderr, + "Invalid argument combination - conflicting index creation semantics\n"); + exit(1); + } + pgis_optind++; + continue; + } + if (strcmp(argv[pgis_optind], "--if-not-exists") == 0) + { + config->actions.if_not_exists = 1; + pgis_optind++; + continue; + } + if (strcmp(argv[pgis_optind], "--analyze") == 0) + { + config->analyze = 1; + pgis_optind++; + continue; + } + if (strcmp(argv[pgis_optind], "--no-analyze") == 0) + { + config->analyze = 0; + pgis_optind++; + continue; + } + if (strcmp(argv[pgis_optind], "--no-transaction") == 0) + { + config->usetransaction = 0; + pgis_optind++; + continue; + } + if (strncmp(argv[pgis_optind], "--", 2) == 0) + { + fprintf(stderr, "Unknown option: %s\n", argv[pgis_optind]); + usage(); + exit(1); + } c = pgis_getopt(argc, argv, "-?acdeg:ikm:nps:t:uwDGIN:ST:W:X:Z"); if (c == EOF) @@ -130,7 +203,8 @@ main (int argc, char **argv) case 'd': case 'a': case 'p': - config->opt = c; + config->actions.mode = c; + config->actions.mode_set = 1; break; case 'D': @@ -188,7 +262,13 @@ main (int argc, char **argv) break; case 'I': - config->createindex = 1; + if (!loader_action_set_create_mode( + &config->actions.create_index, &config->actions.create_index_set, LOADER_CREATE_ALWAYS)) + { + fprintf(stderr, + "Invalid argument combination - conflicting index creation semantics\n"); + exit(1); + } break; case 'u': @@ -279,10 +359,27 @@ main (int argc, char **argv) exit(1); } - if (config->drop_table && config->opt == 'a') { - fprintf(stderr, "Invalid argument combination - cannot use both --drop-table and -a\n"); - exit(1); + const int has_table_creation = + config->actions.create_table_set + ? config->actions.create_table != LOADER_CREATE_NONE + : config->actions.mode != 'a'; + const int has_index_creation = + config->actions.create_index_set && config->actions.create_index == LOADER_CREATE_ALWAYS; + const int has_load_data = + config->actions.load_data_set ? config->actions.load_data : config->actions.mode != 'p'; + + if (config->actions.if_not_exists && !has_table_creation && !has_index_creation) + { + fprintf(stderr, "--if-not-exists requires an active creation action\n"); + exit(1); + } + + if (config->actions.drop_table && has_load_data && !has_table_creation) + { + fprintf(stderr, "Invalid argument combination - --drop-table with load data requires --create-table\n"); + exit(1); + } } /* Determine the shapefile name from the next argument, if no shape file, exit. */ @@ -404,7 +501,7 @@ main (int argc, char **argv) free(header); /* If we are not in "prepare" mode, go ahead and write out the data. */ - if (state->config->load_data) + if (state->config->plan.load_data) { /* If in COPY mode, output the COPY statement */ diff --git a/loader/shp2pgsql-core.c b/loader/shp2pgsql-core.c index fa8bffe75..52226802a 100644 --- a/loader/shp2pgsql-core.c +++ b/loader/shp2pgsql-core.c @@ -754,6 +754,56 @@ strtolower(char *s) s[j] = tolower(s[j]); } +static void +pgtype_typmod_name(const SHPLOADERSTATE *state, char *buf, size_t len) +{ + const char *suffix = ""; + size_t base_len = strlen(state->pgtype); + + if (state->pgdims == 4 && state->has_z && state->has_m) + suffix = "ZM"; + else if (state->pgdims == 3 && state->has_z) + suffix = "Z"; + else if (state->pgdims == 3 && state->has_m) + suffix = "M"; + + if (base_len > 0 && state->pgtype[base_len - 1] == 'M') + base_len--; + + snprintf(buf, len, "%.*s%s", (int)base_len, state->pgtype, suffix); +} + +static void +append_qualified_table(stringbuffer_t *sb, const char *schema, const char *table) +{ + if (schema) + stringbuffer_aprintf(sb, "\"%s\".", schema); + stringbuffer_aprintf(sb, "\"%s\"", table); +} + +static void +append_primary_key_ddl(const SHPLOADERSTATE *state, stringbuffer_t *sb) +{ + stringbuffer_aprintf(sb, "ALTER TABLE "); + append_qualified_table(sb, state->config->schema, state->config->table); + stringbuffer_aprintf(sb, " ADD PRIMARY KEY (gid);\n"); + + if (state->config->idxtablespace != NULL) + { + stringbuffer_aprintf(sb, "ALTER INDEX "); + if (state->config->schema) + stringbuffer_aprintf(sb, "\"%s\".", state->config->schema); + stringbuffer_aprintf( + sb, "\"%s_pkey\" SET TABLESPACE \"%s\";\n", state->config->table, state->config->idxtablespace); + } +} + +static int +plan_has_transactional_work(const LoaderPlan *plan) +{ + return plan->create_table != LOADER_CREATE_NONE || plan->load_data || + plan->create_index != LOADER_CREATE_NONE; +} /* Default configuration settings */ void @@ -769,12 +819,13 @@ set_loader_config_defaults(SHPLOADERCONFIG *config) config->geography = 0; config->quoteidentifiers = 0; config->forceint4 = 0; - config->createindex = 0; + config->createindex = LOADER_CREATE_NONE; config->unlogged = 0; - config->drop_table = 0; - config->drop_geometry_column = 0; - config->create_table = 1; - config->load_data = 1; + memset(&config->actions, 0, sizeof(config->actions)); + config->actions.mode = 'c'; + config->actions.create_table = LOADER_CREATE_ALWAYS; + config->actions.load_data = 1; + memset(&config->plan, 0, sizeof(config->plan)); config->analyze = 1; config->readshape = 1; config->force_output = FORCE_OUTPUT_DISABLE; @@ -792,12 +843,57 @@ set_loader_config_defaults(SHPLOADERCONFIG *config) static void set_loader_config_actions(SHPLOADERCONFIG *config) { - const int explicit_drop_table = config->drop_table; + LoaderActionOptions *actions = &config->actions; - config->drop_table = explicit_drop_table || config->opt == 'd'; - config->drop_geometry_column = config->opt == 'd'; - config->create_table = config->opt != 'a'; - config->load_data = config->opt != 'p'; + memset(&config->plan, 0, sizeof(config->plan)); + config->plan.transaction = config->usetransaction ? LOADER_TRANSACTION_ON : LOADER_TRANSACTION_OFF; + + switch (actions->mode) + { + case 'd': + config->plan.drop_table = 1; + config->plan.create_table = LOADER_CREATE_ALWAYS; + config->plan.load_data = 1; + break; + case 'a': + config->plan.load_data = 1; + break; + case 'p': + config->plan.create_table = LOADER_CREATE_ALWAYS; + break; + case 'c': + default: + config->plan.create_table = LOADER_CREATE_ALWAYS; + config->plan.load_data = 1; + break; + } + + if (actions->drop_table) + config->plan.drop_table = 1; + if (actions->create_table_set) + config->plan.create_table = actions->create_table; + if (actions->load_data_set) + config->plan.load_data = actions->load_data; + + config->plan.create_index = config->createindex; + if (actions->create_index_set) + config->plan.create_index = actions->create_index; + + if (actions->if_not_exists) + { + if (config->plan.create_table == LOADER_CREATE_ALWAYS) + config->plan.create_table = LOADER_CREATE_IF_NOT_EXISTS; + if (config->plan.create_index == LOADER_CREATE_ALWAYS) + config->plan.create_index = LOADER_CREATE_IF_NOT_EXISTS; + } + + if (actions->analyze) + config->plan.analyze = 1; + else if (config->analyze && (config->plan.create_table != LOADER_CREATE_NONE || config->plan.load_data || + config->plan.create_index != LOADER_CREATE_NONE)) + { + config->plan.analyze = 1; + } } /* Create a new shapefile state object */ @@ -1301,6 +1397,8 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) stringbuffer_t *sb; char *ret; int j; + const int use_transaction = + state->config->plan.transaction == LOADER_TRANSACTION_ON && plan_has_transactional_work(&state->config->plan); /* Create the stringbuffer containing the header; we use this API as it's easier for handling string resizing during append */ @@ -1317,67 +1415,44 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) stringbuffer_aprintf(sb, "SET STANDARD_CONFORMING_STRINGS TO ON;\n"); /* Drop table if requested */ - if (state->config->drop_table) + if (state->config->plan.drop_table) { - /** - * TODO: if the table has more then one geometry column - * the DROP TABLE call will leave spurious records in - * geometry_columns. - * - * If the geometry column in the table being dropped - * does not match 'the_geom' or the name specified with - * -g an error is returned by DropGeometryColumn. - * - * The table to be dropped might not exist. - */ if (state->config->schema) { - if (state->config->drop_geometry_column && state->config->readshape == 1 && - (!state->config->geography)) - { - stringbuffer_aprintf(sb, "SELECT DropGeometryColumn('%s','%s','%s');\n", - state->config->schema, state->config->table, state->geo_col); - } - stringbuffer_aprintf(sb, "DROP TABLE IF EXISTS \"%s\".\"%s\";\n", state->config->schema, state->config->table); } else { - if (state->config->drop_geometry_column && state->config->readshape == 1 && - (!state->config->geography)) - { - stringbuffer_aprintf(sb, "SELECT DropGeometryColumn('','%s','%s');\n", - state->config->table, state->geo_col); - } - stringbuffer_aprintf(sb, "DROP TABLE IF EXISTS \"%s\";\n", state->config->table); } } /* Start of transaction if we are using one */ - if (state->config->usetransaction) + if (use_transaction) { stringbuffer_aprintf(sb, "BEGIN;\n"); } /* Create the spatial table when requested by the selected actions. */ - if (state->config->create_table) + if (state->config->plan.create_table != LOADER_CREATE_NONE) { + const int if_not_exists = state->config->plan.create_table == LOADER_CREATE_IF_NOT_EXISTS; + /* - * Create a table for inserting the shapes into with appropriate - * columns and types - */ - if (state->config->schema) + * Create a table for inserting the shapes into with appropriate + * columns and types + */ + stringbuffer_aprintf(sb, + "CREATE %sTABLE %s", + state->config->unlogged ? "UNLOGGED " : "", + if_not_exists ? "IF NOT EXISTS " : ""); + append_qualified_table(sb, state->config->schema, state->config->table); + stringbuffer_aprintf(sb, " (gid serial%s", if_not_exists ? " PRIMARY KEY" : ""); + + if (if_not_exists && state->config->idxtablespace != NULL) { - stringbuffer_aprintf(sb, "CREATE %sTABLE \"%s\".\"%s\" (gid serial", - state->config->unlogged ? "UNLOGGED " : "", - state->config->schema, state->config->table); - } - else - { - stringbuffer_aprintf(sb, "CREATE %sTABLE \"%s\" (gid serial", - state->config->unlogged ? "UNLOGGED " : "", state->config->table); + stringbuffer_aprintf(sb, " USING INDEX TABLESPACE \"%s\"", state->config->idxtablespace); } /* Generate the field types based upon the shapefile information */ @@ -1401,22 +1476,22 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) } } - /* Add the geography column directly to the table definition, we don't - need to do an AddGeometryColumn() call. */ - if (state->config->readshape == 1 && state->config->geography) + /* + * geometry_columns is a view in current PostGIS, so typmod column + * DDL is equivalent to the default AddGeometryColumn path. + */ + if (state->config->readshape == 1) { - char *dimschar; - - if (state->pgdims == 4) - dimschar = "ZM"; - else - dimschar = ""; - - if (state->to_srid == SRID_UNKNOWN ){ + const char *coltype = state->config->geography ? "geography" : "geometry"; + char typmod_type[64]; + if (state->config->geography && state->to_srid == SRID_UNKNOWN) + { state->to_srid = 4326; } - stringbuffer_aprintf(sb, ",\n\"%s\" geography(%s%s,%d)", state->geo_col, state->pgtype, dimschar, state->to_srid); + pgtype_typmod_name(state, typmod_type, sizeof(typmod_type)); + stringbuffer_aprintf( + sb, ",\n\"%s\" %s(%s,%d)", state->geo_col, coltype, typmod_type, state->to_srid); } stringbuffer_aprintf(sb, ")"); @@ -1427,61 +1502,8 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) } stringbuffer_aprintf(sb, ";\n"); - /* Create the primary key. This is done separately because the index for the PK needs - * to be in the correct tablespace. */ - - /* TODO: Currently PostgreSQL does not allow specifying an index to use for a PK (so you get - * a default one called table_pkey) and it does not provide a way to create a PK index - * in a specific tablespace. So as a hacky solution we create the PK, then move the - * index to the correct tablespace. Eventually this should be: - * CREATE INDEX table_pkey on table(gid) TABLESPACE tblspc; - * ALTER TABLE table ADD PRIMARY KEY (gid) USING INDEX table_pkey; - * A patch has apparently been submitted to PostgreSQL to enable this syntax, see this thread: - * http://archives.postgresql.org/pgsql-hackers/2011-01/msg01405.php */ - stringbuffer_aprintf(sb, "ALTER TABLE "); - - /* Schema is optional, include if present. */ - if (state->config->schema) - { - stringbuffer_aprintf(sb, "\"%s\".",state->config->schema); - } - stringbuffer_aprintf(sb, "\"%s\" ADD PRIMARY KEY (gid);\n", state->config->table); - - /* Tablespace is optional for the index. */ - if (state->config->idxtablespace != NULL) - { - stringbuffer_aprintf(sb, "ALTER INDEX "); - if (state->config->schema) - { - stringbuffer_aprintf(sb, "\"%s\".",state->config->schema); - } - - /* WARNING: We're assuming the default "table_pkey" name for the primary - * key index. PostgreSQL may use "table_pkey1" or similar in the - * case of a name conflict, so you may need to edit the produced - * SQL in this rare case. */ - stringbuffer_aprintf(sb, "\"%s_pkey\" SET TABLESPACE \"%s\";\n", - state->config->table, state->config->idxtablespace); - } - - /* Create the geometry column with an addgeometry call */ - if (state->config->readshape == 1 && (!state->config->geography)) - { - /* If they didn't specify a target SRID, see if they specified a source SRID. */ - int32_t srid = state->to_srid; - if (state->config->schema) - { - stringbuffer_aprintf(sb, "SELECT AddGeometryColumn('%s','%s','%s','%d',", - state->config->schema, state->config->table, state->geo_col, srid); - } - else - { - stringbuffer_aprintf(sb, "SELECT AddGeometryColumn('','%s','%s','%d',", - state->config->table, state->geo_col, srid); - } - - stringbuffer_aprintf(sb, "'%s',%d);\n", state->pgtype, state->pgdims); - } + if (!if_not_exists) + append_primary_key_ddl(state, sb); } /**If we are in dump mode and a transform was asked for need to create a temp table to store original data @@ -1900,6 +1922,8 @@ ShpLoaderGetSQLFooter(SHPLOADERSTATE *state, char **strfooter) { stringbuffer_t *sb; char *ret; + const int use_transaction = + state->config->plan.transaction == LOADER_TRANSACTION_ON && plan_has_transactional_work(&state->config->plan); /* Create the stringbuffer containing the header; we use this API as it's easier for handling string resizing during append */ @@ -1926,9 +1950,14 @@ ShpLoaderGetSQLFooter(SHPLOADERSTATE *state, char **strfooter) } /* Create gist index if specified and not in "prepare" mode */ - if (state->config->readshape && state->config->createindex) + if (state->config->readshape && state->config->plan.create_index != LOADER_CREATE_NONE) { - stringbuffer_aprintf(sb, "CREATE INDEX ON "); + stringbuffer_aprintf(sb, "CREATE INDEX "); + if (state->config->plan.create_index == LOADER_CREATE_IF_NOT_EXISTS) + { + stringbuffer_aprintf(sb, "IF NOT EXISTS \"%s_%s_gist\" ", state->config->table, state->geo_col); + } + stringbuffer_aprintf(sb, "ON "); /* Schema is optional, include if present. */ if (state->config->schema) { @@ -1944,13 +1973,12 @@ ShpLoaderGetSQLFooter(SHPLOADERSTATE *state, char **strfooter) } /* End the transaction if there is one. */ - if (state->config->usetransaction) + if (use_transaction) { stringbuffer_aprintf(sb, "COMMIT;\n"); } - - if(state->config->analyze) + if (state->config->plan.analyze) { /* Always ANALYZE the resulting table, for better stats */ stringbuffer_aprintf(sb, "ANALYZE "); diff --git a/loader/shp2pgsql-core.h b/loader/shp2pgsql-core.h index ed8e5ae71..b106e2cde 100644 --- a/loader/shp2pgsql-core.h +++ b/loader/shp2pgsql-core.h @@ -26,6 +26,7 @@ #include "shapefil.h" #include "shpcommon.h" #include "getopt.h" +#include "loader_actions.h" #include "../liblwgeom/stringbuffer.h" @@ -111,23 +112,15 @@ typedef struct shp_loader_config /* 0 = allow int8 fields, 1 = no int8 fields */ int forceint4; - /* 0 = no index, 1 = create index after load */ - int createindex; + /* index creation action */ + LoaderCreateMode createindex; /* 0 = logged table, 1 = create as UNLOGGED table */ int unlogged; - /* action: emit DROP TABLE before create/prepare */ - int drop_table; - - /* action: remove geometry_columns entry before dropping the table */ - int drop_geometry_column; - - /* action: create the target table */ - int create_table; - - /* action: load rows from the input file */ - int load_data; + /* raw action options and normalized execution plan */ + LoaderActionOptions actions; + LoaderPlan plan; /* 0 = don't analyze tables , 1 = analyze tables */ int analyze; diff --git a/loader/shp2pgsql-gui.c b/loader/shp2pgsql-gui.c index 853a8c3af..51307ccba 100644 --- a/loader/shp2pgsql-gui.c +++ b/loader/shp2pgsql-gui.c @@ -587,9 +587,9 @@ update_loader_config_globals_from_options_ui(SHPLOADERCONFIG *config) /* Create spatial index after load */ if (createindex) - config->createindex = 1; + config->createindex = LOADER_CREATE_ALWAYS; else - config->createindex = 0; + config->createindex = LOADER_CREATE_NONE; /* Read the .shp file, don't ignore it */ if (dbfonly) @@ -597,7 +597,7 @@ update_loader_config_globals_from_options_ui(SHPLOADERCONFIG *config) config->readshape = 0; /* There will be no spatial column so don't create a spatial index */ - config->createindex = 0; + config->createindex = LOADER_CREATE_NONE; } else config->readshape = 1; @@ -1188,7 +1188,7 @@ validate_remote_loader_columns(SHPLOADERCONFIG *config, PGresult *result) { ntuples = PQntuples(result); - switch (config->opt) + switch (config->actions.mode) { case 'c': /* If we have a row matching the table given in the config, then it already exists */ @@ -1540,7 +1540,19 @@ pgui_action_import(GtkWidget *widget, gpointer data) loader_file_config = (SHPLOADERCONFIG *)gptr; pgui_logf("\n=============================="); - pgui_logf("Importing with configuration: %s, %s, %s, %s, mode=%c, dump=%d, simple=%d, geography=%d, index=%d, shape=%d, srid=%d", loader_file_config->table, loader_file_config->schema, loader_file_config->geo_col, loader_file_config->shp_file, loader_file_config->opt, loader_file_config->dump_format, loader_file_config->simple_geometries, loader_file_config->geography, loader_file_config->createindex, loader_file_config->readshape, loader_file_config->sr_id); + pgui_logf( + "Importing with configuration: %s, %s, %s, %s, mode=%c, dump=%d, simple=%d, geography=%d, index=%d, shape=%d, srid=%d", + loader_file_config->table, + loader_file_config->schema, + loader_file_config->geo_col, + loader_file_config->shp_file, + loader_file_config->actions.mode, + loader_file_config->dump_format, + loader_file_config->simple_geometries, + loader_file_config->geography, + loader_file_config->createindex, + loader_file_config->readshape, + loader_file_config->sr_id); /* * Loop through the items in the shapefile @@ -1610,7 +1622,7 @@ pgui_action_import(GtkWidget *widget, gpointer data) goto import_cleanup; /* Load rows when requested by the selected actions. */ - if (state->config->load_data) + if (state->config->plan.load_data) { int numrecords = ShpLoaderGetRecordCount(state); int records_per_tick = (numrecords / 200) - 1; @@ -1714,7 +1726,7 @@ pgui_action_import(GtkWidget *widget, gpointer data) goto import_cleanup; } } - } /* if (state->config->load_data) */ + } /* if (state->config->plan.load_data) */ /* Only continue if we didn't abort part way through */ if (is_running) @@ -1730,7 +1742,7 @@ pgui_action_import(GtkWidget *widget, gpointer data) } /* Just in case index creation takes a long time, update the progress text */ - if (state->config->createindex) + if (state->config->plan.create_index != LOADER_CREATE_NONE) { gtk_label_set_text(GTK_LABEL(label_progress), _("Creating spatial index...")); @@ -1756,7 +1768,7 @@ import_cleanup: pg_connection = NULL; /* If we didn't finish inserting all of the items (and we expected to), an error occurred */ - if ((state->config->load_data && i != ShpLoaderGetRecordCount(state)) || !ret) + if ((state->config->plan.load_data && i != ShpLoaderGetRecordCount(state)) || !ret) pgui_logf(_("Shapefile import failed.")); else pgui_logf(_("Shapefile import completed.")); @@ -2173,23 +2185,23 @@ pgui_action_handle_tree_combo(GtkCellRendererCombo *combo, switch (opt) { case 'a': - loader_file_config->opt = 'a'; + loader_file_config->actions.mode = 'a'; /* Other half of index creation hack */ - loader_file_config->createindex = 0; + loader_file_config->createindex = LOADER_CREATE_NONE; break; case 'd': - loader_file_config->opt = 'd'; + loader_file_config->actions.mode = 'd'; break; case 'p': - loader_file_config->opt = 'p'; + loader_file_config->actions.mode = 'p'; break; case 'c': - loader_file_config->opt = 'c'; + loader_file_config->actions.mode = 'c'; break; } @@ -3518,7 +3530,7 @@ main(int argc, char *argv[]) set_dumper_config_defaults(global_dumper_config); /* Here we override any defaults for the GUI */ - global_loader_config->createindex = 1; + global_loader_config->createindex = LOADER_CREATE_ALWAYS; global_loader_config->geo_col = strdup(GEOMETRY_DEFAULT); global_loader_config->dump_format = 1; diff --git a/raster/loader/Makefile.in b/raster/loader/Makefile.in index a08bbc355..6b4babaeb 100644 --- a/raster/loader/Makefile.in +++ b/raster/loader/Makefile.in @@ -84,7 +84,7 @@ LDFLAGS = \ all: $(RASTER2PGSQL) -raster2pgsql.o: raster2pgsql.c +raster2pgsql.o: raster2pgsql.c ../../loader/loader_actions.h $(CC) $(CPPFLAGS) $(CFLAGS) -c $< $(RASTER2PGSQL): ../rt_core/librtcore.a raster2pgsql.o diff --git a/raster/loader/raster2pgsql.c b/raster/loader/raster2pgsql.c index 85508bb67..0a7474945 100644 --- a/raster/loader/raster2pgsql.c +++ b/raster/loader/raster2pgsql.c @@ -382,7 +382,14 @@ usage() { " -p Prepare mode, only creates the table.\n")); printf( _(" --if-not-exists Use IF NOT EXISTS for table creation in -c and -p\n" - " modes. With -I, also use IF NOT EXISTS for index creation.\n")); + " modes. With -I, also use IF NOT EXISTS for index creation.\n" + " Append mode requires an explicit creation action.\n")); + printf( + _(" --drop-table Drop the target table before other actions.\n" + " With no mode specified, the default create/load actions still apply.\n" + " --create-table Create the target table.\n" + " --load-data Load raster data into the target table.\n" + " --create-index Create a GIST spatial index on the raster column.\n")); printf(_( " -f Specify the name of the raster column\n" )); @@ -405,6 +412,12 @@ usage() { " -I Create a GIST spatial index on the raster column. The ANALYZE\n" " command will automatically be issued for the created index.\n" )); + printf( + _(" --add-constraints Set the standard set of constraints on the\n" + " raster column after the rasters are loaded.\n" + " --vacuum Run VACUUM on the table of the raster column.\n" + " --analyze Run ANALYZE on the table of the raster column.\n" + " --no-transaction Execute statements without a transaction.\n")); printf(_( " -M Run VACUUM ANALYZE on the table of the raster column. Most\n" " useful when appending raster to existing table with -a.\n" @@ -692,13 +705,11 @@ init_config(RTLOADERCFG *config) { config->pad_tile = 0; config->outdb = 0; config->opt = 'c'; - config->if_not_exists = 0; - config->drop_table = 0; - config->create_table = CREATE_TABLE_ALWAYS; - config->load_data = 1; - config->create_index = CREATE_INDEX_NONE; - config->maintenance = 0; - config->constraints = 0; + memset(&config->actions, 0, sizeof(config->actions)); + config->actions.mode = 'c'; + config->actions.create_table = LOADER_CREATE_ALWAYS; + config->actions.load_data = 1; + memset(&config->plan, 0, sizeof(config->plan)); config->max_extent = 1; config->regular_blocking = 0; config->tablespace = NULL; @@ -713,47 +724,75 @@ init_config(RTLOADERCFG *config) { config->max_tiles_per_copy = 50; } +static void rtdealloc_config(RTLOADERCFG *config); + +static void +exit_config_error(RTLOADERCFG *config) +{ + rtdealloc_config(config); + exit(1); +} + static int apply_action_presets(RTLOADERCFG *config) { - config->drop_table = 0; - config->create_table = CREATE_TABLE_NONE; - config->load_data = 0; + LoaderActionOptions *actions = &config->actions; - switch (config->opt) + memset(&config->plan, 0, sizeof(config->plan)); + + switch (actions->mode) { case 'd': - config->drop_table = 1; - config->create_table = CREATE_TABLE_ALWAYS; - config->load_data = 1; + config->plan.drop_table = 1; + config->plan.create_table = LOADER_CREATE_ALWAYS; + config->plan.load_data = 1; break; case 'a': - config->load_data = 1; + config->plan.load_data = 1; break; case 'c': - config->create_table = CREATE_TABLE_ALWAYS; - config->load_data = 1; + config->plan.create_table = LOADER_CREATE_ALWAYS; + config->plan.load_data = 1; break; case 'p': - config->create_table = CREATE_TABLE_ALWAYS; + config->plan.create_table = LOADER_CREATE_ALWAYS; break; default: - rterror(_("Unknown loader operation: -%c"), config->opt); + rterror(_("Unknown loader operation: -%c"), actions->mode); return 0; } - if (config->if_not_exists) + if (actions->drop_table) + config->plan.drop_table = 1; + if (actions->create_table_set) + config->plan.create_table = actions->create_table; + if (actions->load_data_set) + config->plan.load_data = actions->load_data; + if (actions->create_index_set) + config->plan.create_index = actions->create_index; + if (actions->add_constraints) + config->plan.add_constraints = 1; + config->plan.vacuum = actions->vacuum; + config->plan.analyze = actions->analyze; + + if (config->plan.drop_table && config->plan.load_data && config->plan.create_table == LOADER_CREATE_NONE) { - if (config->opt == 'd' || config->opt == 'a') + rterror(_("--drop-table with load data requires a table creation action")); + return 0; + } + + if (actions->if_not_exists) + { + if (config->plan.create_table == LOADER_CREATE_NONE && config->plan.create_index == LOADER_CREATE_NONE) { - rterror(_("--if-not-exists can only modify create and prepare modes")); + rterror(_("--if-not-exists requires a table or index creation action")); return 0; } - if (config->create_table == CREATE_TABLE_ALWAYS) - config->create_table = CREATE_TABLE_IF_NOT_EXISTS; - if (config->create_index == CREATE_INDEX_ALWAYS) - config->create_index = CREATE_INDEX_IF_NOT_EXISTS; + if (config->plan.create_table == LOADER_CREATE_ALWAYS) + config->plan.create_table = LOADER_CREATE_IF_NOT_EXISTS; + if (config->plan.create_index == LOADER_CREATE_ALWAYS) + config->plan.create_index = LOADER_CREATE_IF_NOT_EXISTS; } return 1; @@ -1202,10 +1241,8 @@ analyze_table( } static int -vacuum_table( - const char *schema, const char *table, - STRINGBUFFER *buffer -) { +vacuum_table(const char *schema, const char *table, int analyze, STRINGBUFFER *buffer) +{ char *sql = NULL; uint32_t len = 0; @@ -1221,10 +1258,7 @@ vacuum_table( rterror(_("vacuum_table: Could not allocate memory for VACUUM statement")); return 0; } - sprintf(sql, "VACUUM ANALYZE %s%s;", - (schema != NULL ? schema : ""), - table - ); + sprintf(sql, "VACUUM%s %s%s;", (analyze ? " ANALYZE" : ""), (schema != NULL ? schema : ""), table); append_sql_to_buffer(buffer, sql); @@ -2080,7 +2114,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* drop table */ - if (config->drop_table) + if (config->plan.drop_table) { if (!drop_table(config->schema, config->table, buffer)) { rterror(_("process_rasters: Could not add DROP TABLE statement to string buffer")); @@ -2098,7 +2132,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* create table */ - if (config->create_table != CREATE_TABLE_NONE) + if (config->plan.create_table != LOADER_CREATE_NONE) { if (!create_table(config->schema, config->table, @@ -2107,7 +2141,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { config->file_column_name, config->tablespace, config->idx_tablespace, - config->create_table == CREATE_TABLE_IF_NOT_EXISTS, + config->plan.create_table == LOADER_CREATE_IF_NOT_EXISTS, buffer)) { rterror(_("process_rasters: Could not add CREATE TABLE statement to string buffer")); @@ -2123,7 +2157,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { config->file_column_name, config->tablespace, config->idx_tablespace, - config->create_table == CREATE_TABLE_IF_NOT_EXISTS, + config->plan.create_table == LOADER_CREATE_IF_NOT_EXISTS, buffer)) { rterror(_("process_rasters: Could not add an overview's CREATE TABLE statement to string buffer")); @@ -2134,7 +2168,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* no need to load data in prepare mode */ - if (config->load_data) + if (config->plan.load_data) { RASTERINFO refinfo; init_rastinfo(&refinfo); @@ -2223,14 +2257,14 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* index */ - if (config->create_index != CREATE_INDEX_NONE) + if (config->plan.create_index != LOADER_CREATE_NONE) { /* create index */ if (!create_index(config->schema, config->table, config->raster_column, config->idx_tablespace, - config->create_index == CREATE_INDEX_IF_NOT_EXISTS, + config->plan.create_index == LOADER_CREATE_IF_NOT_EXISTS, buffer)) { rterror(_("process_rasters: Could not add CREATE INDEX statement to string buffer")); @@ -2238,7 +2272,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* analyze */ - if (config->load_data) + if (config->plan.load_data) { if (!analyze_table( config->schema, config->table, @@ -2256,7 +2290,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { config->overview_table[i], config->raster_column, config->idx_tablespace, - config->create_index == CREATE_INDEX_IF_NOT_EXISTS, + config->plan.create_index == LOADER_CREATE_IF_NOT_EXISTS, buffer)) { rterror(_("process_rasters: Could not add an overview's CREATE INDEX statement to string buffer")); @@ -2264,7 +2298,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* analyze */ - if (config->load_data) + if (config->plan.load_data) { if (!analyze_table( config->schema, config->overview_table[i], @@ -2279,7 +2313,8 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* add constraints */ - if (config->constraints) { + if (config->plan.add_constraints) + { if (!add_raster_constraints( config->schema, config->table, config->raster_column, config->regular_blocking, config->max_extent, @@ -2326,12 +2361,10 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* maintenance */ - if (config->load_data && config->maintenance) + if (config->plan.vacuum) { - if (!vacuum_table( - config->schema, config->table, - buffer - )) { + if (!vacuum_table(config->schema, config->table, config->plan.analyze, buffer)) + { rterror(_("process_rasters: Could not add VACUUM statement to string buffer")); return 0; } @@ -2339,15 +2372,35 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { if (config->overview_count) { for (i = 0; i < config->overview_count; i++) { if (!vacuum_table( - config->schema, config->overview_table[i], - buffer - )) { + config->schema, config->overview_table[i], config->plan.analyze, buffer)) + { rterror(_("process_rasters: Could not add an overview's VACUUM statement to string buffer")); return 0; } } } } + else if (config->plan.analyze) + { + if (!analyze_table(config->schema, config->table, buffer)) + { + rterror(_("process_rasters: Could not add ANALYZE statement to string buffer")); + return 0; + } + + if (config->overview_count) + { + for (i = 0; i < config->overview_count; i++) + { + if (!analyze_table(config->schema, config->overview_table[i], buffer)) + { + rterror(_( + "process_rasters: Could not add an overview's ANALYZE statement to string buffer")); + return 0; + } + } + } + } return 1; } @@ -2542,24 +2595,46 @@ main(int argc, char **argv) { } /* drop table and recreate */ else if (CSEQUAL(argv[argit], "-d")) { - config->opt = 'd'; + config->actions.mode = 'd'; + config->actions.mode_set = 1; } /* append to table */ else if (CSEQUAL(argv[argit], "-a")) { - config->opt = 'a'; + config->actions.mode = 'a'; + config->actions.mode_set = 1; } /* create new table */ else if (CSEQUAL(argv[argit], "-c")) { - config->opt = 'c'; + config->actions.mode = 'c'; + config->actions.mode_set = 1; } /* prepare only */ else if (CSEQUAL(argv[argit], "-p")) { - config->opt = 'p'; + config->actions.mode = 'p'; + config->actions.mode_set = 1; } /* make creation statements idempotent */ else if (CSEQUAL(argv[argit], "--if-not-exists")) { - config->if_not_exists = 1; + config->actions.if_not_exists = 1; + } + else if (CSEQUAL(argv[argit], "--drop-table")) + { + config->actions.drop_table = 1; + } + else if (CSEQUAL(argv[argit], "--create-table")) + { + if (!loader_action_set_create_mode( + &config->actions.create_table, &config->actions.create_table_set, LOADER_CREATE_ALWAYS)) + { + rterror(_("--create-table was specified with conflicting creation semantics")); + exit_config_error(config); + } + } + else if (CSEQUAL(argv[argit], "--load-data")) + { + config->actions.load_data = 1; + config->actions.load_data_set = 1; } /* raster column name */ else if (CSEQUAL(argv[argit], "-f") && argit < argc - 1) { @@ -2628,15 +2703,42 @@ main(int argc, char **argv) { } /* create index */ else if (CSEQUAL(argv[argit], "-I")) { - config->create_index = CREATE_INDEX_ALWAYS; + if (!loader_action_set_create_mode( + &config->actions.create_index, &config->actions.create_index_set, LOADER_CREATE_ALWAYS)) + { + rterror(_("--create-index was specified with conflicting creation semantics")); + exit_config_error(config); + } + } + else if (CSEQUAL(argv[argit], "--create-index")) + { + if (!loader_action_set_create_mode( + &config->actions.create_index, &config->actions.create_index_set, LOADER_CREATE_ALWAYS)) + { + rterror(_("--create-index was specified with conflicting creation semantics")); + exit_config_error(config); + } } /* maintenance */ else if (CSEQUAL(argv[argit], "-M")) { - config->maintenance = 1; + config->actions.vacuum = 1; + config->actions.analyze = 1; + } + else if (CSEQUAL(argv[argit], "--vacuum")) + { + config->actions.vacuum = 1; + } + else if (CSEQUAL(argv[argit], "--analyze")) + { + config->actions.analyze = 1; } /* set constraints */ else if (CSEQUAL(argv[argit], "-C")) { - config->constraints = 1; + config->actions.add_constraints = 1; + } + else if (CSEQUAL(argv[argit], "--add-constraints")) + { + config->actions.add_constraints = 1; } /* disable extent constraint */ else if (CSEQUAL(argv[argit], "-x")) { @@ -2691,6 +2793,16 @@ main(int argc, char **argv) { else if (CSEQUAL(argv[argit], "-e")) { config->transaction = 0; } + else if (CSEQUAL(argv[argit], "--no-transaction")) + { + config->transaction = 0; + } + else if (CSEQUAL(argv[argit], "--transaction")) + { + rterror(_("--transaction is the default; omit -e/--no-transaction instead")); + rtdealloc_config(config); + exit(1); + } /* COPY statements */ else if (CSEQUAL(argv[argit], "-Y")) { config->copy_statements = 1; diff --git a/raster/loader/raster2pgsql.h b/raster/loader/raster2pgsql.h index 96f674191..a18e76ea8 100644 --- a/raster/loader/raster2pgsql.h +++ b/raster/loader/raster2pgsql.h @@ -44,6 +44,7 @@ #include "../../postgis_config.h" #include "../raster_config.h" +#include "../../loader/loader_actions.h" #define CSEQUAL(a,b) (strcmp(a,b)==0) @@ -69,20 +70,6 @@ #define RCSID "$Id$" -typedef enum raster_loader_create_table_action -{ - CREATE_TABLE_NONE = 0, - CREATE_TABLE_ALWAYS, - CREATE_TABLE_IF_NOT_EXISTS -} CREATE_TABLE_ACTION; - -typedef enum raster_loader_create_index_action -{ - CREATE_INDEX_NONE = 0, - CREATE_INDEX_ALWAYS, - CREATE_INDEX_IF_NOT_EXISTS -} CREATE_INDEX_ACTION; - typedef struct raster_loader_config { /* raster filename */ uint32_t rt_file_count; @@ -132,20 +119,9 @@ typedef struct raster_loader_config { /* type of operation, (d|a|c|p) */ char opt; - /* make creation actions idempotent */ - int if_not_exists; - - /* actions derived from operation presets */ - int drop_table; - CREATE_TABLE_ACTION create_table; - int load_data; - CREATE_INDEX_ACTION create_index; - - /* maintenance statements, 1 = yes, 0 = no (default) */ - int maintenance; - - /* set constraints */ - int constraints; + /* raw action options and normalized execution plan */ + LoaderActionOptions actions; + LoaderPlan plan; /* enable max extent constraint, 1 = yes (default), 0 = no */ int max_extent; diff --git a/raster/test/regress/loader/LongMaintenance.opts b/raster/test/regress/loader/LongMaintenance.opts new file mode 100644 index 000000000..0320409c5 --- /dev/null +++ b/raster/test/regress/loader/LongMaintenance.opts @@ -0,0 +1,2 @@ +# Exercise raster-only long maintenance actions and constraint creation. +--add-constraints --vacuum --analyze diff --git a/raster/test/regress/loader/LongMaintenance.select.expected b/raster/test/regress/loader/LongMaintenance.select.expected new file mode 100644 index 000000000..484721c35 --- /dev/null +++ b/raster/test/regress/loader/LongMaintenance.select.expected @@ -0,0 +1,4 @@ +0|1.0000000000|-1.0000000000|90|50|t|f|3|{8BUI,8BUI,8BUI}|{NULL,NULL,NULL}|{f,f,f}|POLYGON((0 -50,0 0,90 0,90 -50,0 -50)) +POLYGON((0 0,1 0,1 -1,0 -1,0 0))|255 +POLYGON((89 -49,90 -49,90 -50,89 -50,89 -49))|0 +POLYGON((44 -24,45 -24,45 -25,44 -25,44 -24))|0 diff --git a/raster/test/regress/loader/LongMaintenance.select.sql b/raster/test/regress/loader/LongMaintenance.select.sql new file mode 100644 index 000000000..18027ebe8 --- /dev/null +++ b/raster/test/regress/loader/LongMaintenance.select.sql @@ -0,0 +1,8 @@ +-- --add-constraints should register the loaded raster in raster_columns +-- with the same metadata that the existing short -C test expects. +SELECT srid, scale_x::numeric(16, 10), scale_y::numeric(16, 10), blocksize_x, blocksize_y, same_alignment, regular_blocking, num_bands, pixel_types, nodata_values::numeric(16,10)[], out_db, ST_AsEWKT(extent) FROM raster_columns WHERE r_table_name = 'loadedrast' AND r_raster_column = 'rast'; + +-- The raster data should survive the long maintenance path unchanged. +SELECT ST_AsEWKT(geom), val FROM (SELECT (ST_PixelAsPolygons(rast, 1)).* FROM loadedrast WHERE rid = 1) foo WHERE x = 1 AND y = 1; +SELECT ST_AsEWKT(geom), val FROM (SELECT (ST_PixelAsPolygons(rast, 2)).* FROM loadedrast WHERE rid = 1) foo WHERE x = 90 AND y = 50; +SELECT ST_AsEWKT(geom), val FROM (SELECT (ST_PixelAsPolygons(rast, 3)).* FROM loadedrast WHERE rid = 1) foo WHERE x = 45 AND y = 25; diff --git a/raster/test/regress/loader/LongMaintenance.tif.ref b/raster/test/regress/loader/LongMaintenance.tif.ref new file mode 100644 index 000000000..1e1cc0fc8 --- /dev/null +++ b/raster/test/regress/loader/LongMaintenance.tif.ref @@ -0,0 +1 @@ +testraster.tif diff --git a/raster/test/regress/loader/LongOptions.opts b/raster/test/regress/loader/LongOptions.opts new file mode 100644 index 000000000..628a4b62b --- /dev/null +++ b/raster/test/regress/loader/LongOptions.opts @@ -0,0 +1 @@ +--drop-table --create-table --load-data --create-index --if-not-exists --no-transaction diff --git a/raster/test/regress/loader/LongOptions.select.expected b/raster/test/regress/loader/LongOptions.select.expected new file mode 100644 index 000000000..47e5ca813 --- /dev/null +++ b/raster/test/regress/loader/LongOptions.select.expected @@ -0,0 +1,4 @@ +1 +90|50|3 +255 +1 diff --git a/raster/test/regress/loader/LongOptions.select.sql b/raster/test/regress/loader/LongOptions.select.sql new file mode 100644 index 000000000..71dc9a290 --- /dev/null +++ b/raster/test/regress/loader/LongOptions.select.sql @@ -0,0 +1,12 @@ +-- The long action options should still perform a normal raster load. +SELECT count(*) FROM loadedrast; +SELECT ST_Width(rast), ST_Height(rast), ST_NumBands(rast) FROM loadedrast WHERE rid = 1; +SELECT ST_Value(rast, 1, 1, 1) FROM loadedrast WHERE rid = 1; + +-- --create-index combined with --if-not-exists emits a stable named index. +-- PostgreSQL stores the resulting definition without IF NOT EXISTS. +SELECT COUNT(*) +FROM pg_indexes +WHERE schemaname = 'public' + AND tablename = 'loadedrast' + AND indexdef LIKE 'CREATE INDEX loadedrast_rast_gist ON public.loadedrast USING gist (st_convexhull(rast))'; diff --git a/raster/test/regress/loader/LongOptions.tif.ref b/raster/test/regress/loader/LongOptions.tif.ref new file mode 100644 index 000000000..1e1cc0fc8 --- /dev/null +++ b/raster/test/regress/loader/LongOptions.tif.ref @@ -0,0 +1 @@ +testraster.tif diff --git a/raster/test/regress/tests.mk.in b/raster/test/regress/tests.mk.in index 8fa0cf6d2..7bc6972e6 100644 --- a/raster/test/regress/tests.mk.in +++ b/raster/test/regress/tests.mk.in @@ -132,6 +132,8 @@ RASTER_TEST_LOADER = \ $(top_srcdir)/raster/test/regress/loader/Projected \ $(top_srcdir)/raster/test/regress/loader/OverviewNoPadding \ $(top_srcdir)/raster/test/regress/loader/IfNotExists \ + $(top_srcdir)/raster/test/regress/loader/LongOptions \ + $(top_srcdir)/raster/test/regress/loader/LongMaintenance \ $(top_srcdir)/raster/test/regress/loader/BasicCopy \ $(top_srcdir)/raster/test/regress/loader/BasicFilename \ $(top_srcdir)/raster/test/regress/loader/BasicOutDB \ diff --git a/regress/loader/LongOptions.dbf b/regress/loader/LongOptions.dbf new file mode 100644 index 000000000..13b4aeea0 Binary files /dev/null and b/regress/loader/LongOptions.dbf differ diff --git a/regress/loader/LongOptions.opts b/regress/loader/LongOptions.opts new file mode 100644 index 000000000..098600e4b --- /dev/null +++ b/regress/loader/LongOptions.opts @@ -0,0 +1,3 @@ +# Exercise the public long action names as one loader invocation: +# drop, create-if-missing, load, idempotent index, no transaction, and analyze. +--drop-table --create-table --load-data --create-index --if-not-exists --no-transaction --no-analyze --analyze diff --git a/regress/loader/LongOptions.select.expected b/regress/loader/LongOptions.select.expected new file mode 100644 index 000000000..f00580c40 --- /dev/null +++ b/regress/loader/LongOptions.select.expected @@ -0,0 +1,2 @@ +3 +1 diff --git a/regress/loader/LongOptions.select.sql b/regress/loader/LongOptions.select.sql new file mode 100644 index 000000000..e49ab059c --- /dev/null +++ b/regress/loader/LongOptions.select.sql @@ -0,0 +1,10 @@ +-- The long action options should still perform a normal load. +SELECT count(*) FROM loadedshp; + +-- --create-index combined with --if-not-exists emits a stable named index. +-- PostgreSQL stores the resulting definition without IF NOT EXISTS. +SELECT COUNT(*) +FROM pg_indexes +WHERE schemaname = 'public' + AND tablename = 'loadedshp' + AND indexdef LIKE 'CREATE INDEX loadedshp_the_geom_gist ON public.loadedshp USING gist (the_geom)'; diff --git a/regress/loader/LongOptions.shp b/regress/loader/LongOptions.shp new file mode 100644 index 000000000..51d38e75d Binary files /dev/null and b/regress/loader/LongOptions.shp differ diff --git a/regress/loader/LongOptions.shx b/regress/loader/LongOptions.shx new file mode 100644 index 000000000..7db02aff8 Binary files /dev/null and b/regress/loader/LongOptions.shx differ diff --git a/regress/loader/TestANALYZE.sql.expected b/regress/loader/LongOptions.sql.expected similarity index 61% copy from regress/loader/TestANALYZE.sql.expected copy to regress/loader/LongOptions.sql.expected index fe56dd4b1..59151e1a3 100644 --- a/regress/loader/TestANALYZE.sql.expected +++ b/regress/loader/LongOptions.sql.expected @@ -1,12 +1,10 @@ SET CLIENT_ENCODING TO UTF8; SET STANDARD_CONFORMING_STRINGS TO ON; -BEGIN; -CREATE TABLE "loadedshp" (gid serial); -ALTER TABLE "loadedshp" ADD PRIMARY KEY (gid); -SELECT AddGeometryColumn('','loadedshp','the_geom','0','POINT',2); +DROP TABLE IF EXISTS "loadedshp"; +CREATE TABLE IF NOT EXISTS "loadedshp" (gid serial PRIMARY KEY, +"the_geom" geometry(POINT,0)); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000000000000000000000F03F'); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000002240000000000000F0BF'); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000002240000000000000F0BF'); -CREATE INDEX ON "loadedshp" USING GIST ("the_geom"); -COMMIT; +CREATE INDEX IF NOT EXISTS "loadedshp_the_geom_gist" ON "loadedshp" USING GIST ("the_geom"); ANALYZE "loadedshp"; diff --git a/regress/loader/TestANALYZE.opts b/regress/loader/TestANALYZE.opts index c865f6dca..2f7d46ac5 100644 --- a/regress/loader/TestANALYZE.opts +++ b/regress/loader/TestANALYZE.opts @@ -1,2 +1,2 @@ -# Test with ANALYZE and index creation --I -g the_geom {regdir}/loader/TestSkipANALYZE loadedshp +# Test long --analyze with short index creation. +-I --analyze -g the_geom {regdir}/loader/TestSkipANALYZE loadedshp diff --git a/regress/loader/TestANALYZE.sql.expected b/regress/loader/TestANALYZE.sql.expected index fe56dd4b1..10769aea0 100644 --- a/regress/loader/TestANALYZE.sql.expected +++ b/regress/loader/TestANALYZE.sql.expected @@ -1,9 +1,9 @@ SET CLIENT_ENCODING TO UTF8; SET STANDARD_CONFORMING_STRINGS TO ON; BEGIN; -CREATE TABLE "loadedshp" (gid serial); +CREATE TABLE "loadedshp" (gid serial, +"the_geom" geometry(POINT,0)); ALTER TABLE "loadedshp" ADD PRIMARY KEY (gid); -SELECT AddGeometryColumn('','loadedshp','the_geom','0','POINT',2); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000000000000000000000F03F'); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000002240000000000000F0BF'); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000002240000000000000F0BF'); diff --git a/regress/loader/TestSkipANALYZE.opts b/regress/loader/TestSkipANALYZE.opts index 4ffc225f6..cbfc8e6cd 100644 --- a/regress/loader/TestSkipANALYZE.opts +++ b/regress/loader/TestSkipANALYZE.opts @@ -1,2 +1,2 @@ -# Test -Z skips ANALYZE --Z -g the_geom {regdir}/loader/TestSkipANALYZE loadedshp +# Test long --no-analyze skips ANALYZE. +--no-analyze -g the_geom {regdir}/loader/TestSkipANALYZE loadedshp diff --git a/regress/loader/tests.mk b/regress/loader/tests.mk index ac4f8ad23..40941b7e6 100644 --- a/regress/loader/tests.mk +++ b/regress/loader/tests.mk @@ -38,7 +38,7 @@ TESTS += \ $(top_srcdir)/regress/loader/Latin1 \ $(top_srcdir)/regress/loader/Latin1-implicit \ $(top_srcdir)/regress/loader/mfile \ + $(top_srcdir)/regress/loader/LongOptions \ $(top_srcdir)/regress/loader/TestSkipANALYZE \ $(top_srcdir)/regress/loader/TestANALYZE \ $(top_srcdir)/regress/loader/CharNoWidth \ - commit 37db33a47b8d380d6b58f8fcdf4824bfa0f2c847 Author: Darafei Praliaskouski Date: Sun Jun 21 00:24:08 2026 +0400 loader: add shp2pgsql --drop-table option Add --drop-table to request a DROP TABLE IF EXISTS statement before create/prepare output without changing mutually exclusive load modes. Keep -d as the drop/create/load preset and reject --drop-table -a because append mode has no create step to precede. Closes #2935 Closes https://github.com/postgis/postgis/pull/1048 diff --git a/NEWS b/NEWS index 121538c26..495b17930 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #1124, shp2pgsql can create UNLOGGED tables for transient staging loads (Darafei Praliaskouski) + - #2935, shp2pgsql --drop-table can emit DROP TABLE before prepare output + (Darafei Praliaskouski) - #4208, Add single-geometry variants of ST_MaxDistance and ST_LongestLine (Darafei Praliaskouski) - [topology] FindVertexSegmentPairsBelowDistance function (Sandro Santilli) diff --git a/doc/man/shp2pgsql.1 b/doc/man/shp2pgsql.1 index 37ccabcba..8ccc5d1bb 100644 --- a/doc/man/shp2pgsql.1 +++ b/doc/man/shp2pgsql.1 @@ -48,6 +48,10 @@ Only produces the table creation SQL code, without adding any actual data. This can be used if you need to completely separate the table creation and data loading steps. .TP +\fB\-\-drop\-table\fR +Emits a DROP TABLE IF EXISTS statement before table creation. This can be +combined with \-c or \-p, but not with \-a. +.TP \fB\-D\fR Use the PostgreSQL "dump" format for the output data. This can be combined with \-a, \-c and \-d. It is much faster to load than the default "insert" diff --git a/loader/README.shp2pgsql b/loader/README.shp2pgsql index 08ecde1f7..d5afc8e19 100644 --- a/loader/README.shp2pgsql +++ b/loader/README.shp2pgsql @@ -48,6 +48,10 @@ OPTIONS actual data. This can be used if you need to completely sepa- rate the table creation and data loading steps. + --drop-table + Emits a DROP TABLE IF EXISTS statement before table creation. + This can be combined with -c or -p, but not with -a. + -D Use the PostgreSQL "dump" format for the output data. This can be combined with -a, -c and -d. It is much faster to load than the default "insert" SQL format. Use this for very large data diff --git a/loader/cunit/cu_shp2pgsql.c b/loader/cunit/cu_shp2pgsql.c index ee6159cb0..0eefab957 100644 --- a/loader/cunit/cu_shp2pgsql.c +++ b/loader/cunit/cu_shp2pgsql.c @@ -12,10 +12,12 @@ #include "cu_shp2pgsql.h" #include "cu_tester.h" #include "../shp2pgsql-core.h" +#include /* Test functions */ void test_ShpLoaderCreate(void); void test_ShpLoaderDestroy(void); +void test_ShpLoaderGetSQLHeader_drop_prepare(void); SHPLOADERCONFIG *loader_config; SHPLOADERSTATE *loader_state; @@ -33,10 +35,10 @@ CU_pSuite register_shp2pgsql_suite(void) return NULL; } - if ( - (NULL == CU_add_test(pSuite, "test_ShpLoaderCreate()", test_ShpLoaderCreate)) || - (NULL == CU_add_test(pSuite, "test_ShpLoaderDestroy()", test_ShpLoaderDestroy)) - ) + if ((NULL == CU_add_test(pSuite, "test_ShpLoaderCreate()", test_ShpLoaderCreate)) || + (NULL == CU_add_test(pSuite, "test_ShpLoaderDestroy()", test_ShpLoaderDestroy)) || + (NULL == + CU_add_test(pSuite, "test_ShpLoaderGetSQLHeader_drop_prepare()", test_ShpLoaderGetSQLHeader_drop_prepare))) { CU_cleanup_registry(); return NULL; @@ -75,3 +77,34 @@ void test_ShpLoaderDestroy(void) { ShpLoaderDestroy(loader_state); } + +void +test_ShpLoaderGetSQLHeader_drop_prepare(void) +{ + char *header = NULL; + const char *drop; + const char *create; + + loader_config = (SHPLOADERCONFIG *)calloc(1, sizeof(SHPLOADERCONFIG)); + set_loader_config_defaults(loader_config); + loader_config->opt = 'p'; + loader_config->drop_table = 1; + /* This header-only test does not open a shapefile, so avoid geometry metadata. */ + loader_config->readshape = 0; + loader_config->table = "loadedshp"; + loader_config->geo_col = "the_geom"; + + loader_state = ShpLoaderCreate(loader_config); + CU_ASSERT_EQUAL(ShpLoaderGetSQLHeader(loader_state, &header), SHPLOADEROK); + CU_ASSERT_PTR_NOT_NULL(header); + + drop = strstr(header, "DROP TABLE IF EXISTS \"loadedshp\";"); + create = strstr(header, "CREATE TABLE \"loadedshp\""); + CU_ASSERT_PTR_NOT_NULL(drop); + CU_ASSERT_PTR_NOT_NULL(create); + CU_ASSERT_PTR_NULL(strstr(header, "DropGeometryColumn")); + CU_ASSERT(drop < create); + + free(header); + ShpLoaderDestroy(loader_state); +} diff --git a/loader/shp2pgsql-cli.c b/loader/shp2pgsql-cli.c index 784ba3a7e..28d1a1c25 100644 --- a/loader/shp2pgsql-cli.c +++ b/loader/shp2pgsql-cli.c @@ -63,6 +63,7 @@ usage() " attribute column. (default: \"UTF-8\")\n" )); printf(_( " -N NULL geometries handling policy (insert*,skip,abort).\n" )); printf(_( " -n Only import DBF file.\n" )); + printf(_(" --drop-table Emit DROP TABLE IF EXISTS before create or prepare output.\n")); printf(_( " -T Specify the tablespace for the new table.\n" " Note that indexes will still use the default tablespace unless the\n" " -X flag is also used.\n")); @@ -106,8 +107,19 @@ main (int argc, char **argv) set_loader_config_defaults(config); /* Keep the flag list alphabetic so it's easy to see what's left. */ - while ((c = pgis_getopt(argc, argv, "-?acdeg:ikm:nps:t:uwDGIN:ST:W:X:Z")) != EOF) + while (pgis_optind < argc) { + if (strcmp(argv[pgis_optind], "--drop-table") == 0) + { + config->drop_table = 1; + pgis_optind++; + continue; + } + + c = pgis_getopt(argc, argv, "-?acdeg:ikm:nps:t:uwDGIN:ST:W:X:Z"); + if (c == EOF) + break; + // can not do this inside the switch case if ('-' == c) break; @@ -267,6 +279,12 @@ main (int argc, char **argv) exit(1); } + if (config->drop_table && config->opt == 'a') + { + fprintf(stderr, "Invalid argument combination - cannot use both --drop-table and -a\n"); + exit(1); + } + /* Determine the shapefile name from the next argument, if no shape file, exit. */ if (pgis_optind < argc) { @@ -386,7 +404,7 @@ main (int argc, char **argv) free(header); /* If we are not in "prepare" mode, go ahead and write out the data. */ - if ( state->config->opt != 'p' ) + if (state->config->load_data) { /* If in COPY mode, output the COPY statement */ diff --git a/loader/shp2pgsql-core.c b/loader/shp2pgsql-core.c index ac1adc528..fa8bffe75 100644 --- a/loader/shp2pgsql-core.c +++ b/loader/shp2pgsql-core.c @@ -771,6 +771,10 @@ set_loader_config_defaults(SHPLOADERCONFIG *config) config->forceint4 = 0; config->createindex = 0; config->unlogged = 0; + config->drop_table = 0; + config->drop_geometry_column = 0; + config->create_table = 1; + config->load_data = 1; config->analyze = 1; config->readshape = 1; config->force_output = FORCE_OUTPUT_DISABLE; @@ -785,12 +789,25 @@ set_loader_config_defaults(SHPLOADERCONFIG *config) config->column_map_filename = NULL; } +static void +set_loader_config_actions(SHPLOADERCONFIG *config) +{ + const int explicit_drop_table = config->drop_table; + + config->drop_table = explicit_drop_table || config->opt == 'd'; + config->drop_geometry_column = config->opt == 'd'; + config->create_table = config->opt != 'a'; + config->load_data = config->opt != 'p'; +} + /* Create a new shapefile state object */ SHPLOADERSTATE * ShpLoaderCreate(SHPLOADERCONFIG *config) { SHPLOADERSTATE *state; + set_loader_config_actions(config); + /* Create a new state object and assign the config to it */ state = malloc(sizeof(SHPLOADERSTATE)); state->config = config; @@ -1300,7 +1317,7 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) stringbuffer_aprintf(sb, "SET STANDARD_CONFORMING_STRINGS TO ON;\n"); /* Drop table if requested */ - if (state->config->opt == 'd') + if (state->config->drop_table) { /** * TODO: if the table has more then one geometry column @@ -1315,7 +1332,8 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) */ if (state->config->schema) { - if (state->config->readshape == 1 && (! state->config->geography) ) + if (state->config->drop_geometry_column && state->config->readshape == 1 && + (!state->config->geography)) { stringbuffer_aprintf(sb, "SELECT DropGeometryColumn('%s','%s','%s');\n", state->config->schema, state->config->table, state->geo_col); @@ -1326,7 +1344,8 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) } else { - if (state->config->readshape == 1 && (! state->config->geography) ) + if (state->config->drop_geometry_column && state->config->readshape == 1 && + (!state->config->geography)) { stringbuffer_aprintf(sb, "SELECT DropGeometryColumn('','%s','%s');\n", state->config->table, state->geo_col); @@ -1342,8 +1361,8 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) stringbuffer_aprintf(sb, "BEGIN;\n"); } - /* If not in 'append' mode create the spatial table */ - if (state->config->opt != 'a') + /* Create the spatial table when requested by the selected actions. */ + if (state->config->create_table) { /* * Create a table for inserting the shapes into with appropriate diff --git a/loader/shp2pgsql-core.h b/loader/shp2pgsql-core.h index fd078e21b..ed8e5ae71 100644 --- a/loader/shp2pgsql-core.h +++ b/loader/shp2pgsql-core.h @@ -81,7 +81,7 @@ */ typedef struct shp_loader_config { - /* load mode: c = create, d = delete, a = append, p = prepare */ + /* load mode preset: c = create, d = drop/create, a = append, p = prepare */ char opt; /* table to load into */ @@ -117,7 +117,19 @@ typedef struct shp_loader_config /* 0 = logged table, 1 = create as UNLOGGED table */ int unlogged; - /* 0 = don't analyze tables , 1 = analyze tables */ + /* action: emit DROP TABLE before create/prepare */ + int drop_table; + + /* action: remove geometry_columns entry before dropping the table */ + int drop_geometry_column; + + /* action: create the target table */ + int create_table; + + /* action: load rows from the input file */ + int load_data; + + /* 0 = don't analyze tables , 1 = analyze tables */ int analyze; /* 0 = load DBF file only, 1 = load everything */ diff --git a/loader/shp2pgsql-gui.c b/loader/shp2pgsql-gui.c index 7f8dbbc87..853a8c3af 100644 --- a/loader/shp2pgsql-gui.c +++ b/loader/shp2pgsql-gui.c @@ -1609,8 +1609,8 @@ pgui_action_import(GtkWidget *widget, gpointer data) if (!ret) goto import_cleanup; - /* If we are in prepare mode, we need to skip the actual load. */ - if (state->config->opt != 'p') + /* Load rows when requested by the selected actions. */ + if (state->config->load_data) { int numrecords = ShpLoaderGetRecordCount(state); int records_per_tick = (numrecords / 200) - 1; @@ -1714,7 +1714,7 @@ pgui_action_import(GtkWidget *widget, gpointer data) goto import_cleanup; } } - } /* if (state->config->opt != 'p') */ + } /* if (state->config->load_data) */ /* Only continue if we didn't abort part way through */ if (is_running) @@ -1756,7 +1756,7 @@ import_cleanup: pg_connection = NULL; /* If we didn't finish inserting all of the items (and we expected to), an error occurred */ - if ((state->config->opt != 'p' && i != ShpLoaderGetRecordCount(state)) || !ret) + if ((state->config->load_data && i != ShpLoaderGetRecordCount(state)) || !ret) pgui_logf(_("Shapefile import failed.")); else pgui_logf(_("Shapefile import completed.")); ----------------------------------------------------------------------- Summary of changes: NEWS | 6 +- doc/man/raster2pgsql.1 | 28 ++- doc/man/shp2pgsql.1 | 28 ++- doc/using_raster_dataman.xml | 24 +- loader/Makefile.in | 4 +- loader/README.shp2pgsql | 26 ++ loader/cunit/Makefile.in | 2 + loader/cunit/cu_shp2pgsql.c | 108 +++++++- loader/loader_actions.h | 67 +++++ loader/shp2pgsql-cli.c | 125 +++++++++- loader/shp2pgsql-core.c | 271 ++++++++++++--------- loader/shp2pgsql-core.h | 13 +- loader/shp2pgsql-gui.c | 44 ++-- raster/loader/Makefile.in | 2 +- raster/loader/raster2pgsql.c | 236 +++++++++++++----- raster/loader/raster2pgsql.h | 32 +-- raster/test/regress/loader/LongMaintenance.opts | 2 + ...ct.expected => LongMaintenance.select.expected} | 0 ...ename.select.sql => LongMaintenance.select.sql} | 5 +- .../{Basic.tif.ref => LongMaintenance.tif.ref} | 0 raster/test/regress/loader/LongOptions.opts | 1 + ...select.expected => LongOptions.select.expected} | 0 ...NotExists.select.sql => LongOptions.select.sql} | 4 + .../loader/{Basic.tif.ref => LongOptions.tif.ref} | 0 raster/test/regress/tests.mk.in | 2 + regress/loader/{ArcM.dbf => LongOptions.dbf} | Bin regress/loader/LongOptions.opts | 3 + ...select.expected => LongOptions.select.expected} | 2 +- regress/loader/LongOptions.select.sql | 10 + .../loader/{NoTransPoint.shp => LongOptions.shp} | Bin .../loader/{NoTransPoint.shx => LongOptions.shx} | Bin ...ALYZE.sql.expected => LongOptions.sql.expected} | 10 +- regress/loader/TestANALYZE.opts | 4 +- regress/loader/TestANALYZE.sql.expected | 4 +- regress/loader/TestSkipANALYZE.opts | 4 +- regress/loader/tests.mk | 2 +- 36 files changed, 815 insertions(+), 254 deletions(-) create mode 100644 loader/loader_actions.h create mode 100644 raster/test/regress/loader/LongMaintenance.opts copy raster/test/regress/loader/{BasicCopy.select.expected => LongMaintenance.select.expected} (100%) copy raster/test/regress/loader/{BasicFilename.select.sql => LongMaintenance.select.sql} (76%) copy raster/test/regress/loader/{Basic.tif.ref => LongMaintenance.tif.ref} (100%) create mode 100644 raster/test/regress/loader/LongOptions.opts copy raster/test/regress/loader/{IfNotExists.select.expected => LongOptions.select.expected} (100%) copy raster/test/regress/loader/{IfNotExists.select.sql => LongOptions.select.sql} (64%) copy raster/test/regress/loader/{Basic.tif.ref => LongOptions.tif.ref} (100%) copy regress/loader/{ArcM.dbf => LongOptions.dbf} (100%) create mode 100644 regress/loader/LongOptions.opts copy regress/loader/{TestANALYZE.select.expected => LongOptions.select.expected} (50%) create mode 100644 regress/loader/LongOptions.select.sql copy regress/loader/{NoTransPoint.shp => LongOptions.shp} (100%) copy regress/loader/{NoTransPoint.shx => LongOptions.shx} (100%) copy regress/loader/{TestANALYZE.sql.expected => LongOptions.sql.expected} (61%) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 06:06:05 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 13:06:05 -0000 Subject: [PostGIS] #2935: shp2pgsql: There should be a way to add a delete table statement even when just preparing the DDL In-Reply-To: <052.ab34beef46750988c2fd266980d622a1@osgeo.org> References: <052.ab34beef46750988c2fd266980d622a1@osgeo.org> Message-ID: <067.69dffbbea14170275d69572460a1f5b0@osgeo.org> #2935: shp2pgsql: There should be a way to add a delete table statement even when just preparing the DDL ----------------------------------+----------------------------- Reporter: jimktrains | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: utils/loader-dumper | Version: 2.1.x Resolution: fixed | Keywords: shp2pgsql ----------------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"37db33a47b8d380d6b58f8fcdf4824bfa0f2c847/git" 37db33a4/git]: {{{#!CommitTicketReference repository="git" revision="37db33a47b8d380d6b58f8fcdf4824bfa0f2c847" loader: add shp2pgsql --drop-table option Add --drop-table to request a DROP TABLE IF EXISTS statement before create/prepare output without changing mutually exclusive load modes. Keep -d as the drop/create/load preset and reject --drop-table -a because append mode has no create step to precede. Closes #2935 Closes https://github.com/postgis/postgis/pull/1048 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 06:34:29 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 06:34:29 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-640-gc94f62361 Message-ID: <20260621133429.543131ADB13@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via c94f62361826e4dc14b660b31e6614727db8deb3 (commit) via f82a1015b8772b570e05ad552eed4029ff718dd5 (commit) from 0482d073a2d174a544428664fa7cebcd36b7d96a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c94f62361826e4dc14b660b31e6614727db8deb3 Author: Darafei Praliaskouski Date: Sun Jun 21 17:33:10 2026 +0400 Use escape strings for version regexes Make the PostGIS script-version comparison helper and its regression checks independent of standard_conforming_strings. This avoids warnings during install when standard_conforming_strings is off, which the regression harness treats as load failure.\n\nCloses #2808 diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 8abfd90a2..027170b68 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -3161,7 +3161,7 @@ CREATE OR REPLACE FUNCTION _postgis_scripts_version_cmp_key(ver text) BEGIN ver_match := pg_catalog.regexp_match( pg_catalog.lower(ver), - '^([0-9]+)\.([0-9]+)\.([0-9]+)(dev|alpha|beta|rc)?([0-9]*)([^0-9a-z].*)?$' + E'^([0-9]+)\\.([0-9]+)\\.([0-9]+)(dev|alpha|beta|rc)?([0-9]*)([^0-9a-z].*)?$' ); IF ver_match IS NULL THEN RETURN NULL; diff --git a/regress/core/postgis_full_version.sql b/regress/core/postgis_full_version.sql index 88e9a3c62..5cbc5d9ed 100644 --- a/regress/core/postgis_full_version.sql +++ b/regress/core/postgis_full_version.sql @@ -25,7 +25,7 @@ LANGUAGE 'sql' IMMUTABLE; -- Older component script versions still mean the installed procs need upgrade. SELECT 'topology_old_scripts', postgis_full_version() ~ - 'TOPOLOGY \(topology procs from "1\.0\.0" need upgrade\)'; + E'TOPOLOGY \\(topology procs from "1\\.0\\.0" need upgrade\\)'; CREATE OR REPLACE FUNCTION topology.postgis_topology_scripts_installed() RETURNS text @@ -52,17 +52,17 @@ LANGUAGE 'sql' IMMUTABLE; -- includes final releases newer than release candidates and later RCs. SELECT 'topology_newer_scripts', postgis_full_version() ~ - 'TOPOLOGY \(topology procs from "3\.7\.0" are newer than core procs from "3\.7\.0rc1"\)'; + E'TOPOLOGY \\(topology procs from "3\\.7\\.0" are newer than core procs from "3\\.7\\.0rc1"\\)'; SELECT 'raster_newer_scripts', postgis_full_version() ~ - '\(raster procs from "3\.7\.0rc2" are newer than core procs from "3\.7\.0rc1"\)'; + E'\\(raster procs from "3\\.7\\.0rc2" are newer than core procs from "3\\.7\\.0rc1"\\)'; -- A prerelease older than the core prerelease is still reported as needing -- upgrade, even when its numeric major/minor/micro components match. SELECT 'sfcgal_older_prerelease', postgis_full_version() ~ - '\(sfcgal procs from "3\.7\.0beta1" need upgrade\)'; + E'\\(sfcgal procs from "3\\.7\\.0beta1" need upgrade\\)'; CREATE OR REPLACE FUNCTION postgis_sfcgal_scripts_installed() RETURNS text @@ -71,6 +71,6 @@ LANGUAGE 'sql' IMMUTABLE; SELECT 'sfcgal_newer_scripts', postgis_full_version() ~ - '\(sfcgal procs from "3\.7\.0" are newer than core procs from "3\.7\.0rc1"\)'; + E'\\(sfcgal procs from "3\\.7\\.0" are newer than core procs from "3\\.7\\.0rc1"\\)'; ROLLBACK; commit f82a1015b8772b570e05ad552eed4029ff718dd5 Author: Darafei Praliaskouski Date: Sun Jun 21 17:26:13 2026 +0400 Fix red main CI failures diff --git a/raster/rt_core/rt_warp.c b/raster/rt_core/rt_warp.c index 2cdda3c1e..8058529ba 100644 --- a/raster/rt_core/rt_warp.c +++ b/raster/rt_core/rt_warp.c @@ -163,6 +163,12 @@ rt_raster rt_raster_gdal_warp( ) { CPLErr cplerr; char *dst_options[] = {"SUBCLASS=VRTWarpedDataset", NULL}; + const char *init_dest_nodata_option = "INIT_DEST=NO_DATA"; +#if POSTGIS_GDAL_VERSION >= 30302 + const char *unified_src_nodata_option = "UNIFIED_SRC_NODATA=PARTIAL"; +#else + const char *unified_src_nodata_option = "UNIFIED_SRC_NODATA=NO"; +#endif _rti_warp_arg arg = NULL; int nodata_count = 0; @@ -197,6 +203,7 @@ rt_raster rt_raster_gdal_warp( int numBands = 0; int nodata_pos = 0; int data_pos = 0; + int use_init_dest_nodata = 0; int subspatial = 0; @@ -865,17 +872,21 @@ rt_raster rt_raster_gdal_warp( arg->wopts->hDstDS = arg->dst.ds; arg->wopts->pfnTransformer = arg->transform.func; arg->wopts->pTransformerArg = arg->transform.arg.transform; - arg->wopts->papszWarpOptions = (char **) CPLMalloc(sizeof(char *) * 3); - arg->wopts->papszWarpOptions[0] = (char *) CPLMalloc(sizeof(char) * (strlen("INIT_DEST=NO_DATA") + 1)); - strcpy(arg->wopts->papszWarpOptions[0], "INIT_DEST=NO_DATA"); -#if POSTGIS_GDAL_VERSION >= 30302 - arg->wopts->papszWarpOptions[1] = (char *) CPLMalloc(sizeof(char) * (strlen("UNIFIED_SRC_NODATA=PARTIAL") + 1)); - strcpy(arg->wopts->papszWarpOptions[1], "UNIFIED_SRC_NODATA=PARTIAL"); -#else - arg->wopts->papszWarpOptions[1] = (char *) CPLMalloc(sizeof(char) * (strlen("UNIFIED_SRC_NODATA=NO") + 1)); - strcpy(arg->wopts->papszWarpOptions[1], "UNIFIED_SRC_NODATA=NO"); -#endif - arg->wopts->papszWarpOptions[2] = NULL; + /* + * GDAL 3.11 warns, and later treats as an error, when INIT_DEST=NO_DATA + * is requested without destination nodata values for every band. + */ + use_init_dest_nodata = numBands > 0 && nodata_count == numBands; + arg->wopts->papszWarpOptions = + (char **) CPLMalloc(sizeof(char *) * (use_init_dest_nodata ? 3 : 2)); + i = 0; + if (use_init_dest_nodata) { + arg->wopts->papszWarpOptions[i] = (char *) CPLMalloc(sizeof(char) * (strlen(init_dest_nodata_option) + 1)); + strcpy(arg->wopts->papszWarpOptions[i++], init_dest_nodata_option); + } + arg->wopts->papszWarpOptions[i] = (char *) CPLMalloc(sizeof(char) * (strlen(unified_src_nodata_option) + 1)); + strcpy(arg->wopts->papszWarpOptions[i++], unified_src_nodata_option); + arg->wopts->papszWarpOptions[i] = NULL; /* band mapping */ arg->wopts->nBandCount = numBands; diff --git a/raster/test/regress/loader/LongMaintenance.opts b/raster/test/regress/loader/LongMaintenance.opts index 0320409c5..e63937728 100644 --- a/raster/test/regress/loader/LongMaintenance.opts +++ b/raster/test/regress/loader/LongMaintenance.opts @@ -1,2 +1 @@ -# Exercise raster-only long maintenance actions and constraint creation. --add-constraints --vacuum --analyze diff --git a/regress/loader/LongOptions.opts b/regress/loader/LongOptions.opts index 098600e4b..dc46a9b2d 100644 --- a/regress/loader/LongOptions.opts +++ b/regress/loader/LongOptions.opts @@ -1,3 +1 @@ -# Exercise the public long action names as one loader invocation: -# drop, create-if-missing, load, idempotent index, no transaction, and analyze. ---drop-table --create-table --load-data --create-index --if-not-exists --no-transaction --no-analyze --analyze +--drop-table --create-table --load-data --create-index --if-not-exists --no-transaction --analyze ----------------------------------------------------------------------- Summary of changes: postgis/postgis.sql.in | 2 +- raster/rt_core/rt_warp.c | 33 ++++++++++++++++--------- raster/test/regress/loader/LongMaintenance.opts | 1 - regress/core/postgis_full_version.sql | 10 ++++---- regress/loader/LongOptions.opts | 4 +-- 5 files changed, 29 insertions(+), 21 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Sun Jun 21 06:45:03 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 06:45:03 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-641-g3b1b4aae0 Message-ID: <20260621134503.D20D01AD971@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 3b1b4aae021865171c25a37bcfc929e6e4d7a74b (commit) from c94f62361826e4dc14b660b31e6614727db8deb3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 3b1b4aae021865171c25a37bcfc929e6e4d7a74b Author: Darafei Praliaskouski Date: Sun Jun 21 17:43:55 2026 +0400 Move typmod bit helpers into libpgcommon The geometry and geography typmod bit-field helpers are PostgreSQL extension concerns, not liblwgeom public API. Move them to libpgcommon and relocate the CUnit coverage to the postgis helper test harness. Closes #3158 Closes https://github.com/postgis/postgis/pull/1089 diff --git a/NEWS b/NEWS index a9843c1aa..e4ac634d8 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Enhancements * + - #3158, Move geometry and geography typmod bit helpers out of the + public liblwgeom header (Darafei Praliaskouski) - #2116, [raster] Add ST_Value nearest-neighbor boundary options (Darafei Praliaskouski) - #2804, #4315, [raster] Support two-argument ST_MapAlgebra callbacks diff --git a/liblwgeom/cunit/cu_gserialized1.c b/liblwgeom/cunit/cu_gserialized1.c index 23f3b9743..e4f38666e 100644 --- a/liblwgeom/cunit/cu_gserialized1.c +++ b/liblwgeom/cunit/cu_gserialized1.c @@ -18,61 +18,6 @@ #include "gserialized1.c" /* for gserialized_peek_gbox_p */ #include "cu_tester.h" -static void test_typmod_macros(void) -{ - int32_t typmod = 0; - int32_t srid = 4326; - int type = 6; - int z = 1; - int rv; - - TYPMOD_SET_SRID(typmod,srid); - rv = TYPMOD_GET_SRID(typmod); - CU_ASSERT_EQUAL(rv, srid); - - srid = -5005; - TYPMOD_SET_SRID(typmod,srid); - rv = TYPMOD_GET_SRID(typmod); - CU_ASSERT_EQUAL(rv, srid); - - srid = 999999; - TYPMOD_SET_SRID(typmod,srid); - rv = TYPMOD_GET_SRID(typmod); - CU_ASSERT_EQUAL(rv, srid); - - srid = -999999; - TYPMOD_SET_SRID(typmod,srid); - rv = TYPMOD_GET_SRID(typmod); - CU_ASSERT_EQUAL(rv, srid); - - srid = SRID_UNKNOWN; - TYPMOD_SET_SRID(typmod,srid); - rv = TYPMOD_GET_SRID(typmod); - CU_ASSERT_EQUAL(rv, srid); - - srid = 0; - TYPMOD_SET_SRID(typmod,srid); - rv = TYPMOD_GET_SRID(typmod); - CU_ASSERT_EQUAL(rv, srid); - - srid = 1; - TYPMOD_SET_SRID(typmod,srid); - rv = TYPMOD_GET_SRID(typmod); - CU_ASSERT_EQUAL(rv, srid); - - TYPMOD_SET_TYPE(typmod,type); - rv = TYPMOD_GET_TYPE(typmod); - CU_ASSERT_EQUAL(rv,type); - - TYPMOD_SET_Z(typmod); - rv = TYPMOD_GET_Z(typmod); - CU_ASSERT_EQUAL(rv,z); - - rv = TYPMOD_GET_M(typmod); - CU_ASSERT_EQUAL(rv,0); - -} - static void test_flags_macros(void) { uint8_t flags = 0; @@ -1282,7 +1227,6 @@ void gserialized1_suite_setup(void); void gserialized1_suite_setup(void) { CU_pSuite suite = CU_add_suite("serialization/deserialization v1", NULL, NULL); - PG_ADD_TEST(suite, test_typmod_macros); PG_ADD_TEST(suite, test_flags_macros); PG_ADD_TEST(suite, test_serialized1_srid); PG_ADD_TEST(suite, test_gserialized1_from_lwgeom_size); diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index da1514458..17efdce61 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -181,25 +181,6 @@ typedef enum LWORD_T { #define FLAGS_GET_ZM(flags) (FLAGS_GET_M(flags) + FLAGS_GET_Z(flags) * 2) #define FLAGS_NDIMS_BOX(flags) (FLAGS_GET_GEODETIC(flags) ? 3 : FLAGS_NDIMS(flags)) -/** -* Macros for manipulating the 'typemod' int. An int32_t used as follows: -* Plus/minus = Top bit. -* Spare bits = Next 2 bits. -* SRID = Next 21 bits. -* TYPE = Next 6 bits. -* ZM Flags = Bottom 2 bits. -*/ - -#define TYPMOD_GET_SRID(typmod) ((((typmod) & 0x0FFFFF00) - ((typmod) & 0x10000000)) >> 8) -#define TYPMOD_SET_SRID(typmod, srid) ((typmod) = (((typmod) & 0xE00000FF) | ((srid & 0x001FFFFF)<<8))) -#define TYPMOD_GET_TYPE(typmod) ((typmod & 0x000000FC)>>2) -#define TYPMOD_SET_TYPE(typmod, type) ((typmod) = (typmod & 0xFFFFFF03) | ((type & 0x0000003F)<<2)) -#define TYPMOD_GET_Z(typmod) ((typmod & 0x00000002)>>1) -#define TYPMOD_SET_Z(typmod) ((typmod) = typmod | 0x00000002) -#define TYPMOD_GET_M(typmod) (typmod & 0x00000001) -#define TYPMOD_SET_M(typmod) ((typmod) = typmod | 0x00000001) -#define TYPMOD_GET_NDIMS(typmod) (2+TYPMOD_GET_Z(typmod)+TYPMOD_GET_M(typmod)) - /** * Maximum allowed SRID value in serialized geometry. * Currently we are using 21 bits (2097152) of storage for SRID. diff --git a/libpgcommon/Makefile.in b/libpgcommon/Makefile.in index 6f436e764..4fb9c3010 100644 --- a/libpgcommon/Makefile.in +++ b/libpgcommon/Makefile.in @@ -32,6 +32,7 @@ SA_OBJS = \ SA_HEADERS = \ lwgeom_pg.h \ + lwgeom_pg_typmod.h \ lwgeom_transform.h \ lwgeom_cache.h \ gserialized_gist.h @@ -68,4 +69,3 @@ $(SA_OBJS): %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< $(SA_OBJS): ../postgis_config.h - diff --git a/libpgcommon/lwgeom_pg_typmod.h b/libpgcommon/lwgeom_pg_typmod.h new file mode 100644 index 000000000..c7db7b913 --- /dev/null +++ b/libpgcommon/lwgeom_pg_typmod.h @@ -0,0 +1,50 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.net + * + * This file is part of PostGIS + * + * PostGIS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * PostGIS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PostGIS. If not, see . + * + ********************************************************************** + * + * Copyright 2026 Darafei Praliaskouski + * + **********************************************************************/ + +#ifndef LWGEOM_PG_TYPMOD_H +#define LWGEOM_PG_TYPMOD_H 1 + +/* + * Macros for manipulating the PostgreSQL typmod int32_t used by the + * PostGIS geometry and geography types: + * + * Plus/minus = Top bit. + * Spare bits = Next 2 bits. + * SRID = Next 21 bits. + * TYPE = Next 6 bits. + * ZM Flags = Bottom 2 bits. + */ +#define TYPMOD_GET_SRID(typmod) ((((typmod) & 0x0FFFFF00) - ((typmod) & 0x10000000)) >> 8) +#define TYPMOD_SET_SRID(typmod, srid) ((typmod) = (((typmod) & 0xE00000FF) | ((srid & 0x001FFFFF) << 8))) +#define TYPMOD_GET_TYPE(typmod) (((typmod) & 0x000000FC) >> 2) +#define TYPMOD_SET_TYPE(typmod, type) ((typmod) = ((typmod) & 0xFFFFFF03) | (((type) & 0x0000003F) << 2)) +#define TYPMOD_GET_Z(typmod) (((typmod) & 0x00000002) >> 1) +#define TYPMOD_SET_Z(typmod) ((typmod) = (typmod) | 0x00000002) +#define TYPMOD_GET_M(typmod) ((typmod) & 0x00000001) +#define TYPMOD_SET_M(typmod) ((typmod) = (typmod) | 0x00000001) +#define TYPMOD_GET_NDIMS(typmod) (2 + TYPMOD_GET_Z(typmod) + TYPMOD_GET_M(typmod)) + +#endif /* LWGEOM_PG_TYPMOD_H */ diff --git a/postgis/Makefile.in b/postgis/Makefile.in index e292772c2..a3e2d46f5 100644 --- a/postgis/Makefile.in +++ b/postgis/Makefile.in @@ -273,6 +273,7 @@ distclean: clean if [ -e "cunit/Makefile" ]; then make -C cunit distclean; fi check-unit: + $(MAKE) -C cunit check check-regress: diff --git a/postgis/cunit/cu_tester.c b/postgis/cunit/cu_tester.c index eb6ba5b0d..6fe59a1d9 100644 --- a/postgis/cunit/cu_tester.c +++ b/postgis/cunit/cu_tester.c @@ -20,7 +20,7 @@ * ********************************************************************** * - * Copyright 2025 (C) Darafei Praliaskouski + * Copyright 2025-2026 (C) Darafei Praliaskouski * **********************************************************************/ @@ -31,6 +31,8 @@ #include #include +#include "liblwgeom.h" +#include "lwgeom_pg_typmod.h" #include "../gserialized_estimate_support.h" static ND_BOX @@ -50,6 +52,65 @@ make_box(float minx, float miny, float minz, float minm, float maxx, float maxy, return box; } +static void +typmod_bitfield_roundtrip(void) +{ + int32_t typmod = 0; + int32_t srid = 4326; + int type = 6; + int z = 1; + int rv; + + TYPMOD_SET_SRID(typmod, srid); + rv = TYPMOD_GET_SRID(typmod); + CU_ASSERT_EQUAL(rv, srid); + + srid = -5005; + TYPMOD_SET_SRID(typmod, srid); + rv = TYPMOD_GET_SRID(typmod); + CU_ASSERT_EQUAL(rv, srid); + + srid = 999999; + TYPMOD_SET_SRID(typmod, srid); + rv = TYPMOD_GET_SRID(typmod); + CU_ASSERT_EQUAL(rv, srid); + + srid = -999999; + TYPMOD_SET_SRID(typmod, srid); + rv = TYPMOD_GET_SRID(typmod); + CU_ASSERT_EQUAL(rv, srid); + + srid = SRID_UNKNOWN; + TYPMOD_SET_SRID(typmod, srid); + rv = TYPMOD_GET_SRID(typmod); + CU_ASSERT_EQUAL(rv, srid); + + srid = 0; + TYPMOD_SET_SRID(typmod, srid); + rv = TYPMOD_GET_SRID(typmod); + CU_ASSERT_EQUAL(rv, srid); + + srid = 1; + TYPMOD_SET_SRID(typmod, srid); + rv = TYPMOD_GET_SRID(typmod); + CU_ASSERT_EQUAL(rv, srid); + + TYPMOD_SET_TYPE(typmod, type); + rv = TYPMOD_GET_TYPE(typmod); + CU_ASSERT_EQUAL(rv, type); + + TYPMOD_SET_Z(typmod); + rv = TYPMOD_GET_Z(typmod); + CU_ASSERT_EQUAL(rv, z); + + rv = TYPMOD_GET_M(typmod); + CU_ASSERT_EQUAL(rv, 0); + + TYPMOD_SET_M(typmod); + rv = TYPMOD_GET_M(typmod); + CU_ASSERT_EQUAL(rv, 1); +} + static void histogram_budget_clamps(void) { @@ -151,11 +212,12 @@ main(void) if (CU_initialize_registry() != CUE_SUCCESS) return CU_get_error(); - suite = CU_add_suite("gserialized_histogram_helpers", NULL, NULL); + suite = CU_add_suite("postgis_helpers", NULL, NULL); if (!suite) goto cleanup; - if (!CU_add_test(suite, "histogram budget clamps", histogram_budget_clamps) || + if (!CU_add_test(suite, "typmod bitfield roundtrip", typmod_bitfield_roundtrip) || + !CU_add_test(suite, "histogram budget clamps", histogram_budget_clamps) || !CU_add_test(suite, "histogram axis guards", histogram_axis_allocation_guards) || !CU_add_test(suite, "nd_stats value index guards", nd_stats_indexing_behaviour) || !CU_add_test(suite, "nd_box ratio edge cases", nd_box_ratio_cases)) diff --git a/postgis/gserialized_typmod.c b/postgis/gserialized_typmod.c index 8e5f63b56..228097490 100644 --- a/postgis/gserialized_typmod.c +++ b/postgis/gserialized_typmod.c @@ -41,10 +41,10 @@ #include "catalog/pg_type.h" /* for CSTRINGOID */ #include "liblwgeom.h" /* For standard geometry types. */ -#include "lwgeom_pg.h" /* For debugging macros. */ -#include "geography.h" /* For utility functions. */ -#include "lwgeom_transform.h" /* for srid_is_latlon */ - +#include "lwgeom_pg.h" /* For debugging macros. */ +#include "lwgeom_pg_typmod.h" /* For typmod bit-field accessors. */ +#include "geography.h" /* For utility functions. */ +#include "lwgeom_transform.h" /* for srid_is_latlon */ Datum geography_typmod_in(PG_FUNCTION_ARGS); Datum geometry_typmod_in(PG_FUNCTION_ARGS); @@ -462,4 +462,3 @@ Datum postgis_typmod_srid(PG_FUNCTION_ARGS) PG_RETURN_INT32(0); PG_RETURN_INT32(TYPMOD_GET_SRID(typmod)); } - ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ liblwgeom/cunit/cu_gserialized1.c | 56 -------------------------------- liblwgeom/liblwgeom.h.in | 19 ----------- libpgcommon/Makefile.in | 2 +- libpgcommon/lwgeom_pg_typmod.h | 50 ++++++++++++++++++++++++++++ postgis/Makefile.in | 1 + postgis/cunit/cu_tester.c | 68 +++++++++++++++++++++++++++++++++++++-- postgis/gserialized_typmod.c | 9 +++--- 8 files changed, 123 insertions(+), 84 deletions(-) create mode 100644 libpgcommon/lwgeom_pg_typmod.h hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 06:45:05 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 13:45:05 -0000 Subject: [PostGIS] #3158: Move TYPMOD handling out of liblwgeom In-Reply-To: <046.5cb75fc32521ff3f73d112af9a9c36a6@osgeo.org> References: <046.5cb75fc32521ff3f73d112af9a9c36a6@osgeo.org> Message-ID: <061.b4ff4b09cc6f2018f8569b42416ed172@osgeo.org> #3158: Move TYPMOD handling out of liblwgeom ------------------------+----------------------------- Reporter: strk | Owner: strk Type: task | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: liblwgeom | Version: master Resolution: fixed | Keywords: ------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: assigned => closed Comment: In [changeset:"3b1b4aae021865171c25a37bcfc929e6e4d7a74b/git" 3b1b4aa/git]: {{{#!CommitTicketReference repository="git" revision="3b1b4aae021865171c25a37bcfc929e6e4d7a74b" Move typmod bit helpers into libpgcommon The geometry and geography typmod bit-field helpers are PostgreSQL extension concerns, not liblwgeom public API. Move them to libpgcommon and relocate the CUnit coverage to the postgis helper test harness. Closes #3158 Closes https://github.com/postgis/postgis/pull/1089 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 07:06:09 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 07:06:09 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-642-g6884c2be4 Message-ID: <20260621140610.25E721AEB12@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 6884c2be41810eb4d02a1d0f88ca61439024f827 (commit) from 3b1b4aae021865171c25a37bcfc929e6e4d7a74b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6884c2be41810eb4d02a1d0f88ca61439024f827 Author: Darafei Praliaskouski Date: Sun Jun 21 17:51:52 2026 +0400 Clarify raster2pgsql index creation timing Document that -I and --create-index create the spatial index at the end of each raster2pgsql run, so repeated append batches should create the index only on the final run or create it manually after loading. Group related loader argument NEWS entries and use bounded formatting for the generated CREATE INDEX SQL while updating the same code path. Closes #4385 Closes https://github.com/postgis/postgis/pull/1031 diff --git a/NEWS b/NEWS index e4ac634d8..c67f2b50f 100644 --- a/NEWS +++ b/NEWS @@ -21,11 +21,10 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * New Features * - - #1124, shp2pgsql can create UNLOGGED tables for transient staging loads - (Darafei Praliaskouski) - - #2935, shp2pgsql --drop-table can emit DROP TABLE before prepare output - (Darafei Praliaskouski) - - raster2pgsql and shp2pgsql expose loader actions as long options + - #1124, #2935, #4659, [loader] Rework loader arguments: shp2pgsql can + create UNLOGGED tables, shp2pgsql --drop-table can emit DROP TABLE + before prepare output, raster2pgsql/shp2pgsql expose loader actions + as long options, and --if-not-exists makes creation actions idempotent (Darafei Praliaskouski) - #4208, Add single-geometry variants of ST_MaxDistance and ST_LongestLine (Darafei Praliaskouski) @@ -69,9 +68,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #6062, [topology] Stop using recursive snapping, for improved robustness (Sandro Santilli) - #6065, Improved winding order computation robustness for rings having collapsed elements (Sandro Santilli) - - #3743, [raster] Document and test raster2pgsql -s FROM_SRID:SRID - reprojection support (Darafei Praliaskouski) - - #4659, [raster] Add raster2pgsql and shp2pgsql long loader action options + - #3743, #4385, [raster loader] Document raster2pgsql -s FROM_SRID:SRID + reprojection support and clarify index creation timing for append loads (Darafei Praliaskouski) - #4749, Use point-in-polygon predicate fast paths for point-only GeometryCollections (Darafei Praliaskouski) diff --git a/doc/man/raster2pgsql.1 b/doc/man/raster2pgsql.1 index 5fd3e3f0d..17fa7194d 100644 --- a/doc/man/raster2pgsql.1 +++ b/doc/man/raster2pgsql.1 @@ -55,9 +55,10 @@ Create a new table and populate it. This is the default mode. Prepare mode. Only emit SQL to create the table. .TP \fB\-\-if\-not\-exists\fR -Use IF NOT EXISTS for table creation in \-c and \-p modes. When \-I is also -specified, use IF NOT EXISTS for index creation too. This option cannot be used -with \-d. Append mode requires an explicit creation action. +Use IF NOT EXISTS for table creation in \-c and \-p modes. When \-I or +\-\-create\-index is also specified, use IF NOT EXISTS for index creation too. +This option cannot be used with \-d. Append mode requires an explicit creation +action. .TP \fB\-\-drop\-table\fR Drop the target table before other actions. With no mode specified, the default @@ -88,10 +89,13 @@ overviews are stored in the database and are not affected by \-R. Wrap PostgreSQL identifiers in quotes. .TP \fB\-I\fR -Create a GiST spatial index on the raster column. +Alias for \-\-create\-index. .TP \fB\-\-create\-index\fR -Create a GiST spatial index on the raster column. +Create a GiST spatial index on the raster column at the end of this +raster2pgsql run. With repeated \-a append runs, create the index on the final +run or after loading; add \-\-if\-not\-exists to make reruns tolerate an +existing index. .TP \fB\-M\fR Run VACUUM ANALYZE on the raster table. This is most useful when appending to an diff --git a/doc/using_raster_dataman.xml b/doc/using_raster_dataman.xml index 7568d3ada..a686de06e 100644 --- a/doc/using_raster_dataman.xml +++ b/doc/using_raster_dataman.xml @@ -143,10 +143,10 @@ Available GDAL raster formats: Use IF NOT EXISTS for table creation in and modes. When - is also specified, use - IF NOT EXISTS for index creation too. This - option cannot be used with . Append mode - requires an explicit creation action. + or is also + specified, use IF NOT EXISTS for index + creation too. This option cannot be used with . + Append mode requires an explicit creation action. @@ -319,7 +319,20 @@ Available GDAL raster formats: - Create a GiST index on the raster column. + Alias for . + + + + + + + + + Create a GiST index on the raster column at the end of this + raster2pgsql run. With repeated append + runs, create the index on the final run or after loading; + add to make reruns tolerate + an existing index. diff --git a/raster/loader/raster2pgsql.c b/raster/loader/raster2pgsql.c index 0a7474945..450474eb6 100644 --- a/raster/loader/raster2pgsql.c +++ b/raster/loader/raster2pgsql.c @@ -382,14 +382,18 @@ usage() { " -p Prepare mode, only creates the table.\n")); printf( _(" --if-not-exists Use IF NOT EXISTS for table creation in -c and -p\n" - " modes. With -I, also use IF NOT EXISTS for index creation.\n" + " modes. With -I/--create-index, also use IF NOT EXISTS for index\n" + " creation.\n" " Append mode requires an explicit creation action.\n")); printf( _(" --drop-table Drop the target table before other actions.\n" " With no mode specified, the default create/load actions still apply.\n" " --create-table Create the target table.\n" " --load-data Load raster data into the target table.\n" - " --create-index Create a GIST spatial index on the raster column.\n")); + " --create-index Create a GIST spatial index on the raster column\n" + " at the end of this raster2pgsql run. With repeated -a append\n" + " runs, create the index on the final run or after loading; add\n" + " --if-not-exists to make reruns tolerate an existing index.\n")); printf(_( " -f Specify the name of the raster column\n" )); @@ -408,10 +412,7 @@ usage() { printf(_( " -q Wrap PostgreSQL identifiers in quotes.\n" )); - printf(_( - " -I Create a GIST spatial index on the raster column. The ANALYZE\n" - " command will automatically be issued for the created index.\n" - )); + printf(_(" -I Alias for --create-index.\n")); printf( _(" --add-constraints Set the standard set of constraints on the\n" " raster column after the rasters are loaded.\n" @@ -1152,7 +1153,7 @@ create_index(const char *schema, STRINGBUFFER *buffer) { char *sql = NULL; - uint32_t len = 0; + size_t len = 0; char *_table = NULL; char *_column = NULL; @@ -1182,25 +1183,27 @@ create_index(const char *schema, } if (if_not_exists) { - sprintf(sql, - "CREATE INDEX IF NOT EXISTS \"%s_%s_gist\" ON %s%s USING gist (st_convexhull(%s))%s%s;", - _table, - _column, - (schema != NULL ? schema : ""), - table, - column, - (tablespace != NULL ? " TABLESPACE " : ""), - (tablespace != NULL ? tablespace : "")); + snprintf(sql, + len, + "CREATE INDEX IF NOT EXISTS \"%s_%s_gist\" ON %s%s USING gist (st_convexhull(%s))%s%s;", + _table, + _column, + (schema != NULL ? schema : ""), + table, + column, + (tablespace != NULL ? " TABLESPACE " : ""), + (tablespace != NULL ? tablespace : "")); } else { - sprintf(sql, - "CREATE INDEX ON %s%s USING gist (st_convexhull(%s))%s%s;", - (schema != NULL ? schema : ""), - table, - column, - (tablespace != NULL ? " TABLESPACE " : ""), - (tablespace != NULL ? tablespace : "")); + snprintf(sql, + len, + "CREATE INDEX ON %s%s USING gist (st_convexhull(%s))%s%s;", + (schema != NULL ? schema : ""), + table, + column, + (tablespace != NULL ? " TABLESPACE " : ""), + (tablespace != NULL ? tablespace : "")); } rtdealloc(_table); rtdealloc(_column); ----------------------------------------------------------------------- Summary of changes: NEWS | 14 ++++++------- doc/man/raster2pgsql.1 | 14 ++++++++----- doc/using_raster_dataman.xml | 23 ++++++++++++++++----- raster/loader/raster2pgsql.c | 49 +++++++++++++++++++++++--------------------- 4 files changed, 59 insertions(+), 41 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 07:06:11 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 14:06:11 -0000 Subject: [PostGIS] #4385: [raster2pgsql] -I option recreates index for each insertion In-Reply-To: <047.bf5123fe514f4eb3652182f7b4cd41fb@osgeo.org> References: <047.bf5123fe514f4eb3652182f7b4cd41fb@osgeo.org> Message-ID: <062.f55341386c98797143409896c21486da@osgeo.org> #4385: [raster2pgsql] -I option recreates index for each insertion --------------------------+----------------------------- Reporter: RaphJ | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: 2.4.x Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"6884c2be41810eb4d02a1d0f88ca61439024f827/git" 6884c2b/git]: {{{#!CommitTicketReference repository="git" revision="6884c2be41810eb4d02a1d0f88ca61439024f827" Clarify raster2pgsql index creation timing Document that -I and --create-index create the spatial index at the end of each raster2pgsql run, so repeated append batches should create the index only on the final run or create it manually after loading. Group related loader argument NEWS entries and use bounded formatting for the generated CREATE INDEX SQL while updating the same code path. Closes #4385 Closes https://github.com/postgis/postgis/pull/1031 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 07:13:12 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 07:13:12 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-643-g45c26068e Message-ID: <20260621141312.CE4DF1AF097@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 45c26068ef27de003a39e69c01532340063ecc13 (commit) from 6884c2be41810eb4d02a1d0f88ca61439024f827 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 45c26068ef27de003a39e69c01532340063ecc13 Author: Darafei Praliaskouski Date: Sun Jun 21 18:12:09 2026 +0400 Clarify shp2pgsql zip archive input Report .zip archive input before the loader tries to open shapefile sidecar files, and document that shapefiles must be unpacked before loading. References #1577 Closes https://github.com/postgis/postgis/pull/1109 diff --git a/NEWS b/NEWS index c67f2b50f..20209cb38 100644 --- a/NEWS +++ b/NEWS @@ -57,6 +57,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Enhancements * + - #1577, [loader] Report unsupported .zip archive input before trying + to open shapefile sidecar files (Darafei Praliaskouski) - #3158, Move geometry and geography typmod bit helpers out of the public liblwgeom header (Darafei Praliaskouski) - #2116, [raster] Add ST_Value nearest-neighbor boundary options diff --git a/doc/man/shp2pgsql.1 b/doc/man/shp2pgsql.1 index c840c60f9..2cd3b9720 100644 --- a/doc/man/shp2pgsql.1 +++ b/doc/man/shp2pgsql.1 @@ -19,6 +19,8 @@ Version: 1.1.5 (2006/10/06) The is the name of the shape file, without any extension information. For example, 'roads' would be the name of the shapefile comprising the 'roads.shp', 'roads.shx', and 'roads.dbf' files. +Compressed archives are not read directly; unpack .zip packages before +loading the shapefile components. The is the (optionally schema-qualified) name of the database table you want the data stored in in the database. Within that table, diff --git a/doc/using_postgis_dataman.xml b/doc/using_postgis_dataman.xml index 8f840a5ce..be8c75391 100644 --- a/doc/using_postgis_dataman.xml +++ b/doc/using_postgis_dataman.xml @@ -1877,6 +1877,11 @@ COMMIT; insertion into a PostGIS/PostgreSQL database either in geometry or geography format. The loader has several operating modes selected by command line flags. + + The input must be an unpacked shapefile path. The loader does not read + .zip archives directly; unpack the .shp, + .shx, and .dbf files before loading. + There is also a shp2pgsql-gui graphical interface with most of the options as the command-line loader. This may be easier to use for one-off non-scripted loading or if you are new to PostGIS. diff --git a/loader/cunit/cu_shp2pgsql.c b/loader/cunit/cu_shp2pgsql.c index 01be2be03..c43f5ac55 100644 --- a/loader/cunit/cu_shp2pgsql.c +++ b/loader/cunit/cu_shp2pgsql.c @@ -20,6 +20,7 @@ void test_ShpLoaderDestroy(void); void test_ShpLoaderGetSQLHeader_drop_prepare(void); void test_ShpLoaderGetSQLHeader_if_not_exists_table_modifier(void); void test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier(void); +void test_ShpLoaderOpenShapeRejectsZip(void); SHPLOADERCONFIG *loader_config; SHPLOADERSTATE *loader_state; @@ -47,7 +48,8 @@ CU_pSuite register_shp2pgsql_suite(void) test_ShpLoaderGetSQLHeader_if_not_exists_table_modifier)) || (NULL == CU_add_test(pSuite, "test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier()", - test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier))) + test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier)) || + (NULL == CU_add_test(pSuite, "test_ShpLoaderOpenShapeRejectsZip()", test_ShpLoaderOpenShapeRejectsZip))) { CU_cleanup_registry(); return NULL; @@ -175,3 +177,28 @@ test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier(void) free(footer); ShpLoaderDestroy(loader_state); } + +void +test_ShpLoaderOpenShapeRejectsZip(void) +{ + int ret; + + loader_config = (SHPLOADERCONFIG *)calloc(1, sizeof(SHPLOADERCONFIG)); + set_loader_config_defaults(loader_config); + loader_config->shp_file = "fixtures/parcel.ZIP"; + loader_state = ShpLoaderCreate(loader_config); + ret = ShpLoaderOpenShape(loader_state); + CU_ASSERT_EQUAL(ret, SHPLOADERERR); + CU_ASSERT_PTR_NOT_NULL(strstr(loader_state->message, "does not read .zip archives")); + ShpLoaderDestroy(loader_state); + + loader_config = (SHPLOADERCONFIG *)calloc(1, sizeof(SHPLOADERCONFIG)); + set_loader_config_defaults(loader_config); + loader_config->shp_file = "fixtures.zip/parcel"; + loader_config->readshape = 0; + loader_state = ShpLoaderCreate(loader_config); + ret = ShpLoaderOpenShape(loader_state); + CU_ASSERT_EQUAL(ret, SHPLOADERERR); + CU_ASSERT_PTR_NULL(strstr(loader_state->message, "does not read .zip archives")); + ShpLoaderDestroy(loader_state); +} diff --git a/loader/shp2pgsql-core.c b/loader/shp2pgsql-core.c index 52226802a..394d5dd66 100644 --- a/loader/shp2pgsql-core.c +++ b/loader/shp2pgsql-core.c @@ -16,6 +16,7 @@ #include "../postgis_config.h" #include /* for isnan */ +#include #include "shp2pgsql-core.h" #include "../liblwgeom/liblwgeom.h" @@ -55,7 +56,25 @@ int PIP(Point P, Point *V, int n); int FindPolygons(SHPObject *obj, Ring ***Out); void ReleasePolygons(Ring **polys, int npolys); int GeneratePolygonGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry); +static int shp_loader_is_zip_archive(const char *filename); +static int +shp_loader_is_zip_archive(const char *filename) +{ + const char *basename; + const char *ext; + + if (!filename) + return 0; + + basename = strrchr(filename, '/'); + if (!basename) + basename = strrchr(filename, '\\'); + basename = basename ? basename + 1 : filename; + + ext = strrchr(basename, '.'); + return ext && strcasecmp(ext, ".zip") == 0; +} /* Return allocated string containing UTF8 string converted from encoding fromcode */ static int @@ -966,6 +985,15 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state) DBFFieldType type = FTInvalid; char *utf8str; + if (shp_loader_is_zip_archive(state->config->shp_file)) + { + snprintf(state->message, + SHPLOADERMSGLEN, + _("%s: shp2pgsql does not read .zip archives; unpack the .shp, .shx, and .dbf files first."), + state->config->shp_file); + return SHPLOADERERR; + } + /* If we are reading the entire shapefile, open it */ if (state->config->readshape == 1) { ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ doc/man/shp2pgsql.1 | 2 ++ doc/using_postgis_dataman.xml | 5 +++++ loader/cunit/cu_shp2pgsql.c | 29 ++++++++++++++++++++++++++++- loader/shp2pgsql-core.c | 28 ++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 07:13:14 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 14:13:14 -0000 Subject: [PostGIS] #1577: Add support for .zip input in shp2pgsql In-Reply-To: <046.a69a5864dcbcbafaa2246a396d120f97@osgeo.org> References: <046.a69a5864dcbcbafaa2246a396d120f97@osgeo.org> Message-ID: <061.3845fae4f595e308facf74694beac661@osgeo.org> #1577: Add support for .zip input in shp2pgsql ----------------------------------+----------------------------- Reporter: strk | Owner: mcayland Type: enhancement | Status: new Priority: low | Milestone: PostGIS Fund Me Component: utils/loader-dumper | Version: master Resolution: | Keywords: ----------------------------------+----------------------------- Comment (by Darafei Praliaskouski ): In [changeset:"45c26068ef27de003a39e69c01532340063ecc13/git" 45c2606/git]: {{{#!CommitTicketReference repository="git" revision="45c26068ef27de003a39e69c01532340063ecc13" Clarify shp2pgsql zip archive input Report .zip archive input before the loader tries to open shapefile sidecar files, and document that shapefiles must be unpacked before loading. References #1577 Closes https://github.com/postgis/postgis/pull/1109 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 09:56:18 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 09:56:18 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-645-g1c8bb486c Message-ID: <20260621165619.3B2231B0C0D@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 1c8bb486ca51d64a9cc767c0a2a487c2275be33b (commit) via c222d23c27f4225b403ac19bfe53cff2c557e1a0 (commit) from 45c26068ef27de003a39e69c01532340063ecc13 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1c8bb486ca51d64a9cc767c0a2a487c2275be33b Author: Darafei Praliaskouski Date: Sun Jun 21 18:34:09 2026 +0400 Add long option aliases to shp2pgsql Accept GNU-style long aliases for existing shp2pgsql command-line options, including --option=value spelling for value-taking options. Reuse the existing short-option switch so the loader action long options remain the canonical action vocabulary. References #4658 diff --git a/NEWS b/NEWS index 4fb4532c8..199261ee1 100644 --- a/NEWS +++ b/NEWS @@ -24,7 +24,7 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #1124, #2935, #4658, #4659, [loader] Rework loader arguments: shp2pgsql can create UNLOGGED tables, shp2pgsql --drop-table can emit DROP TABLE before prepare output, raster2pgsql/shp2pgsql expose loader actions - as long options, raster2pgsql accepts long aliases for existing + as long options, both loaders accept long aliases for existing options, and --if-not-exists makes creation actions idempotent (Darafei Praliaskouski) - #4208, Add single-geometry variants of ST_MaxDistance and ST_LongestLine diff --git a/doc/man/shp2pgsql.1 b/doc/man/shp2pgsql.1 index 2cd3b9720..2895b5c36 100644 --- a/doc/man/shp2pgsql.1 +++ b/doc/man/shp2pgsql.1 @@ -30,6 +30,8 @@ the geometry will be placed in the 'geo_value' column by default. .LP The loader has several operating modes distinguished by command line flags: +Long options that take values also accept the \fB\-\-option=value\fR spelling. + (Note that \-a, \-c, \-d and \-p are mutually exclusive.) .TP \fB\-d\fR @@ -61,44 +63,41 @@ create-and-load action set. \fB\-\-load\-data\fR Load Shape file rows into the target table. .TP -\fB\-D\fR +\fB\-D\fR, \fB\-\-dump\-format\fR Use the PostgreSQL "dump" format for the output data. This can be combined with \-a, \-c and \-d. It is much faster to load than the default "insert" SQL format. Use this for very large data sets. .TP -\fB\-w\fR +\fB\-w\fR, \fB\-\-use\-wkt\fR Output WKT format, instead of WKB. Note that this can introduce coordinate drifts due to loss of precision. .TP -\fB\-e\fR +\fB\-e\fR, \fB\-\-no\-transaction\fR Execute each statement on its own, without using a transaction. This allows loading of the majority of good data when there are some bad geometries that generate errors. Note that this cannot be used with the \-D flag as the "dump" format always uses a transaction. .TP -\fB\-\-no\-transaction\fR -Execute each statement individually, without using a transaction. -.TP -\fB\-s\fR [<\fIFROM_SRID\fR>:]<\fISRID\fR> +\fB\-s\fR, \fB\-\-srid\fR [<\fIFROM_SRID\fR>:]<\fISRID\fR> Creates and populates the geometry tables with the specified SRID. If FROM_SRID is given, the geometries will be reprojected. Reprojection cannot be used with \-D. .TP -\fB\-G\fR +\fB\-G\fR, \fB\-\-geography\fR Use the geography type instead of geometry. Geography is used to store lat/lon data. At the moment the only spatial reference supported is 4326. .TP -\fB\-g\fR <\fIgeometry_column\fR> +\fB\-g\fR, \fB\-\-geometry\-column\fR <\fIgeometry_column\fR> Specify the name of the geometry column (mostly useful in append mode). .TP \fB\-\-create\-index\fR Create a spatial index on the geometry column. .TP -\fB\-k\fR +\fB\-k\fR, \fB\-\-keep\-case\fR Keep identifiers case (column, schema and attributes). Note that attributes in Shapefile are usually all UPPERCASE. .TP -\fB\-m\fR <\fIfilename\fR> +\fB\-m\fR, \fB\-\-column\-map\fR <\fIfilename\fR> Specify a file containing a set of mappings of (long) column names to 10 character DBF column names. The content of the file is one or more lines of two names separated by white space and no trailing or leading space: @@ -109,18 +108,21 @@ AVERYLONGCOLUMNNAME DBFFIELD2\\n etc. .TP -\fB\-i\fR +\fB\-i\fR, \fB\-\-force\-int4\fR Coerce all integers to standard 32\-bit integers, do not create 64\-bit bigints, even if the DBF header signature appears to warrant it. .TP -\fB\-S\fR +\fB\-S\fR, \fB\-\-simple\-geometries\fR Generate simple Geometries instead of MULTIgeometries. Shape files don't differ between LINESTRINGs and MULTILINESTRINGs, so shp2pgsql generates MULTILINESTRINGs by default. This switch will produce LINESTRINGs instead, but shp2pgsql will fail when it hits a real MULTILINESTRING. The same works for POLYGONs vs. MULTIPOLYGONs. .TP -\fB\-W\fR <\fIencoding\fR> +\fB\-t\fR, \fB\-\-dimensionality\fR <\fIdimensionality\fR> +Force geometry to be one of 2D, 3DZ, 3DM, or 4D. +.TP +\fB\-W\fR, \fB\-\-encoding\fR <\fIencoding\fR> Specify the character \fIencoding\fR of Shapefile's attributes. If this option is used the output will be encoded in UTF-8. .TP @@ -136,24 +138,27 @@ Analyze the table after loading. \fB\-\-no\-analyze\fR Prevent tables from being analyzed. .TP -\fB\-u\fR +\fB\-u\fR, \fB\-\-unlogged\fR Create the target table as UNLOGGED. This can speed up loading transient staging data, but PostgreSQL does not preserve unlogged table contents after a crash or unclean shutdown. .TP -\fB\-N\fR <\fIpolicy\fR> +\fB\-N\fR, \fB\-\-null\-policy\fR <\fIpolicy\fR> Specify NULL geometries handling policy (insert,skip,abort). +.TP +\fB\-n\fR, \fB\-\-dbf\-only\fR +Only import the DBF file. .TP -\fB\-T\fR <\fItablespace\fR> +\fB\-T\fR, \fB\-\-tablespace\fR <\fItablespace\fR> Specify the tablespace for the new table. Indexes will still use the default tablespace unless the \-X parameter is also used. The PostgreSQL documentation has a good description on when to use custom tablespaces. .TP -\fB\-X\fR <\fItablespace\fR> +\fB\-X\fR, \fB\-\-index\-tablespace\fR <\fItablespace\fR> Specify the tablespace for the new table's indexes. This applies to the primary key index, and the GIST spatial index if \-I is also used. .TP -\fB\-?\fR +\fB\-?\fR, \fB\-\-help\fR Display version and usage information. .SH "INSTALLATION" diff --git a/loader/shp2pgsql-cli.c b/loader/shp2pgsql-cli.c index bcd03e516..13690e91f 100644 --- a/loader/shp2pgsql-cli.c +++ b/loader/shp2pgsql-cli.c @@ -20,16 +20,100 @@ #define xstr(s) str(s) #define str(s) #s +typedef struct { + const char *name; + int short_option; + int takes_value; +} ShpLoaderLongOption; + +static const ShpLoaderLongOption long_option_aliases[] = { + {"column-map", 'm', 1}, + {"create-index", 'I', 0}, + {"dbf-only", 'n', 0}, + {"dimensionality", 't', 1}, + {"dump-format", 'D', 0}, + {"encoding", 'W', 1}, + {"force-int4", 'i', 0}, + {"geography", 'G', 0}, + {"geometry-column", 'g', 1}, + {"help", '?', 0}, + {"index-tablespace", 'X', 1}, + {"keep-case", 'k', 0}, + {"no-analyze", 'Z', 0}, + {"no-transaction", 'e', 0}, + {"null-policy", 'N', 1}, + {"simple-geometries", 'S', 0}, + {"srid", 's', 1}, + {"tablespace", 'T', 1}, + {"unlogged", 'u', 0}, + {"use-wkt", 'w', 0}, +}; + +static int +consume_long_option(int argc, char **argv, int *option) +{ + char *arg = argv[pgis_optind]; + char *equals = strchr(arg, '='); + size_t name_len = equals ? (size_t)(equals - arg - 2) : strlen(arg + 2); + size_t i; + + if (strncmp(arg, "--", 2) != 0) + return 0; + + for (i = 0; i < sizeof(long_option_aliases) / sizeof(long_option_aliases[0]); i++) + { + const ShpLoaderLongOption *alias = &long_option_aliases[i]; + if (strlen(alias->name) != name_len || strncmp(arg + 2, alias->name, name_len) != 0) + continue; + + if (alias->takes_value) + { + if (equals) + { + pgis_optarg = equals + 1; + pgis_optind++; + } + else if (pgis_optind + 1 < argc) + { + pgis_optarg = argv[pgis_optind + 1]; + pgis_optind += 2; + } + else + { + fprintf(stderr, "Option requires an argument: --%s\n", alias->name); + exit(1); + } + } + else + { + if (equals) + { + fprintf(stderr, "Option does not take an argument: --%s\n", alias->name); + exit(1); + } + pgis_optarg = NULL; + pgis_optind++; + } + + *option = alias->short_option; + return 1; + } + + return 0; +} + static void usage() { printf(_( "RELEASE: %s (%s)\n" ), POSTGIS_LIB_VERSION, xstr(POSTGIS_REVISION)); - printf(_( "USAGE: shp2pgsql [] [[.]
]\n" - "OPTIONS:\n" )); - printf(_( " -s [:] Set the SRID field. Defaults to %d.\n" - " Optionally reprojects from given SRID.\n"), - SRID_UNKNOWN); + printf( + _("USAGE: shp2pgsql [] [[.]
]\n" + "OPTIONS:\n" + " Long options with values also accept --option=value.\n")); + printf(_(" -s, --srid [:] Set the SRID field. Defaults to %d.\n" + " Optionally reprojects from given SRID.\n"), + SRID_UNKNOWN); printf(_( " (-d|a|c|p) These are mutually exclusive options:\n" " -d Drops the table, then recreates it and populates\n" " it with current shape file data.\n" @@ -38,47 +122,53 @@ usage() " -c Creates a new table and populates it, this is the\n" " default if you do not specify any options.\n" " -p Prepare mode, only creates the table.\n" )); - printf(_( " -g Specify the name of the geometry/geography column\n" - " (mostly useful in append mode).\n" )); - printf(_( " -D Use postgresql dump format (defaults to SQL insert statements).\n" )); + printf( + _(" -g, --geometry-column Specify the name of the geometry/geography column\n" + " (mostly useful in append mode).\n")); + printf(_(" -D, --dump-format Use postgresql dump format (defaults to SQL insert statements).\n")); printf(_( " -e Execute each statement individually, do not use a transaction.\n" " Not compatible with -D.\n" )); - printf(_( " -G Use geography type (requires lon/lat data or -s to reproject).\n" )); - printf(_( " -k Keep postgresql identifiers case.\n" )); - printf(_( " -i Use int4 type for all integer dbf fields.\n" )); + printf(_(" -G, --geography Use geography type (requires lon/lat data or -s to reproject).\n")); + printf(_(" -k, --keep-case Keep postgresql identifiers case.\n")); + printf(_(" -i, --force-int4 Use int4 type for all integer dbf fields.\n")); printf(_( " -I Create a spatial index on the geocolumn.\n" )); printf(_(" --create-index Create a spatial index on the geocolumn.\n")); - printf(_( " -u Create the table as UNLOGGED.\n" )); - printf(_(" -m Specify a file containing a set of mappings of (long) column\n" - " names to 10 character DBF column names. The content of the file is one or\n" - " more lines of two names separated by white space and no trailing or\n" - " leading space. For example:\n" - " COLUMNNAME DBFFIELD1\n" - " AVERYLONGCOLUMNNAME DBFFIELD2\n" )); - printf(_( " -S Generate simple geometries instead of MULTI geometries.\n" )); - printf(_( " -t Force geometry to be one of '2D', '3DZ', '3DM', or '4D'\n" )); + printf(_(" -u, --unlogged Create the table as UNLOGGED.\n")); + printf( + _(" -m, --column-map Specify a file containing a set of mappings of (long) column\n" + " names to 10 character DBF column names. The content of the file is one or\n" + " more lines of two names separated by white space and no trailing or\n" + " leading space. For example:\n" + " COLUMNNAME DBFFIELD1\n" + " AVERYLONGCOLUMNNAME DBFFIELD2\n")); + printf(_(" -S, --simple-geometries Generate simple geometries instead of MULTI geometries.\n")); + printf(_(" -t, --dimensionality Force geometry to be one of '2D', '3DZ', '3DM', or '4D'\n")); - printf(_( " -w Output WKT instead of WKB. Note that this can result in\n" - " coordinate drift.\n" )); - printf(_( " -W Specify the character encoding of Shape's\n" - " attribute column. (default: \"UTF-8\")\n" )); - printf(_( " -N NULL geometries handling policy (insert*,skip,abort).\n" )); - printf(_( " -n Only import DBF file.\n" )); + printf( + _(" -w, --use-wkt Output WKT instead of WKB. Note that this can result in\n" + " coordinate drift.\n")); + printf( + _(" -W, --encoding Specify the character encoding of Shape's\n" + " attribute column. (default: \"UTF-8\")\n")); + printf(_(" -N, --null-policy NULL geometries handling policy (insert*,skip,abort).\n")); + printf(_(" -n, --dbf-only Only import DBF file.\n")); printf(_(" --drop-table Drop the target table before the selected actions.\n")); printf(_(" --create-table Create the target table.\n")); printf(_(" --if-not-exists Make active creation actions use IF NOT EXISTS.\n")); printf(_(" --load-data Load shapefile rows into the target table.\n")); - printf(_( " -T Specify the tablespace for the new table.\n" - " Note that indexes will still use the default tablespace unless the\n" - " -X flag is also used.\n")); - printf(_( " -X Specify the tablespace for the table's indexes.\n" - " This applies to the primary key, and the spatial index if\n" - " the -I flag is used.\n" )); + printf( + _(" -T, --tablespace Specify the tablespace for the new table.\n" + " Note that indexes will still use the default tablespace unless the\n" + " -X flag is also used.\n")); + printf( + _(" -X, --index-tablespace Specify the tablespace for the table's indexes.\n" + " This applies to the primary key, and the spatial index if\n" + " the -I flag is used.\n")); printf(_( " -Z Prevent tables from being analyzed.\n" )); printf(_(" --analyze Analyze the table after loading.\n")); printf(_(" --no-analyze Prevent tables from being analyzed.\n")); printf(_(" --no-transaction Execute each statement individually.\n")); - printf(_( " -? Display this help screen.\n" )); + printf(_(" -?, --help Display this help screen.\n")); printf( "\n" ); printf(_( " An argument of `--' disables further option processing.\n" )); printf(_( " (useful for unusual file names starting with '-')\n" )); @@ -184,18 +274,23 @@ main (int argc, char **argv) } if (strncmp(argv[pgis_optind], "--", 2) == 0) { - fprintf(stderr, "Unknown option: %s\n", argv[pgis_optind]); - usage(); - exit(1); + if (!consume_long_option(argc, argv, &c)) + { + fprintf(stderr, "Unknown option: %s\n", argv[pgis_optind]); + usage(); + exit(1); + } } + else + { + c = pgis_getopt(argc, argv, "-?acdeg:ikm:nps:t:uwDGIN:ST:W:X:Z"); + if (c == EOF) + break; - c = pgis_getopt(argc, argv, "-?acdeg:ikm:nps:t:uwDGIN:ST:W:X:Z"); - if (c == EOF) - break; - - // can not do this inside the switch case - if ('-' == c) - break; + // can not do this inside the switch case + if ('-' == c) + break; + } switch (c) { diff --git a/regress/loader/LongOptions.opts b/regress/loader/LongOptions.opts index dc46a9b2d..28e5ec9db 100644 --- a/regress/loader/LongOptions.opts +++ b/regress/loader/LongOptions.opts @@ -1 +1 @@ ---drop-table --create-table --load-data --create-index --if-not-exists --no-transaction --analyze +--drop-table --create-table --load-data --create-index --if-not-exists --no-transaction --analyze --srid=0 --geometry-column=the_geom --encoding=UTF-8 --null-policy=insert --dimensionality=2D --simple-geometries --force-int4 commit c222d23c27f4225b403ac19bfe53cff2c557e1a0 Author: Darafei Praliaskouski Date: Sun Jun 21 18:25:31 2026 +0400 Add long option aliases to raster2pgsql Accept GNU-style long aliases for existing raster2pgsql command-line options, including --option=value spelling for value-taking options. Keep the recent loader action long options as the canonical action names, and preserve endian selector compatibility while still emitting NDR output. Closes #4658 Closes https://github.com/postgis/postgis/pull/1029 diff --git a/NEWS b/NEWS index 20209cb38..4fb4532c8 100644 --- a/NEWS +++ b/NEWS @@ -21,10 +21,11 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * New Features * - - #1124, #2935, #4659, [loader] Rework loader arguments: shp2pgsql can + - #1124, #2935, #4658, #4659, [loader] Rework loader arguments: shp2pgsql can create UNLOGGED tables, shp2pgsql --drop-table can emit DROP TABLE before prepare output, raster2pgsql/shp2pgsql expose loader actions - as long options, and --if-not-exists makes creation actions idempotent + as long options, raster2pgsql accepts long aliases for existing + options, and --if-not-exists makes creation actions idempotent (Darafei Praliaskouski) - #4208, Add single-geometry variants of ST_MaxDistance and ST_LongestLine (Darafei Praliaskouski) diff --git a/doc/man/raster2pgsql.1 b/doc/man/raster2pgsql.1 index 17fa7194d..2789b2174 100644 --- a/doc/man/raster2pgsql.1 +++ b/doc/man/raster2pgsql.1 @@ -17,27 +17,29 @@ files. .SH "OPTIONS" .LP The commandline options are: +.LP +Long options that take values also accept the \fB\-\-option=value\fR spelling. .TP -\fB\-s\fR [<\fIFROM_SRID\fR>:]<\fISRID\fR> +\fB\-s\fR, \fB\-\-srid\fR [<\fIFROM_SRID\fR>:]<\fISRID\fR> Set the SRID field. If FROM_SRID is given, the input raster is treated as that source SRID before being transformed to SRID. If no SRID is provided, or if SRID is 0, raster metadata is used when possible. .TP -\fB\-b\fR <\fIband\fR> +\fB\-b\fR, \fB\-\-band\fR <\fIband\fR> Index, starting from 1, of the band to extract from the raster. Separate multiple band indexes with commas. Ranges can be written with a dash. If this option is omitted, all bands are extracted. .TP -\fB\-t\fR <\fItile_size\fR> +\fB\-t\fR, \fB\-\-tile\-size\fR <\fItile_size\fR> Cut each raster into tiles inserted one per table row. The tile size is written as WIDTHxHEIGHT. Use "auto" to let the loader choose a tile size from the first raster and apply it to all rasters. .TP -\fB\-P\fR +\fB\-P\fR, \fB\-\-pad\fR Pad right-most and bottom-most tiles so all tiles have the same width and height. .TP -\fB\-R\fR +\fB\-R\fR, \fB\-\-register\fR Register the raster as an out-of-db filesystem raster. Input raster paths must be absolute. .TP @@ -71,21 +73,21 @@ Create the target table. \fB\-\-load\-data\fR Load raster data into the target table. .TP -\fB\-f\fR <\fIcolumn\fR> +\fB\-f\fR, \fB\-\-raster\-column\fR <\fIcolumn\fR> Specify the name of the raster column. .TP -\fB\-F\fR +\fB\-F\fR, \fB\-\-filename\fR Add a column containing the source raster filename. .TP -\fB\-n\fR <\fIcolumn\fR> +\fB\-n\fR, \fB\-\-filename\-column\fR <\fIcolumn\fR> Specify the filename column name. This implies \-F. .TP -\fB\-l\fR <\fIoverview_factor\fR> +\fB\-l\fR, \fB\-\-overview\-factor\fR <\fIoverview_factor\fR> Create overview tables for the raster. Separate multiple factors with commas. Overview table names follow the pattern o__
. Created overviews are stored in the database and are not affected by \-R. .TP -\fB\-q\fR +\fB\-q\fR, \fB\-\-quote\fR Wrap PostgreSQL identifiers in quotes. .TP \fB\-I\fR @@ -114,48 +116,45 @@ constraints may fail if one or more input rasters violate the constraint. \fB\-\-add\-constraints\fR Set the standard raster constraints after the rasters are loaded. .TP -\fB\-x\fR +\fB\-x\fR, \fB\-\-no\-extent\fR Disable setting the max extent constraint. Only applies with \-C. .TP -\fB\-r\fR +\fB\-r\fR, \fB\-\-regular\-blocking\fR Set spatially unique and coverage tile constraints for regular blocking. Only applies with \-C. .TP -\fB\-T\fR <\fItablespace\fR> +\fB\-T\fR, \fB\-\-tablespace\fR <\fItablespace\fR> Specify the tablespace for the new table. .TP -\fB\-X\fR <\fItablespace\fR> +\fB\-X\fR, \fB\-\-index\-tablespace\fR <\fItablespace\fR> Specify the tablespace for the new table's indexes. This applies to the primary key and the spatial index when \-I is used. .TP -\fB\-N\fR <\fInodata\fR> +\fB\-N\fR, \fB\-\-nodata\fR <\fInodata\fR> NODATA value to use on bands without a NODATA value. .TP -\fB\-k\fR +\fB\-k\fR, \fB\-\-skip\-nodata\-check\fR Keep empty tiles by skipping NODATA value checks for each raster band. .TP -\fB\-E\fR <\fIendian\fR> +\fB\-E\fR, \fB\-\-endian\fR <\fIendian\fR> Control endianness of generated binary raster output. Use 0 for XDR and 1 for NDR. Only NDR is currently supported. .TP -\fB\-V\fR <\fIversion\fR> +\fB\-V\fR, \fB\-\-wkb\-version\fR <\fIversion\fR> Specify the output WKB format version. Only version 0 is currently supported. .TP -\fB\-e\fR +\fB\-e\fR, \fB\-\-no\-transaction\fR Execute each statement individually instead of wrapping the load in a transaction. .TP -\fB\-\-no\-transaction\fR -Execute statements individually, without using a transaction. -.TP -\fB\-Y\fR [<\fImax_rows_per_copy\fR>] +\fB\-Y\fR, \fB\-\-copy\fR [<\fImax_rows_per_copy\fR>] Use COPY statements instead of INSERT statements. If no row limit is provided, 50 rows are written per COPY. .TP -\fB\-G\fR +\fB\-G\fR, \fB\-\-gdal\-formats\fR Print the supported GDAL raster formats. .TP -\fB\-?\fR +\fB\-?\fR, \fB\-\-help\fR Display version and usage information. .SH "EXAMPLES" diff --git a/doc/using_raster_dataman.xml b/doc/using_raster_dataman.xml index a686de06e..97b60ab87 100644 --- a/doc/using_raster_dataman.xml +++ b/doc/using_raster_dataman.xml @@ -73,9 +73,13 @@ Available GDAL raster formats:
raster2pgsql options + + Long options that take values also accept the spelling. + + - + Display help screen. Help will also display if you don't pass in any arguments. @@ -84,7 +88,7 @@ Available GDAL raster formats: - + Print the supported raster formats. @@ -177,7 +181,7 @@ Available GDAL raster formats: - + Apply raster constraints -- srid, pixelsize etc. to ensure raster is properly registered in raster_columns view. @@ -185,18 +189,18 @@ Available GDAL raster formats: - + - Disable setting the max extent constraint. Only applied if -C flag is also used. + Disable setting the max extent constraint. Only applied if -C or --add-constraints is also used. - + - Set the constraints (spatially unique and coverage tile) for regular blocking. Only applied if -C flag is also used. + Set the constraints (spatially unique and coverage tile) for regular blocking. Only applied if -C or --add-constraints is also used. @@ -211,7 +215,7 @@ Available GDAL raster formats: - + Assign the output raster to the specified SRID. When FROM_SRID is also provided, raster2pgsql marks the input raster with FROM_SRID and emits SQL that reprojects the raster to the target SRID. If the source SRID is omitted or is zero, the raster metadata will be checked to determine an appropriate source SRID. Reprojection cannot be used with copy mode. @@ -220,7 +224,7 @@ Available GDAL raster formats: - + Index (1-based) of band to extract from raster. For more than one band index, separate with comma (,). If unspecified, @@ -230,7 +234,7 @@ Available GDAL raster formats: - + Cut raster into tiles to be inserted one per table row. TILE_SIZE is expressed as WIDTHxHEIGHT or set to the value "auto" to allow the loader to compute an appropriate tile size using the first raster and applied to all rasters. @@ -239,7 +243,7 @@ Available GDAL raster formats: - + Pad right-most and bottom-most tiles to guarantee that all tiles @@ -259,7 +263,7 @@ Available GDAL raster formats: - + Create overview of the raster. For more than one factor, separate with comma(,). Overview table name follows the pattern o_overview factor_table, where overview factor is a placeholder for numerical overview factor and table is replaced with the base table name. Created overview is @@ -268,7 +272,7 @@ Available GDAL raster formats: - + NODATA value to use on bands without a NODATA value. @@ -287,7 +291,7 @@ Available GDAL raster formats: - + Specify name of destination raster column, default is 'rast' @@ -295,21 +299,21 @@ Available GDAL raster formats: - + Add a column with the name of the file - + Specify the name of the filename column. Implies -F. - + Wrap PostgreSQL identifiers in quotes. @@ -348,7 +352,7 @@ Available GDAL raster formats: - + Keeps empty tiles and skips NODATA value checks for each raster band. @@ -359,7 +363,7 @@ Available GDAL raster formats: - + Specify the tablespace for the new table. @@ -370,7 +374,7 @@ Available GDAL raster formats: - + Specify the tablespace for the table's new index. @@ -380,8 +384,8 @@ Available GDAL raster formats: - - + + Use copy statements instead of insert statements. Optionally specify max_rows_per_copy; @@ -395,17 +399,17 @@ Available GDAL raster formats: - + Execute each statement individually, do not use a transaction. - + Control endianness of generated binary output of raster; specify 0 for XDR and 1 for NDR (default); only NDR output is supported now - + Specify version of output format. Default is 0. Only 0 is supported at this time. diff --git a/raster/loader/raster2pgsql.c b/raster/loader/raster2pgsql.c index 450474eb6..442511ae8 100644 --- a/raster/loader/raster2pgsql.c +++ b/raster/loader/raster2pgsql.c @@ -336,6 +336,33 @@ chartrim(const char *input, char *remove) { return rtn; } +static int +option_matches(const char *arg, const char *shortopt, const char *longopt) +{ + size_t longopt_len; + + if (CSEQUAL(arg, shortopt) || CSEQUAL(arg, longopt)) + return 1; + + longopt_len = strlen(longopt); + return strncmp(arg, longopt, longopt_len) == 0 && arg[longopt_len] == '='; +} + +static char * +option_value(int argc, char **argv, int *argit, const char *longopt) +{ + const size_t longopt_len = strlen(longopt); + char *arg = argv[*argit]; + + if (strncmp(arg, longopt, longopt_len) == 0 && arg[longopt_len] == '=') + return arg + longopt_len + 1; + + if (*argit < argc - 1) + return argv[++(*argit)]; + + return NULL; +} + static void usage() { printf(_("RELEASE: %s GDAL_VERSION=%d (%s)\n"), POSTGIS_LIB_VERSION, POSTGIS_GDAL_VERSION, xstr(POSTGIS_REVISION)); @@ -343,34 +370,31 @@ usage() { _("USAGE: raster2pgsql [] [ [ ...]] [[.]
]\n" " Multiple rasters can also be specified using wildcards (*,?).\n" "\n" - "OPTIONS:\n")); - printf(_(" -s [:] Set the SRID field. Defaults to %d.\n" + "OPTIONS:\n" + " Long options with values also accept --option=value.\n")); + printf(_(" -s, --srid [:] Set the SRID field. Defaults to %d.\n" " Optionally reprojects from given SRID (cannot be used with -Y).\n" " Raster's metadata will be checked to determine an appropriate SRID.\n" " Metadata lookup is also used when %d is provided as from or target.\n"), SRID_UNKNOWN, SRID_UNKNOWN); - printf(_( - " -b Index (1-based) of band to extract from raster. For more\n" - " than one band index, separate with comma (,). Ranges can be\n" - " defined by separating with dash (-). If unspecified, all bands\n" - " of raster will be extracted.\n" - )); - printf(_( - " -t Cut raster into tiles to be inserted one per\n" - " table row. is expressed as WIDTHxHEIGHT.\n" - " can also be \"auto\" to allow the loader to compute\n" - " an appropriate tile size using the first raster and applied to\n" - " all rasters.\n" - )); - printf(_( - " -P Pad right-most and bottom-most tiles to guarantee that all tiles\n" - " have the same width and height.\n" - )); - printf(_( - " -R Register the raster as an out-of-db (filesystem) raster. Provided\n" - " raster should have absolute path to the file\n" - )); + printf( + _(" -b, --band Index (1-based) of band to extract from raster. For more\n" + " than one band index, separate with comma (,). Ranges can be\n" + " defined by separating with dash (-). If unspecified, all bands\n" + " of raster will be extracted.\n")); + printf( + _(" -t, --tile-size Cut raster into tiles to be inserted one per\n" + " table row. is expressed as WIDTHxHEIGHT.\n" + " can also be \"auto\" to allow the loader to compute\n" + " an appropriate tile size using the first raster and applied to\n" + " all rasters.\n")); + printf( + _(" -P, --pad Pad right-most and bottom-most tiles to guarantee that all tiles\n" + " have the same width and height.\n")); + printf( + _(" -R, --register Register the raster as an out-of-db (filesystem) raster. Provided\n" + " raster should have absolute path to the file\n")); printf( _(" (-d|a|c|p) These are mutually exclusive options:\n" " -d Drops the table, then recreates it and populates\n" @@ -394,28 +418,20 @@ usage() { " at the end of this raster2pgsql run. With repeated -a append\n" " runs, create the index on the final run or after loading; add\n" " --if-not-exists to make reruns tolerate an existing index.\n")); - printf(_( - " -f Specify the name of the raster column\n" - )); - printf(_( - " -F Add a column with the filename of the raster.\n" - )); - printf(_( - " -n Specify the name of the filename column. Implies -F.\n" - )); - printf(_( - " -l Create overview of the raster. For more than\n" - " one factor, separate with comma(,). Overview table name follows\n" - " the pattern o__
. Created overview is\n" - " stored in the database and is not affected by -R.\n" - )); - printf(_( - " -q Wrap PostgreSQL identifiers in quotes.\n" - )); + printf(_(" -f, --raster-column Specify the name of the raster column\n")); + printf(_(" -F, --filename Add a column with the filename of the raster.\n")); + printf(_(" -n, --filename-column Specify the name of the filename column. Implies -F.\n")); + printf( + _(" -l, --overview-factor Create overview of the raster. For more than\n" + " one factor, separate with comma(,). Overview table name follows\n" + " the pattern o__
. Created overview is\n" + " stored in the database and is not affected by -R.\n")); + printf(_(" -q, --quote Wrap PostgreSQL identifiers in quotes.\n")); printf(_(" -I Alias for --create-index.\n")); printf( _(" --add-constraints Set the standard set of constraints on the\n" - " raster column after the rasters are loaded.\n" + " raster column after the rasters are loaded. Some constraints may\n" + " fail if one or more rasters violate the constraint.\n" " --vacuum Run VACUUM on the table of the raster column.\n" " --analyze Run ANALYZE on the table of the raster column.\n" " --no-transaction Execute statements without a transaction.\n")); @@ -423,54 +439,37 @@ usage() { " -M Run VACUUM ANALYZE on the table of the raster column. Most\n" " useful when appending raster to existing table with -a.\n" )); - printf(_( - " -C Set the standard set of constraints on the raster\n" - " column after the rasters are loaded. Some constraints may fail\n" - " if one or more rasters violate the constraint.\n" - " -x Disable setting the max extent constraint. Only applied if\n" - " -C flag is also used.\n" - " -r Set the constraints (spatially unique and coverage tile) for\n" - " regular blocking. Only applied if -C flag is also used.\n" - )); - printf(_( - " -T Specify the tablespace for the new table.\n" - " Note that indices (including the primary key) will still use\n" - " the default tablespace unless the -X flag is also used.\n" - )); - printf(_( - " -X Specify the tablespace for the table's new index.\n" - " This applies to the primary key and the spatial index if\n" - " the -I flag is used.\n" - )); - printf(_( - " -N NODATA value to use on bands without a NODATA value.\n" - )); - printf(_( - " -k Keep empty tiles by skipping NODATA value checks for each raster band. \n" - )); - printf(_( - " -E Control endianness of generated binary output of\n" - " raster. Use 0 for XDR and 1 for NDR (default). Only NDR\n" - " is supported at this time.\n" - )); - printf(_( - " -V Specify version of output WKB format. Default\n" - " is 0. Only 0 is supported at this time.\n" - )); - printf(_( - " -e Execute each statement individually, do not use a transaction.\n" - )); - printf(_( - " -Y Use COPY statements instead of INSERT statements. \n" - " Optionally specify ; default 50 when not specified. \n" - )); + printf( + _(" -C Alias for --add-constraints.\n" + " -x, --no-extent Disable setting the max extent constraint. Only applied if\n" + " -C/--add-constraints is also used.\n" + " -r, --regular-blocking Set the constraints (spatially unique and coverage tile) for\n" + " regular blocking. Only applied if -C/--add-constraints is also used.\n")); + printf( + _(" -T, --tablespace Specify the tablespace for the new table.\n" + " Note that indices (including the primary key) will still use\n" + " the default tablespace unless the -X flag is also used.\n")); + printf( + _(" -X, --index-tablespace Specify the tablespace for the table's new index.\n" + " This applies to the primary key and the spatial index if\n" + " the -I flag is used.\n")); + printf(_(" -N, --nodata NODATA value to use on bands without a NODATA value.\n")); + printf( + _(" -k, --skip-nodata-check Keep empty tiles by skipping NODATA value checks for each raster band. \n")); + printf( + _(" -E, --endian Control endianness of generated binary output of\n" + " raster. Use 0 for XDR and 1 for NDR (default). Only NDR\n" + " is supported at this time.\n")); + printf( + _(" -V, --wkb-version Specify version of output WKB format. Default\n" + " is 0. Only 0 is supported at this time.\n")); + printf(_(" -e, --no-transaction Execute each statement individually, do not use a transaction.\n")); + printf( + _(" -Y, --copy [] Use COPY statements instead of INSERT statements. \n" + " Optionally specify ; default 50 when not specified. \n")); - printf(_( - " -G Print the supported GDAL raster formats.\n" - )); - printf(_( - " -? Display this help screen.\n" - )); + printf(_(" -G, --gdal-formats Print the supported GDAL raster formats.\n")); + printf(_(" -?, --help Display this help screen.\n")); } static void @@ -2450,8 +2449,9 @@ main(int argc, char **argv) { char *optarg, *ptr; /* srid */ - if (CSEQUAL(argv[argit], "-s") && argit < argc - 1) { - optarg = argv[++argit]; + if (option_matches(argv[argit], "-s", "--srid") && + (optarg = option_value(argc, argv, &argit, "--srid")) != NULL) + { ptr = strchr(optarg, ':'); if (ptr) { *ptr++ = '\0'; @@ -2462,8 +2462,10 @@ main(int argc, char **argv) { } } /* band index */ - else if (CSEQUAL(argv[argit], "-b") && argit < argc - 1) { - elements = strsplit(argv[++argit], ",", &n); + else if (option_matches(argv[argit], "-b", "--band") && + (optarg = option_value(argc, argv, &argit, "--band")) != NULL) + { + elements = strsplit(optarg, ",", &n); if (n < 1) { rterror(_("Could not process -b")); rtdealloc_config(config); @@ -2556,13 +2558,16 @@ main(int argc, char **argv) { } } /* tile size */ - else if (CSEQUAL(argv[argit], "-t") && argit < argc - 1) { - if (CSEQUAL(argv[++argit], "auto")) { + else if (option_matches(argv[argit], "-t", "--tile-size") && + (optarg = option_value(argc, argv, &argit, "--tile-size")) != NULL) + { + if (CSEQUAL(optarg, "auto")) + { config->tile_size[0] = -1; config->tile_size[1] = -1; } else { - elements = strsplit(argv[argit], "x", &n); + elements = strsplit(optarg, "x", &n); if (n != 2) { rterror(_("Could not process -t")); rtdealloc_config(config); @@ -2589,11 +2594,13 @@ main(int argc, char **argv) { } } /* pad tiles */ - else if (CSEQUAL(argv[argit], "-P")) { + else if (CSEQUAL(argv[argit], "-P") || CSEQUAL(argv[argit], "--pad")) + { config->pad_tile = 1; } /* out-of-db raster */ - else if (CSEQUAL(argv[argit], "-R")) { + else if (CSEQUAL(argv[argit], "-R") || CSEQUAL(argv[argit], "--register")) + { config->outdb = 1; } /* drop table and recreate */ @@ -2640,35 +2647,42 @@ main(int argc, char **argv) { config->actions.load_data_set = 1; } /* raster column name */ - else if (CSEQUAL(argv[argit], "-f") && argit < argc - 1) { - const size_t len = (strlen(argv[++argit]) + 1); + else if (option_matches(argv[argit], "-f", "--raster-column") && + (optarg = option_value(argc, argv, &argit, "--raster-column")) != NULL) + { + const size_t len = (strlen(optarg) + 1); config->raster_column = rtalloc(sizeof(char) * len); if (config->raster_column == NULL) { rterror(_("Could not allocate memory for storing raster column name")); rtdealloc_config(config); exit(1); } - strncpy(config->raster_column, argv[argit], len); + strncpy(config->raster_column, optarg, len); } /* filename column */ - else if (CSEQUAL(argv[argit], "-F")) { + else if (CSEQUAL(argv[argit], "-F") || CSEQUAL(argv[argit], "--filename")) + { config->file_column = 1; } /* filename column name */ - else if (CSEQUAL(argv[argit], "-n") && argit < argc - 1) { - const size_t len = (strlen(argv[++argit]) + 1); + else if (option_matches(argv[argit], "-n", "--filename-column") && + (optarg = option_value(argc, argv, &argit, "--filename-column")) != NULL) + { + const size_t len = (strlen(optarg) + 1); config->file_column_name = rtalloc(sizeof(char) * len); if (config->file_column_name == NULL) { rterror(_("Could not allocate memory for storing filename column name")); rtdealloc_config(config); exit(1); } - strncpy(config->file_column_name, argv[argit], len); + strncpy(config->file_column_name, optarg, len); config->file_column = 1; } /* overview factors */ - else if (CSEQUAL(argv[argit], "-l") && argit < argc - 1) { - elements = strsplit(argv[++argit], ",", &n); + else if (option_matches(argv[argit], "-l", "--overview-factor") && + (optarg = option_value(argc, argv, &argit, "--overview-factor")) != NULL) + { + elements = strsplit(optarg, ",", &n); if (n < 1) { rterror(_("Could not process -l")); rtdealloc_config(config); @@ -2701,7 +2715,8 @@ main(int argc, char **argv) { } } /* quote identifiers */ - else if (CSEQUAL(argv[argit], "-q")) { + else if (CSEQUAL(argv[argit], "-q") || CSEQUAL(argv[argit], "--quote")) + { config->quoteident = 1; } /* create index */ @@ -2744,52 +2759,80 @@ main(int argc, char **argv) { config->actions.add_constraints = 1; } /* disable extent constraint */ - else if (CSEQUAL(argv[argit], "-x")) { + else if (CSEQUAL(argv[argit], "-x") || CSEQUAL(argv[argit], "--no-extent")) + { config->max_extent = 0; } /* enable regular_blocking */ - else if (CSEQUAL(argv[argit], "-r")) { + else if (CSEQUAL(argv[argit], "-r") || CSEQUAL(argv[argit], "--regular-blocking")) + { config->regular_blocking = 1; } /* tablespace of new table */ - else if (CSEQUAL(argv[argit], "-T") && argit < argc - 1) { - const size_t len = (strlen(argv[++argit]) + 1); + else if (option_matches(argv[argit], "-T", "--tablespace") && + (optarg = option_value(argc, argv, &argit, "--tablespace")) != NULL) + { + const size_t len = (strlen(optarg) + 1); config->tablespace = rtalloc(len); if (config->tablespace == NULL) { rterror(_("Could not allocate memory for storing tablespace of new table")); rtdealloc_config(config); exit(1); } - strncpy(config->tablespace, argv[argit], len); + strncpy(config->tablespace, optarg, len); } /* tablespace of new index */ - else if (CSEQUAL(argv[argit], "-X") && argit < argc - 1) { - const size_t len = (strlen(argv[++argit]) + 1); + else if (option_matches(argv[argit], "-X", "--index-tablespace") && + (optarg = option_value(argc, argv, &argit, "--index-tablespace")) != NULL) + { + const size_t len = (strlen(optarg) + 1); config->idx_tablespace = rtalloc(len); if (config->idx_tablespace == NULL) { rterror(_("Could not allocate memory for storing tablespace of new indices")); rtdealloc_config(config); exit(1); } - strncpy(config->idx_tablespace, argv[argit], len); + strncpy(config->idx_tablespace, optarg, len); } /* nodata value */ - else if (CSEQUAL(argv[argit], "-N") && argit < argc - 1) { + else if (option_matches(argv[argit], "-N", "--nodata") && + (optarg = option_value(argc, argv, &argit, "--nodata")) != NULL) + { config->hasnodata = 1; - config->nodataval = atof(argv[++argit]); + config->nodataval = atof(optarg); } /* skip NODATA value check for bands */ - else if (CSEQUAL(argv[argit], "-k")) { + else if (CSEQUAL(argv[argit], "-k") || CSEQUAL(argv[argit], "--skip-nodata-check")) + { config->skip_nodataval_check = 1; } /* endianness */ - else if (CSEQUAL(argv[argit], "-E") && argit < argc - 1) { - config->endian = atoi(argv[++argit]); + else if (option_matches(argv[argit], "-E", "--endian") && + (optarg = option_value(argc, argv, &argit, "--endian")) != NULL) + { + char *endptr = NULL; + const long endian = strtol(optarg, &endptr, 10); + if (*optarg == '\0' || *endptr != '\0' || (endian != 0 && endian != 1)) + { + rterror(_( + "Endian value must be 0 (XDR) or 1 (NDR); only NDR output is supported at this time")); + rtdealloc_config(config); + exit(1); + } config->endian = 1; } /* version */ - else if (CSEQUAL(argv[argit], "-V") && argit < argc - 1) { - config->version = atoi(argv[++argit]); + else if (option_matches(argv[argit], "-V", "--wkb-version") && + (optarg = option_value(argc, argv, &argit, "--wkb-version")) != NULL) + { + char *endptr = NULL; + const long version = strtol(optarg, &endptr, 10); + if (*optarg == '\0' || *endptr != '\0' || version != 0) + { + rterror(_("Only WKB version 0 is supported at this time")); + rtdealloc_config(config); + exit(1); + } config->version = 0; } /* transaction */ @@ -2807,10 +2850,25 @@ main(int argc, char **argv) { exit(1); } /* COPY statements */ - else if (CSEQUAL(argv[argit], "-Y")) { + else if (option_matches(argv[argit], "-Y", "--copy")) + { config->copy_statements = 1; + if (strncmp(argv[argit], "--copy=", strlen("--copy=")) == 0) + { + char *endptr = NULL; + const long max_tiles_per_copy = strtol(argv[argit] + strlen("--copy="), &endptr, 10); + optarg = argv[argit] + strlen("--copy="); + if (*optarg == '\0' || *endptr != '\0' || max_tiles_per_copy < 1) + { + rterror(_("--copy row limit must be greater than 0")); + rtdealloc_config(config); + exit(1); + } + config->max_tiles_per_copy = (int)max_tiles_per_copy; + } /* max tiles per copy */ - if ( argit < argc - 1) { + else if (argit < argc - 1) + { optarg = argv[argit + 1]; if (atoi(optarg) > 0 ) { config->max_tiles_per_copy = atoi(optarg); @@ -2819,9 +2877,9 @@ main(int argc, char **argv) { } } - /* GDAL formats */ - else if (CSEQUAL(argv[argit], "-G")) { + else if (CSEQUAL(argv[argit], "-G") || CSEQUAL(argv[argit], "--gdal-formats")) + { uint32_t drv_count = 0; rt_gdaldriver drv_set = rt_raster_gdal_drivers(&drv_count, 0); if (drv_set == NULL || !drv_count) { @@ -2843,7 +2901,8 @@ main(int argc, char **argv) { exit(0); } /* help */ - else if (CSEQUAL(argv[argit], "-?")) { + else if (CSEQUAL(argv[argit], "-?") || CSEQUAL(argv[argit], "--help")) + { usage(); rtdealloc_config(config); exit(0); diff --git a/raster/test/regress/loader/LongMaintenance.opts b/raster/test/regress/loader/LongMaintenance.opts index e63937728..4841db97c 100644 --- a/raster/test/regress/loader/LongMaintenance.opts +++ b/raster/test/regress/loader/LongMaintenance.opts @@ -1 +1 @@ ---add-constraints --vacuum --analyze +--add-constraints --vacuum --analyze --copy=20 --srid=0 --band=1-3 --tile-size=90x50 --raster-column=rast diff --git a/raster/test/regress/loader/LongMaintenance.select.sql b/raster/test/regress/loader/LongMaintenance.select.sql index 18027ebe8..efe793db4 100644 --- a/raster/test/regress/loader/LongMaintenance.select.sql +++ b/raster/test/regress/loader/LongMaintenance.select.sql @@ -1,5 +1,7 @@ +-- This test combines long action options with GNU-style long value options. -- --add-constraints should register the loaded raster in raster_columns --- with the same metadata that the existing short -C test expects. +-- with the same metadata that the existing short -C test expects, while the +-- 90x50 tile and sampled band values prove that --tile-size and --band parsed. SELECT srid, scale_x::numeric(16, 10), scale_y::numeric(16, 10), blocksize_x, blocksize_y, same_alignment, regular_blocking, num_bands, pixel_types, nodata_values::numeric(16,10)[], out_db, ST_AsEWKT(extent) FROM raster_columns WHERE r_table_name = 'loadedrast' AND r_raster_column = 'rast'; -- The raster data should survive the long maintenance path unchanged. ----------------------------------------------------------------------- Summary of changes: NEWS | 5 +- doc/man/raster2pgsql.1 | 49 ++-- doc/man/shp2pgsql.1 | 43 +-- doc/using_raster_dataman.xml | 54 ++-- loader/shp2pgsql-cli.c | 183 +++++++++--- raster/loader/raster2pgsql.c | 315 ++++++++++++--------- raster/test/regress/loader/LongMaintenance.opts | 2 +- .../test/regress/loader/LongMaintenance.select.sql | 4 +- regress/loader/LongOptions.opts | 2 +- 9 files changed, 411 insertions(+), 246 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 09:56:20 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 16:56:20 -0000 Subject: [PostGIS] #4658: add --long-options to raster2pgsql In-Reply-To: <054.69f8cb697ca25d558fde3c5d068ea926@osgeo.org> References: <054.69f8cb697ca25d558fde3c5d068ea926@osgeo.org> Message-ID: <069.e7dee0eb4523437eb9a3c39613f1044b@osgeo.org> #4658: add --long-options to raster2pgsql ---------------------------+----------------------------- Reporter: andrewharvey | Owner: dustymugs Type: enhancement | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: raster | Version: 2.5.x -- EOL Resolution: fixed | Keywords: ---------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"c222d23c27f4225b403ac19bfe53cff2c557e1a0/git" c222d23/git]: {{{#!CommitTicketReference repository="git" revision="c222d23c27f4225b403ac19bfe53cff2c557e1a0" Add long option aliases to raster2pgsql Accept GNU-style long aliases for existing raster2pgsql command-line options, including --option=value spelling for value-taking options. Keep the recent loader action long options as the canonical action names, and preserve endian selector compatibility while still emitting NDR output. Closes #4658 Closes https://github.com/postgis/postgis/pull/1029 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Sun Jun 21 09:56:20 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 16:56:20 -0000 Subject: [PostGIS] #4658: add --long-options to raster2pgsql In-Reply-To: <054.69f8cb697ca25d558fde3c5d068ea926@osgeo.org> References: <054.69f8cb697ca25d558fde3c5d068ea926@osgeo.org> Message-ID: <069.dd3ee8458979f341eb6b038396d2debb@osgeo.org> #4658: add --long-options to raster2pgsql ---------------------------+----------------------------- Reporter: andrewharvey | Owner: dustymugs Type: enhancement | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: raster | Version: 2.5.x -- EOL Resolution: fixed | Keywords: ---------------------------+----------------------------- Comment (by Darafei Praliaskouski ): In [changeset:"1c8bb486ca51d64a9cc767c0a2a487c2275be33b/git" 1c8bb48/git]: {{{#!CommitTicketReference repository="git" revision="1c8bb486ca51d64a9cc767c0a2a487c2275be33b" Add long option aliases to shp2pgsql Accept GNU-style long aliases for existing shp2pgsql command-line options, including --option=value spelling for value-taking options. Reuse the existing short-option switch so the loader action long options remain the canonical action vocabulary. References #4658 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 10:01:31 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 10:01:31 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-646-g2774c1f8d Message-ID: <20260621170131.DEFA61B12CC@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 2774c1f8dc0960efaf1c23cf2f514f11cff8adef (commit) from 1c8bb486ca51d64a9cc767c0a2a487c2275be33b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 2774c1f8dc0960efaf1c23cf2f514f11cff8adef Author: Darafei Praliaskouski Date: Sun Jun 21 21:00:22 2026 +0400 doc: clarify repeated ring point validity Closes #3425 Closes https://github.com/postgis/postgis/pull/1017 diff --git a/doc/using_postgis_dataman.xml b/doc/using_postgis_dataman.xml index be8c75391..d7ed22913 100644 --- a/doc/using_postgis_dataman.xml +++ b/doc/using_postgis_dataman.xml @@ -1090,6 +1090,13 @@ SELECT + + Consecutive repeated points in a polygon boundary ring are treated as + redundant vertices, and do not make the polygon invalid. Repeated points + that cause the boundary to self-intersect, self-touch, or collapse + still violate the validity rules. + + ----------------------------------------------------------------------- Summary of changes: doc/using_postgis_dataman.xml | 7 +++++++ 1 file changed, 7 insertions(+) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 10:01:33 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 17:01:33 -0000 Subject: [PostGIS] #3425: Clarify PostGIS handling of repeated points wrt validity in docs In-Reply-To: <049.27893d3152c059cac1666ee83b62d99a@osgeo.org> References: <049.27893d3152c059cac1666ee83b62d99a@osgeo.org> Message-ID: <064.06ffd3f2a254c28a47499a4e88181eec@osgeo.org> #3425: Clarify PostGIS handling of repeated points wrt validity in docs ----------------------------+------------------------------------------ Reporter: dbaston | Owner: Darafei Praliaskouski Type: enhancement | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: documentation | Version: master Resolution: fixed | Keywords: ----------------------------+------------------------------------------ Changes (by Darafei Praliaskouski ): * owner: (none) => Darafei Praliaskouski * resolution: => fixed * status: new => closed Comment: In [changeset:"2774c1f8dc0960efaf1c23cf2f514f11cff8adef/git" 2774c1f/git]: {{{#!CommitTicketReference repository="git" revision="2774c1f8dc0960efaf1c23cf2f514f11cff8adef" doc: clarify repeated ring point validity Closes #3425 Closes https://github.com/postgis/postgis/pull/1017 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 10:43:45 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 10:43:45 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-647-ga0b3925cf Message-ID: <20260621174345.CB6DC1B2417@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via a0b3925cf59cea943ac9bd1d2130692a559ff64f (commit) from 2774c1f8dc0960efaf1c23cf2f514f11cff8adef (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a0b3925cf59cea943ac9bd1d2130692a559ff64f Author: Darafei Praliaskouski Date: Sun Jun 21 21:06:58 2026 +0400 Reuse source overviews in raster2pgsql When raster2pgsql builds overview tables with -l, reuse a GDAL source overview whose dimensions match the requested output overview level for every selected band. Fall back to the existing generated overview path when any band has no matching source overview. Includes a loader regression whose source GeoTIFF carries an averaged 2x overview, so expected output distinguishes source-overview reuse from nearest-neighbor regeneration. Closes #2137 Closes https://github.com/postgis/postgis/pull/1092 diff --git a/NEWS b/NEWS index 199261ee1..d0f6e212d 100644 --- a/NEWS +++ b/NEWS @@ -74,6 +74,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed - #3743, #4385, [raster loader] Document raster2pgsql -s FROM_SRID:SRID reprojection support and clarify index creation timing for append loads (Darafei Praliaskouski) + - #2137, [raster] Reuse matching source raster overviews in raster2pgsql -l + (Darafei Praliaskouski) - #4749, Use point-in-polygon predicate fast paths for point-only GeometryCollections (Darafei Praliaskouski) - #5532, Validate the manual against DocBook XMLSchema in check-xml diff --git a/doc/man/raster2pgsql.1 b/doc/man/raster2pgsql.1 index 2789b2174..2b84aab44 100644 --- a/doc/man/raster2pgsql.1 +++ b/doc/man/raster2pgsql.1 @@ -85,7 +85,8 @@ Specify the filename column name. This implies \-F. \fB\-l\fR, \fB\-\-overview\-factor\fR <\fIoverview_factor\fR> Create overview tables for the raster. Separate multiple factors with commas. Overview table names follow the pattern o__
. Created -overviews are stored in the database and are not affected by \-R. +overviews are stored in the database and are not affected by \-R. If a source +raster already has an overview with matching dimensions, that overview is reused. .TP \fB\-q\fR, \fB\-\-quote\fR Wrap PostgreSQL identifiers in quotes. diff --git a/doc/using_raster_dataman.xml b/doc/using_raster_dataman.xml index 97b60ab87..5ef7dd89b 100644 --- a/doc/using_raster_dataman.xml +++ b/doc/using_raster_dataman.xml @@ -266,7 +266,7 @@ Available GDAL raster formats: Create overview of the raster. For more than one factor, separate with comma(,). Overview table name follows - the pattern o_overview factor_table, where overview factor is a placeholder for numerical overview factor and table is replaced with the base table name. Created overview is + the pattern o_overview factor_table, where overview factor is a placeholder for numerical overview factor and table is replaced with the base table name. If a source raster already has an overview with matching dimensions, that overview is reused. Created overview is stored in the database and is not affected by -R. Note that your generated sql file will contain both the main table and overview tables. diff --git a/raster/loader/raster2pgsql.c b/raster/loader/raster2pgsql.c index 442511ae8..5551c2f5b 100644 --- a/raster/loader/raster2pgsql.c +++ b/raster/loader/raster2pgsql.c @@ -1439,6 +1439,47 @@ add_overview_constraints( return 1; } +static GDALRasterBandH +get_matching_overview_band(GDALRasterBandH hbandSrc, const int dimOv[2]) +{ + int ovcount = GDALGetOverviewCount(hbandSrc); + int i = 0; + + for (i = 0; i < ovcount; i++) + { + GDALRasterBandH hbandOv = GDALGetOverview(hbandSrc, i); + + if (hbandOv != NULL && GDALGetRasterBandXSize(hbandOv) == dimOv[0] && + GDALGetRasterBandYSize(hbandOv) == dimOv[1]) + { + return hbandOv; + } + } + + return NULL; +} + +static int +source_has_matching_overviews(GDALDatasetH hdsSrc, RASTERINFO *info, const int dimOv[2]) +{ + uint32_t j = 0; + + /* + * Reuse source overviews only when every selected band has an overview + * with the exact dimensions raster2pgsql will load. Mixed source/generated + * bands would make a single output overview depend on two resampling paths. + */ + for (j = 0; j < info->nband_count; j++) + { + GDALRasterBandH hbandSrc = GDALGetRasterBand(hdsSrc, info->nband[j]); + + if (hbandSrc == NULL || get_matching_overview_band(hbandSrc, dimOv) == NULL) + return LW_FALSE; + } + + return LW_TRUE; +} + static int build_overview(int idx, RTLOADERCFG *config, RASTERINFO *info, uint32_t ovx, STRINGBUFFER *tileset, STRINGBUFFER *buffer) { GDALDatasetH hdsSrc; @@ -1450,6 +1491,7 @@ build_overview(int idx, RTLOADERCFG *config, RASTERINFO *info, uint32_t ovx, STR uint32_t j = 0; int factor; const char *ovtable = NULL; + int use_source_overview = LW_FALSE; VRTDatasetH hdsDst; VRTSourcedRasterBandH hbandDst; @@ -1488,6 +1530,12 @@ build_overview(int idx, RTLOADERCFG *config, RASTERINFO *info, uint32_t ovx, STR dimOv[0] = (int) (info->dim[0] + (factor / 2)) / factor; dimOv[1] = (int) (info->dim[1] + (factor / 2)) / factor; + /* + * Match by dimensions instead of overview index or nominal factor. GDAL + * datasets can carry differently ordered overview levels, while the loader + * needs the level that exactly matches the target overview table size. + */ + use_source_overview = source_has_matching_overviews(hdsSrc, info, dimOv); /* create VRT dataset */ hdsOv = VRTCreate(dimOv[0], dimOv[1]); @@ -1504,20 +1552,39 @@ build_overview(int idx, RTLOADERCFG *config, RASTERINFO *info, uint32_t ovx, STR /* add bands as simple sources */ for (j = 0; j < info->nband_count; j++) { + GDALRasterBandH hbandSrc = GDALGetRasterBand(hdsSrc, info->nband[j]); + int sourceDim[2] = {info->dim[0], info->dim[1]}; + + if (use_source_overview) + { + /* + * The selected source is already reduced to dimOv, so VRT should + * copy it 1:1. Otherwise it reads the full-resolution band and + * resamples down into the target overview dimensions. + */ + hbandSrc = get_matching_overview_band(hbandSrc, dimOv); + sourceDim[0] = dimOv[0]; + sourceDim[1] = dimOv[1]; + } + GDALAddBand(hdsOv, info->gdalbandtype[j], NULL); hbandOv = (VRTSourcedRasterBandH) GDALGetRasterBand(hdsOv, j + 1); if (info->hasnodata[j]) GDALSetRasterNoDataValue(hbandOv, info->nodataval[j]); - VRTAddSimpleSource( - hbandOv, GDALGetRasterBand(hdsSrc, info->nband[j]), - 0, 0, - info->dim[0], info->dim[1], - 0, 0, - dimOv[0], dimOv[1], - "near", VRT_NODATA_UNSET - ); + VRTAddSimpleSource(hbandOv, + hbandSrc, + 0, + 0, + sourceDim[0], + sourceDim[1], + 0, + 0, + dimOv[0], + dimOv[1], + "near", + VRT_NODATA_UNSET); } /* make sure VRT reflects all changes */ diff --git a/raster/test/regress/loader/SourceOverview-post.pl b/raster/test/regress/loader/SourceOverview-post.pl new file mode 100644 index 000000000..dc1a681da --- /dev/null +++ b/raster/test/regress/loader/SourceOverview-post.pl @@ -0,0 +1,3 @@ +use File::Basename qw(dirname); + +unlink dirname($TEST) . '/SourceOverview-generated.tif'; diff --git a/raster/test/regress/loader/SourceOverview-post.sql b/raster/test/regress/loader/SourceOverview-post.sql new file mode 100644 index 000000000..0ea666a10 --- /dev/null +++ b/raster/test/regress/loader/SourceOverview-post.sql @@ -0,0 +1 @@ +DROP TABLE o_2_loadedrast; diff --git a/raster/test/regress/loader/SourceOverview-pre.pl b/raster/test/regress/loader/SourceOverview-pre.pl new file mode 100644 index 000000000..872c55207 --- /dev/null +++ b/raster/test/regress/loader/SourceOverview-pre.pl @@ -0,0 +1,31 @@ +use File::Basename qw(dirname); + +my $dir = dirname($TEST); +my $asc = "$dir/SourceOverview.asc"; +my $tif = "$dir/SourceOverview-generated.tif"; + +# The source raster values are deliberately sequential so the averaged GDAL +# overview has different corner pixels than a nearest-neighbor overview generated +# by raster2pgsql from the full-resolution band. +open(my $fh, '>', $asc) or die "Could not create $asc: $!"; +print $fh "ncols 8\n"; +print $fh "nrows 8\n"; +print $fh "xllcorner 0\n"; +print $fh "yllcorner 0\n"; +print $fh "cellsize 1\n"; +print $fh "NODATA_value -9999\n"; +for my $y (0..7) { + print $fh join(' ', map { $y * 8 + $_ } 1..8), "\n"; +} +close($fh); + +system( + 'gdal_translate', '-q', '-of', 'GTiff', '-ot', 'Byte', + '-a_ullr', '0', '0', '8', '-8', + $asc, $tif +) == 0 or die "Could not create $tif"; + +system('gdaladdo', '-q', '-r', 'average', $tif, '2') == 0 + or die "Could not create overview for $tif"; + +unlink $asc; diff --git a/raster/test/regress/loader/SourceOverview.opts b/raster/test/regress/loader/SourceOverview.opts new file mode 100644 index 000000000..613cec066 --- /dev/null +++ b/raster/test/regress/loader/SourceOverview.opts @@ -0,0 +1 @@ +-l 2 diff --git a/raster/test/regress/loader/SourceOverview.select.expected b/raster/test/regress/loader/SourceOverview.select.expected new file mode 100644 index 000000000..346fe7a64 --- /dev/null +++ b/raster/test/regress/loader/SourceOverview.select.expected @@ -0,0 +1,2 @@ +8|8|1|2|9|10 +4|4|6|8|22|24 diff --git a/raster/test/regress/loader/SourceOverview.select.sql b/raster/test/regress/loader/SourceOverview.select.sql new file mode 100644 index 000000000..3de2a4f88 --- /dev/null +++ b/raster/test/regress/loader/SourceOverview.select.sql @@ -0,0 +1,17 @@ +-- Base table keeps the full-resolution source pixels. +SELECT ST_Width(rast), ST_Height(rast), + ST_Value(rast, 1, 1, 1), + ST_Value(rast, 1, 2, 1), + ST_Value(rast, 1, 1, 2), + ST_Value(rast, 1, 2, 2) +FROM loadedrast; + +-- The overview table should reuse the source's averaged 2x overview. These +-- corner values would be 1, 3, 17, 19 if raster2pgsql regenerated it from the +-- base band with nearest-neighbor sampling. +SELECT ST_Width(rast), ST_Height(rast), + ST_Value(rast, 1, 1, 1), + ST_Value(rast, 1, 2, 1), + ST_Value(rast, 1, 1, 2), + ST_Value(rast, 1, 2, 2) +FROM o_2_loadedrast; diff --git a/raster/test/regress/loader/SourceOverview.tif.ref b/raster/test/regress/loader/SourceOverview.tif.ref new file mode 100644 index 000000000..c9fe00c65 --- /dev/null +++ b/raster/test/regress/loader/SourceOverview.tif.ref @@ -0,0 +1 @@ +SourceOverview-generated.tif diff --git a/raster/test/regress/tests.mk.in b/raster/test/regress/tests.mk.in index 7bc6972e6..03ae943ea 100644 --- a/raster/test/regress/tests.mk.in +++ b/raster/test/regress/tests.mk.in @@ -131,6 +131,7 @@ RASTER_TEST_LOADER = \ $(top_srcdir)/raster/test/regress/loader/Basic \ $(top_srcdir)/raster/test/regress/loader/Projected \ $(top_srcdir)/raster/test/regress/loader/OverviewNoPadding \ + $(top_srcdir)/raster/test/regress/loader/SourceOverview \ $(top_srcdir)/raster/test/regress/loader/IfNotExists \ $(top_srcdir)/raster/test/regress/loader/LongOptions \ $(top_srcdir)/raster/test/regress/loader/LongMaintenance \ ----------------------------------------------------------------------- Summary of changes: NEWS | 2 + doc/man/raster2pgsql.1 | 3 +- doc/using_raster_dataman.xml | 2 +- raster/loader/raster2pgsql.c | 83 +++++++++++++++++++--- raster/test/regress/loader/SourceOverview-post.pl | 3 + raster/test/regress/loader/SourceOverview-post.sql | 1 + raster/test/regress/loader/SourceOverview-pre.pl | 31 ++++++++ raster/test/regress/loader/SourceOverview.opts | 1 + .../regress/loader/SourceOverview.select.expected | 2 + .../test/regress/loader/SourceOverview.select.sql | 17 +++++ raster/test/regress/loader/SourceOverview.tif.ref | 1 + raster/test/regress/tests.mk.in | 1 + 12 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 raster/test/regress/loader/SourceOverview-post.pl create mode 100644 raster/test/regress/loader/SourceOverview-post.sql create mode 100644 raster/test/regress/loader/SourceOverview-pre.pl create mode 100644 raster/test/regress/loader/SourceOverview.opts create mode 100644 raster/test/regress/loader/SourceOverview.select.expected create mode 100644 raster/test/regress/loader/SourceOverview.select.sql create mode 100644 raster/test/regress/loader/SourceOverview.tif.ref hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 10:43:47 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 17:43:47 -0000 Subject: [PostGIS] #2137: [raster] Add handling for overviews present in source rasters In-Reply-To: <051.d6372aba8ea05ff27e76005fb2a32a8f@osgeo.org> References: <051.d6372aba8ea05ff27e76005fb2a32a8f@osgeo.org> Message-ID: <066.62f28095b3ca60b60eb56e1747edb0d9@osgeo.org> #2137: [raster] Add handling for overviews present in source rasters --------------------------+----------------------------- Reporter: dustymugs | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"a0b3925cf59cea943ac9bd1d2130692a559ff64f/git" a0b3925c/git]: {{{#!CommitTicketReference repository="git" revision="a0b3925cf59cea943ac9bd1d2130692a559ff64f" Reuse source overviews in raster2pgsql When raster2pgsql builds overview tables with -l, reuse a GDAL source overview whose dimensions match the requested output overview level for every selected band. Fall back to the existing generated overview path when any band has no matching source overview. Includes a loader regression whose source GeoTIFF carries an averaged 2x overview, so expected output distinguishes source-overview reuse from nearest-neighbor regeneration. Closes #2137 Closes https://github.com/postgis/postgis/pull/1092 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 10:58:35 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 10:58:35 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-648-gc4bae99fc Message-ID: <20260621175836.30ED51B2779@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via c4bae99fc25aabfc512dd0c14f1474b66b3e7730 (commit) from a0b3925cf59cea943ac9bd1d2130692a559ff64f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c4bae99fc25aabfc512dd0c14f1474b66b3e7730 Author: Darafei Praliaskouski Date: Sun Jun 21 21:51:30 2026 +0400 Generate pgsql2shp DBF id for geometry-only dumps When pgsql2shp exports a result with a geometry or geography column but no DBF attributes, add a generated integer GID field and populate it for each output record so the DBF record count remains aligned with the SHP records. Propagate the generated-field warning to callers and guard dumper state allocation failures in the CLI and GUI paths. Closes #2623 Closes https://github.com/postgis/postgis/pull/1019 diff --git a/NEWS b/NEWS index d0f6e212d..7f37d0986 100644 --- a/NEWS +++ b/NEWS @@ -87,6 +87,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed (Darafei Praliaskouski) - #2832, [raster] Avoid padding single-tile raster2pgsql overviews when padding is not requested (Darafei Praliaskouski) + - #2623, Generate a pgsql2shp GID field when exporting geometry-only + shapefiles (Darafei Praliaskouski) - Fix WKB and TWKB parser resource exhaustion on malformed input (Darafei Praliaskouski) - #6083, Pass configured dependency include paths to fuzzer smoke builds diff --git a/loader/pgsql2shp-cli.c b/loader/pgsql2shp-cli.c index 21ab0b7b1..4ce700521 100644 --- a/loader/pgsql2shp-cli.c +++ b/loader/pgsql2shp-cli.c @@ -178,6 +178,12 @@ main(int argc, char **argv) } state = ShpDumperCreate(config); + if (!state) + { + fprintf(stderr, "%s\n", _("Out of memory allocating dumper state")); + fflush(stderr); + exit(1); + } ret = ShpDumperConnectDatabase(state); if (ret != SHPDUMPEROK) diff --git a/loader/pgsql2shp-core.c b/loader/pgsql2shp-core.c index 47d2daf11..14da7a716 100644 --- a/loader/pgsql2shp-core.c +++ b/loader/pgsql2shp-core.c @@ -1161,6 +1161,9 @@ ShpDumperCreate(SHPDUMPERCONFIG *config) /* Create a new state object and assign the config to it */ state = malloc(sizeof(SHPDUMPERSTATE)); + if (!state) + return NULL; + state->config = config; /* Set any state defaults */ @@ -1179,6 +1182,7 @@ ShpDumperCreate(SHPDUMPERCONFIG *config) state->pgfieldnames = NULL; state->pgfieldlens = NULL; state->pgfieldtypmods = NULL; + state->generate_dbf_id = LW_FALSE; state->message[0] = '\0'; colmap_init(&state->column_map); @@ -1317,16 +1321,18 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) PGresult *res; char buf[256]; - int gidfound = 0, i, j, ret, status; + int gidfound = 0, i, j, status; + int ret = SHPDUMPEROK; stringbuffer_t sb; char *quoted = NULL; /* Open the column map if one was specified */ if (state->config->column_map_filename) { - ret = colmap_read(state->config->column_map_filename, - &state->column_map, state->message, SHPDUMPERMSGLEN); - if (!ret) return SHPDUMPERERR; + int colmap_ret = colmap_read( + state->config->column_map_filename, &state->column_map, state->message, SHPDUMPERMSGLEN); + if (!colmap_ret) + return SHPDUMPERERR; } /* If a user-defined query has been specified, create and point the state to our new table */ @@ -1787,6 +1793,25 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) } } + if (state->geo_col_name && !state->fieldcount) + { + if (DBFAddField(state->dbf, "GID", FTInteger, 11, 0) == -1) + { + snprintf( + state->message, SHPDUMPERMSGLEN, _("Error: generated field GID could not be created.")); + PQclear(res); + return SHPDUMPERERR; + } + + state->generate_dbf_id = LW_TRUE; + snprintf(buf, + sizeof(buf), + _("Warning: no DBF attributes found, generating a GID field for compatibility.\n")); + if (SHPDUMPERMSGLEN > (strlen(state->message) + 1)) + strncat(state->message, buf, SHPDUMPERMSGLEN - (strlen(state->message) + 1)); + ret = SHPDUMPERWARN; + } + /* Now we have generated the field lists, grab some info about the table */ status = getTableInfo(state); if (status == SHPDUMPERERR) @@ -1956,7 +1981,7 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) /* Generate the fetch query */ state->fetch_query = core_asprintf("FETCH %d FROM cur", state->config->fetchsize); - return SHPDUMPEROK; + return ret; } @@ -2033,6 +2058,19 @@ int ShpLoaderGenerateShapeRow(SHPDUMPERSTATE *state) } } + if (state->generate_dbf_id) + { + if (!DBFWriteIntegerAttribute(state->dbf, state->currow, 0, state->currow + 1)) + { + snprintf(state->message, + SHPDUMPERMSGLEN, + _("Error: generated GID for record %d could not be created"), + state->currow); + PQclear(state->fetchres); + return SHPDUMPERERR; + } + } + /* Now process the geo field, if present */ if (state->geo_col_name) { diff --git a/loader/pgsql2shp-core.h b/loader/pgsql2shp-core.h index 6b26702e3..564836d91 100644 --- a/loader/pgsql2shp-core.h +++ b/loader/pgsql2shp-core.h @@ -142,6 +142,9 @@ typedef struct shp_dumper_state /* Number of non-spatial fields in DBF output file */ int fieldcount; + /* Generate a DBF id field when the source has no non-spatial fields */ + int generate_dbf_id; + /* Number of rows in the database table */ int num_records; diff --git a/loader/shp2pgsql-gui.c b/loader/shp2pgsql-gui.c index 51307ccba..37a9a04d0 100644 --- a/loader/shp2pgsql-gui.c +++ b/loader/shp2pgsql-gui.c @@ -1864,6 +1864,9 @@ pgui_action_export(GtkWidget *widget, gpointer data) /* Grab the SHPDUMPERCONFIG for this row */ gtk_tree_model_get(GTK_TREE_MODEL(export_table_list_store), &iter, EXPORT_POINTER_COLUMN, &gptr, -1); dumper_table_config = (SHPDUMPERCONFIG *)gptr; + state = NULL; + output_shapefile = NULL; + orig_shapefile = dumper_table_config->shp_file; pgui_logf("\n=============================="); pgui_logf("Exporting with configuration: %s, %s, %s", dumper_table_config->table, dumper_table_config->schema, dumper_table_config->shp_file); @@ -1881,11 +1884,25 @@ pgui_action_export(GtkWidget *widget, gpointer data) /* Create the state for each configuration */ state = ShpDumperCreate(dumper_table_config); + if (!state) + { + pgui_seterr(_("Out of memory allocating dumper state")); + pgui_raise_error_dialogue(); + + break; + } state->config->conn = conn; /* Save the original shapefile name, then create a temporary version containing the full path */ - orig_shapefile = dumper_table_config->shp_file; output_shapefile = malloc(strlen(folder_path) + strlen(dumper_table_config->shp_file) + 2); + if (!output_shapefile) + { + pgui_seterr(_("Out of memory allocating output shapefile path")); + pgui_raise_error_dialogue(); + + ShpDumperDestroy(state); + break; + } strcpy(output_shapefile, folder_path); strcat(output_shapefile, G_DIR_SEPARATOR_S); strcat(output_shapefile, dumper_table_config->shp_file); @@ -1987,6 +2004,7 @@ export_cleanup: /* Reset shapefile back to original form (without full path) */ dumper_table_config->shp_file = orig_shapefile; + free(output_shapefile); /* Get next entry */ is_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(export_table_list_store), &iter); diff --git a/regress/dumper/null3d_expected.dbf b/regress/dumper/null3d_expected.dbf index 3db507ed5..8c1feb282 100644 Binary files a/regress/dumper/null3d_expected.dbf and b/regress/dumper/null3d_expected.dbf differ ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ loader/pgsql2shp-cli.c | 6 +++++ loader/pgsql2shp-core.c | 48 +++++++++++++++++++++++++++++++++---- loader/pgsql2shp-core.h | 3 +++ loader/shp2pgsql-gui.c | 20 +++++++++++++++- regress/dumper/null3d_expected.dbf | Bin 33 -> 89 bytes 6 files changed, 73 insertions(+), 6 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 10:58:37 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 17:58:37 -0000 Subject: [PostGIS] #2623: pgsql2shp creates a dbf with 0 records when the table only has a geometry column In-Reply-To: <048.b1aa54927956b8e2f02375fd738fddc8@osgeo.org> References: <048.b1aa54927956b8e2f02375fd738fddc8@osgeo.org> Message-ID: <063.bec449ee5109175c00629964478d1419@osgeo.org> #2623: pgsql2shp creates a dbf with 0 records when the table only has a geometry column ----------------------------------+----------------------------- Reporter: winkey | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: utils/loader-dumper | Version: 2.0.x Resolution: fixed | Keywords: ----------------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"c4bae99fc25aabfc512dd0c14f1474b66b3e7730/git" c4bae99f/git]: {{{#!CommitTicketReference repository="git" revision="c4bae99fc25aabfc512dd0c14f1474b66b3e7730" Generate pgsql2shp DBF id for geometry-only dumps When pgsql2shp exports a result with a geometry or geography column but no DBF attributes, add a generated integer GID field and populate it for each output record so the DBF record count remains aligned with the SHP records. Propagate the generated-field warning to callers and guard dumper state allocation failures in the CLI and GUI paths. Closes #2623 Closes https://github.com/postgis/postgis/pull/1019 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 11:30:40 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 11:30:40 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-649-g1b74f2013 Message-ID: <20260621183040.896611B304C@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 1b74f201374035483b1d9e53f0fa4d981349f78b (commit) from c4bae99fc25aabfc512dd0c14f1474b66b3e7730 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1b74f201374035483b1d9e53f0fa4d981349f78b Author: Darafei Praliaskouski Date: Sun Jun 21 22:11:27 2026 +0400 Allow custom shp2pgsql feature id column Add shp2pgsql -f/--feature-id-column so callers can choose the generated feature id column name instead of always using gid. Validate the configured column name before generating SQL, and keep escaping source gid attributes to __gid so default pgsql2shp round trips do not silently drop them. Closes #3033 Closes https://github.com/postgis/postgis/pull/1022 diff --git a/NEWS b/NEWS index 7f37d0986..2f67dfa1e 100644 --- a/NEWS +++ b/NEWS @@ -21,11 +21,12 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * New Features * - - #1124, #2935, #4658, #4659, [loader] Rework loader arguments: shp2pgsql can - create UNLOGGED tables, shp2pgsql --drop-table can emit DROP TABLE - before prepare output, raster2pgsql/shp2pgsql expose loader actions - as long options, both loaders accept long aliases for existing - options, and --if-not-exists makes creation actions idempotent + - #1124, #2935, #3033, #4658, #4659, [loader] Rework loader arguments: + shp2pgsql can create UNLOGGED tables and choose the feature id column + name, shp2pgsql --drop-table can emit DROP TABLE before prepare + output, raster2pgsql/shp2pgsql expose loader actions as long options, + both loaders accept long aliases for existing options, and + --if-not-exists makes creation actions idempotent (Darafei Praliaskouski) - #4208, Add single-geometry variants of ST_MaxDistance and ST_LongestLine (Darafei Praliaskouski) diff --git a/doc/man/shp2pgsql.1 b/doc/man/shp2pgsql.1 index 2895b5c36..2ff16973d 100644 --- a/doc/man/shp2pgsql.1 +++ b/doc/man/shp2pgsql.1 @@ -90,6 +90,9 @@ lat/lon data. At the moment the only spatial reference supported is 4326. \fB\-g\fR, \fB\-\-geometry\-column\fR <\fIgeometry_column\fR> Specify the name of the geometry column (mostly useful in append mode). .TP +\fB\-f\fR, \fB\-\-feature\-id\-column\fR <\fIfid_column\fR> +Specify the name of the feature id column. The default is gid. +.TP \fB\-\-create\-index\fR Create a spatial index on the geometry column. .TP diff --git a/doc/using_postgis_dataman.xml b/doc/using_postgis_dataman.xml index d7ed22913..b902f54af 100644 --- a/doc/using_postgis_dataman.xml +++ b/doc/using_postgis_dataman.xml @@ -1966,6 +1966,18 @@ COMMIT; + + + + + + Specify the name of the feature id column. The default is gid. + The value must be a simple PostgreSQL identifier and cannot use a + PostgreSQL system column name. + + + + diff --git a/loader/README.shp2pgsql b/loader/README.shp2pgsql index 0fd7685d8..9f7a93ee8 100644 --- a/loader/README.shp2pgsql +++ b/loader/README.shp2pgsql @@ -78,6 +78,9 @@ OPTIONS Specify the name of the geometry column (mostly useful in append mode). + -f, --feature-id-column + Specify the name of the feature id column. The default is gid. + --create-index Create a spatial index on the geometry column. diff --git a/loader/cunit/cu_shp2pgsql.c b/loader/cunit/cu_shp2pgsql.c index c43f5ac55..a674b1a26 100644 --- a/loader/cunit/cu_shp2pgsql.c +++ b/loader/cunit/cu_shp2pgsql.c @@ -20,6 +20,8 @@ void test_ShpLoaderDestroy(void); void test_ShpLoaderGetSQLHeader_drop_prepare(void); void test_ShpLoaderGetSQLHeader_if_not_exists_table_modifier(void); void test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier(void); +void test_ShpLoaderFIDColumnSQL(void); +void test_ShpLoaderRejectsInvalidFIDColumn(void); void test_ShpLoaderOpenShapeRejectsZip(void); SHPLOADERCONFIG *loader_config; @@ -49,6 +51,9 @@ CU_pSuite register_shp2pgsql_suite(void) (NULL == CU_add_test(pSuite, "test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier()", test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier)) || + (NULL == CU_add_test(pSuite, "test_ShpLoaderFIDColumnSQL()", test_ShpLoaderFIDColumnSQL)) || + (NULL == + CU_add_test(pSuite, "test_ShpLoaderRejectsInvalidFIDColumn()", test_ShpLoaderRejectsInvalidFIDColumn)) || (NULL == CU_add_test(pSuite, "test_ShpLoaderOpenShapeRejectsZip()", test_ShpLoaderOpenShapeRejectsZip))) { CU_cleanup_registry(); @@ -148,7 +153,7 @@ test_ShpLoaderGetSQLHeader_if_not_exists_table_modifier(void) CU_ASSERT_PTR_NOT_NULL(header); CU_ASSERT_PTR_NOT_NULL(strstr(header, "CREATE TABLE IF NOT EXISTS \"loadedshp\" " - "(gid serial PRIMARY KEY,\n" + "(\"gid\" serial PRIMARY KEY,\n" "\"the_geom\" geometry(POINT,0));")); CU_ASSERT_PTR_NULL(strstr(header, "AddGeometryColumn")); CU_ASSERT_PTR_NULL(strstr(header, "ALTER TABLE")); @@ -178,6 +183,66 @@ test_ShpLoaderGetSQLFooter_if_not_exists_index_modifier(void) ShpLoaderDestroy(loader_state); } +void +test_ShpLoaderFIDColumnSQL(void) +{ + SHPLOADERCONFIG config; + SHPLOADERSTATE *state; + char *header = NULL; + + set_loader_config_defaults(&config); + config.table = "loadedshp"; + config.readshape = 0; + + state = ShpLoaderCreate(&config); + CU_ASSERT_EQUAL_FATAL(ShpLoaderGetSQLHeader(state, &header), SHPLOADEROK); + CU_ASSERT_PTR_NOT_NULL_FATAL(header); + CU_ASSERT_PTR_NOT_NULL(strstr(header, "CREATE TABLE \"loadedshp\" (\"gid\" serial")); + CU_ASSERT_PTR_NOT_NULL(strstr(header, "ADD PRIMARY KEY (\"gid\")")); + free(header); + header = NULL; + ShpLoaderDestroy(state); + + config.fid_col = "fid"; + state = ShpLoaderCreate(&config); + CU_ASSERT_EQUAL_FATAL(ShpLoaderGetSQLHeader(state, &header), SHPLOADEROK); + CU_ASSERT_PTR_NOT_NULL_FATAL(header); + CU_ASSERT_PTR_NOT_NULL(strstr(header, "CREATE TABLE \"loadedshp\" (\"fid\" serial")); + CU_ASSERT_PTR_NOT_NULL(strstr(header, "ADD PRIMARY KEY (\"fid\")")); + free(header); + ShpLoaderDestroy(state); + + free(config.encoding); +} + +void +test_ShpLoaderRejectsInvalidFIDColumn(void) +{ + SHPLOADERCONFIG config; + SHPLOADERSTATE *state; + char *header = NULL; + + set_loader_config_defaults(&config); + config.table = "loadedshp"; + config.readshape = 0; + config.fid_col = "bad\"fid"; + + state = ShpLoaderCreate(&config); + CU_ASSERT_EQUAL(ShpLoaderGetSQLHeader(state, &header), SHPLOADERERR); + CU_ASSERT_PTR_NULL(header); + CU_ASSERT_PTR_NOT_NULL(strstr(state->message, "Invalid feature id column name")); + ShpLoaderDestroy(state); + + config.fid_col = "ctid"; + state = ShpLoaderCreate(&config); + CU_ASSERT_EQUAL(ShpLoaderGetSQLHeader(state, &header), SHPLOADERERR); + CU_ASSERT_PTR_NULL(header); + CU_ASSERT_PTR_NOT_NULL(strstr(state->message, "Invalid feature id column name")); + ShpLoaderDestroy(state); + + free(config.encoding); +} + void test_ShpLoaderOpenShapeRejectsZip(void) { diff --git a/loader/shp2pgsql-cli.c b/loader/shp2pgsql-cli.c index 13690e91f..a7c6db37d 100644 --- a/loader/shp2pgsql-cli.c +++ b/loader/shp2pgsql-cli.c @@ -33,6 +33,7 @@ static const ShpLoaderLongOption long_option_aliases[] = { {"dimensionality", 't', 1}, {"dump-format", 'D', 0}, {"encoding", 'W', 1}, + {"feature-id-column", 'f', 1}, {"force-int4", 'i', 0}, {"geography", 'G', 0}, {"geometry-column", 'g', 1}, @@ -125,6 +126,9 @@ usage() printf( _(" -g, --geometry-column Specify the name of the geometry/geography column\n" " (mostly useful in append mode).\n")); + printf( + _(" -f, --feature-id-column Specify the name of the feature id column\n" + " (default: \"" FID_DEFAULT "\").\n")); printf(_(" -D, --dump-format Use postgresql dump format (defaults to SQL insert statements).\n")); printf(_( " -e Execute each statement individually, do not use a transaction.\n" " Not compatible with -D.\n" )); @@ -283,7 +287,7 @@ main (int argc, char **argv) } else { - c = pgis_getopt(argc, argv, "-?acdeg:ikm:nps:t:uwDGIN:ST:W:X:Z"); + c = pgis_getopt(argc, argv, "-?acdef:g:ikm:nps:t:uwDGIN:ST:W:X:Z"); if (c == EOF) break; @@ -344,6 +348,9 @@ main (int argc, char **argv) case 'g': config->geo_col = pgis_optarg; break; + case 'f': + config->fid_col = pgis_optarg; + break; case 'm': config->column_map_filename = pgis_optarg; break; diff --git a/loader/shp2pgsql-core.c b/loader/shp2pgsql-core.c index 394d5dd66..a62e8113b 100644 --- a/loader/shp2pgsql-core.c +++ b/loader/shp2pgsql-core.c @@ -773,6 +773,78 @@ strtolower(char *s) s[j] = tolower(s[j]); } +static const char * +ShpLoaderFIDColumn(const SHPLOADERSTATE *state) +{ + return state->config->fid_col ? state->config->fid_col : FID_DEFAULT; +} + +static int +ShpLoaderNameMatchesAny(const char *name, const char *const *names, size_t num_names, int case_sensitive) +{ + size_t i; + + for (i = 0; i < num_names; i++) + { + if (case_sensitive ? !strcmp(name, names[i]) : !strcasecmp(name, names[i])) + return LW_TRUE; + } + + return LW_FALSE; +} + +static int +ShpLoaderFIDColumnIsSystemColumn(const char *name) +{ + static const char *const names[] = {"tableoid", "cmin", "cmax", "xmin", "xmax", "oid", "ctid"}; + + return ShpLoaderNameMatchesAny(name, names, sizeof(names) / sizeof(names[0]), LW_FALSE); +} + +static int +ShpLoaderFIDColumnIsValid(const char *name) +{ + size_t i; + + if (!name || !name[0] || ShpLoaderFIDColumnIsSystemColumn(name)) + return LW_FALSE; + + if (!isalpha((unsigned char)name[0]) && name[0] != '_') + return LW_FALSE; + + for (i = 1; name[i]; i++) + { + if (!isalnum((unsigned char)name[i]) && name[i] != '_') + return LW_FALSE; + } + + return LW_TRUE; +} + +static int +ShpLoaderValidateFIDColumn(SHPLOADERSTATE *state) +{ + const char *fid_col = ShpLoaderFIDColumn(state); + + if (ShpLoaderFIDColumnIsValid(fid_col)) + return SHPLOADEROK; + + snprintf(state->message, SHPLOADERMSGLEN, _("Invalid feature id column name \"%s\""), fid_col ? fid_col : ""); + return SHPLOADERERR; +} + +static int +ShpLoaderFieldNameNeedsEscape(const SHPLOADERSTATE *state, const char *name) +{ + static const char *const reserved_names[] = { + FID_DEFAULT, "tableoid", "cmin", "cmax", "xmin", "xmax", "primary", "oid", "ctid"}; + const char *fid_col = ShpLoaderFIDColumn(state); + + return name[0] == '_' || !strcmp(name, fid_col) || + ShpLoaderNameMatchesAny( + name, reserved_names, sizeof(reserved_names) / sizeof(reserved_names[0]), LW_TRUE); +} + static void pgtype_typmod_name(const SHPLOADERSTATE *state, char *buf, size_t len) { @@ -803,9 +875,11 @@ append_qualified_table(stringbuffer_t *sb, const char *schema, const char *table static void append_primary_key_ddl(const SHPLOADERSTATE *state, stringbuffer_t *sb) { + const char *fid_col = ShpLoaderFIDColumn(state); + stringbuffer_aprintf(sb, "ALTER TABLE "); append_qualified_table(sb, state->config->schema, state->config->table); - stringbuffer_aprintf(sb, " ADD PRIMARY KEY (gid);\n"); + stringbuffer_aprintf(sb, " ADD PRIMARY KEY (\"%s\");\n", fid_col); if (state->config->idxtablespace != NULL) { @@ -832,6 +906,7 @@ set_loader_config_defaults(SHPLOADERCONFIG *config) config->table = NULL; config->schema = NULL; config->geo_col = NULL; + config->fid_col = NULL; config->shp_file = NULL; config->dump_format = 0; config->simple_geometries = 0; @@ -985,6 +1060,9 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state) DBFFieldType type = FTInvalid; char *utf8str; + if (ShpLoaderValidateFIDColumn(state) != SHPLOADEROK) + return SHPLOADERERR; + if (shp_loader_is_zip_archive(state->config->shp_file)) { snprintf(state->message, @@ -1305,20 +1383,12 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state) strtolower(name); /* - * Escape names starting with the - * escape char (_), those named 'gid' - * or after pgsql reserved attribute names + * Keep generated loader columns and PostgreSQL system columns out of + * the DBF attribute namespace. Always escape source "gid" columns too: + * pgsql2shp treats gid as a loader id by default, so preserving the old + * "__gid" mapping keeps default round trips lossless even with -f. */ - if (name[0] == '_' || - ! strcmp(name, "gid") || - ! strcmp(name, "tableoid") || - ! strcmp(name, "cmin") || - ! strcmp(name, "cmax") || - ! strcmp(name, "xmin") || - ! strcmp(name, "xmax") || - ! strcmp(name, "primary") || - ! strcmp(name, "oid") || - ! strcmp(name, "ctid")) + if (ShpLoaderFieldNameNeedsEscape(state, name)) { char tmp[MAXFIELDNAMELEN] = "__"; memcpy(tmp+2, name, MAXFIELDNAMELEN-2); @@ -1425,9 +1495,15 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) stringbuffer_t *sb; char *ret; int j; + const char *fid_col; const int use_transaction = state->config->plan.transaction == LOADER_TRANSACTION_ON && plan_has_transactional_work(&state->config->plan); + if (ShpLoaderValidateFIDColumn(state) != SHPLOADEROK) + return SHPLOADERERR; + + fid_col = ShpLoaderFIDColumn(state); + /* Create the stringbuffer containing the header; we use this API as it's easier for handling string resizing during append */ sb = stringbuffer_create(); @@ -1476,7 +1552,7 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader) state->config->unlogged ? "UNLOGGED " : "", if_not_exists ? "IF NOT EXISTS " : ""); append_qualified_table(sb, state->config->schema, state->config->table); - stringbuffer_aprintf(sb, " (gid serial%s", if_not_exists ? " PRIMARY KEY" : ""); + stringbuffer_aprintf(sb, " (\"%s\" serial%s", fid_col, if_not_exists ? " PRIMARY KEY" : ""); if (if_not_exists && state->config->idxtablespace != NULL) { diff --git a/loader/shp2pgsql-core.h b/loader/shp2pgsql-core.h index b106e2cde..95ca8866f 100644 --- a/loader/shp2pgsql-core.h +++ b/loader/shp2pgsql-core.h @@ -71,6 +71,7 @@ */ #define GEOMETRY_DEFAULT "geom" #define GEOGRAPHY_DEFAULT "geog" +#define FID_DEFAULT "gid" /* * Default character encoding @@ -94,6 +95,9 @@ typedef struct shp_loader_config /* geometry/geography column name specified by the user, may be null. */ char *geo_col; + /* feature id column name specified by the user, may be null. */ + char *fid_col; + /* the shape file (without the .shp extension) */ char *shp_file; diff --git a/regress/loader/FIDColumn.dbf b/regress/loader/FIDColumn.dbf new file mode 100644 index 000000000..9edcc7d04 Binary files /dev/null and b/regress/loader/FIDColumn.dbf differ diff --git a/regress/loader/FIDColumn.opts b/regress/loader/FIDColumn.opts new file mode 100644 index 000000000..cc8a4fb05 --- /dev/null +++ b/regress/loader/FIDColumn.opts @@ -0,0 +1,5 @@ +# Reuse the CharNoWidth DBF layout to verify that a custom feature id column +# changes the loader primary key but still escapes a source DBF column mapped to +# gid. pgsql2shp treats gid as a loader id by default, so __gid preserves that +# source attribute through default dump/load round trips. +--feature-id-column fid -m {regdir}/loader/FIDColumn_mapping.txt diff --git a/regress/loader/FIDColumn.select.expected b/regress/loader/FIDColumn.select.expected new file mode 100644 index 000000000..8c9e55cfa --- /dev/null +++ b/regress/loader/FIDColumn.select.expected @@ -0,0 +1,2 @@ +fid +__gid diff --git a/regress/loader/FIDColumn.select.sql b/regress/loader/FIDColumn.select.sql new file mode 100644 index 000000000..849c569ea --- /dev/null +++ b/regress/loader/FIDColumn.select.sql @@ -0,0 +1,6 @@ +SET CLIENT_ENCODING to UTF8; +SELECT column_name +FROM information_schema.columns +WHERE table_name = 'loadedshp' + AND column_name IN ('fid', 'gid', '__gid') +ORDER BY ordinal_position; diff --git a/regress/loader/FIDColumn_mapping.txt b/regress/loader/FIDColumn_mapping.txt new file mode 100644 index 000000000..2ac8f55e4 --- /dev/null +++ b/regress/loader/FIDColumn_mapping.txt @@ -0,0 +1 @@ +gid STATEFP diff --git a/regress/loader/tests.mk b/regress/loader/tests.mk index 40941b7e6..b40949bb8 100644 --- a/regress/loader/tests.mk +++ b/regress/loader/tests.mk @@ -42,3 +42,4 @@ TESTS += \ $(top_srcdir)/regress/loader/TestSkipANALYZE \ $(top_srcdir)/regress/loader/TestANALYZE \ $(top_srcdir)/regress/loader/CharNoWidth \ + $(top_srcdir)/regress/loader/FIDColumn \ ----------------------------------------------------------------------- Summary of changes: NEWS | 11 ++- doc/man/shp2pgsql.1 | 3 + doc/using_postgis_dataman.xml | 12 +++ loader/README.shp2pgsql | 3 + loader/cunit/cu_shp2pgsql.c | 67 +++++++++++++- loader/shp2pgsql-cli.c | 9 +- loader/shp2pgsql-core.c | 106 +++++++++++++++++++--- loader/shp2pgsql-core.h | 4 + regress/loader/{CharNoWidth.dbf => FIDColumn.dbf} | Bin regress/loader/FIDColumn.opts | 5 + regress/loader/FIDColumn.select.expected | 2 + regress/loader/FIDColumn.select.sql | 6 ++ regress/loader/FIDColumn_mapping.txt | 1 + regress/loader/tests.mk | 1 + 14 files changed, 208 insertions(+), 22 deletions(-) copy regress/loader/{CharNoWidth.dbf => FIDColumn.dbf} (100%) create mode 100644 regress/loader/FIDColumn.opts create mode 100644 regress/loader/FIDColumn.select.expected create mode 100644 regress/loader/FIDColumn.select.sql create mode 100644 regress/loader/FIDColumn_mapping.txt hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 11:30:42 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 18:30:42 -0000 Subject: [PostGIS] #3033: FID column name option In-Reply-To: <051.a9f8099418272e5572442ade236e5c7a@osgeo.org> References: <051.a9f8099418272e5572442ade236e5c7a@osgeo.org> Message-ID: <066.87d29cca84ca58964c6fbce1324033ef@osgeo.org> #3033: FID column name option ----------------------------------+----------------------------- Reporter: mohayemin | Owner: robe Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: utils/loader-dumper | Version: 2.1.x Resolution: fixed | Keywords: ----------------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"1b74f201374035483b1d9e53f0fa4d981349f78b/git" 1b74f20/git]: {{{#!CommitTicketReference repository="git" revision="1b74f201374035483b1d9e53f0fa4d981349f78b" Allow custom shp2pgsql feature id column Add shp2pgsql -f/--feature-id-column so callers can choose the generated feature id column name instead of always using gid. Validate the configured column name before generating SQL, and keep escaping source gid attributes to __gid so default pgsql2shp round trips do not silently drop them. Closes #3033 Closes https://github.com/postgis/postgis/pull/1022 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Sun Jun 21 11:34:18 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 18:34:18 -0000 Subject: [PostGIS] #2526: [raster] Dynamic Background Workers In-Reply-To: <051.aeb45ff5b18759bf4aa4716f8853a76a@osgeo.org> References: <051.aeb45ff5b18759bf4aa4716f8853a76a@osgeo.org> Message-ID: <066.fb012f62b9dcc781cd7f0864e3537252@osgeo.org> #2526: [raster] Dynamic Background Workers --------------------------+----------------------------- Reporter: dustymugs | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: master Resolution: worksforme | Keywords: postgresql 9.4 --------------------------+----------------------------- Changes (by komzpa): * resolution: => worksforme * status: new => closed Comment: By now it is handled by PARALLEL SAFE. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 11:53:22 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 11:53:22 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-650-ga401974f9 Message-ID: <20260621185323.411F21B3E19@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via a401974f93be7586b3c7dbe9f7d686f3cad16061 (commit) from 1b74f201374035483b1d9e53f0fa4d981349f78b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a401974f93be7586b3c7dbe9f7d686f3cad16061 Author: Darafei Praliaskouski Date: Sun Jun 21 22:40:45 2026 +0400 Move raster st_sum4ma callback to C Replace the PL/pgSQL two-dimensional st_sum4ma callback with a C implementation while preserving nodata handling, including lazy replacement-value casting for wrapper-provided modes. Closes #4678 Closes https://github.com/postgis/postgis/pull/1098 diff --git a/NEWS b/NEWS index 2f67dfa1e..0f1dba4e5 100644 --- a/NEWS +++ b/NEWS @@ -63,6 +63,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed to open shapefile sidecar files (Darafei Praliaskouski) - #3158, Move geometry and geography typmod bit helpers out of the public liblwgeom header (Darafei Praliaskouski) + - #4678, [raster] Move st_sum4ma neighborhood callback to C + (Darafei Praliaskouski) - #2116, [raster] Add ST_Value nearest-neighbor boundary options (Darafei Praliaskouski) - #2804, #4315, [raster] Support two-argument ST_MapAlgebra callbacks diff --git a/raster/rt_pg/rtpg_mapalgebra.c b/raster/rt_pg/rtpg_mapalgebra.c index 36aad8f02..601c795e6 100644 --- a/raster/rt_pg/rtpg_mapalgebra.c +++ b/raster/rt_pg/rtpg_mapalgebra.c @@ -38,6 +38,7 @@ #include /* for get_typlenbyvalalign */ #include /* for ArrayType */ #include /* for cstring_to_text */ +#include /* for float8in */ #include /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */ #include /* for GetAttributeByName */ @@ -71,6 +72,7 @@ Datum RASTER_mapAlgebraFct(PG_FUNCTION_ARGS); /* one-raster neighborhood MapAlgebra */ Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS); +Datum RASTER_sum4ma(PG_FUNCTION_ARGS); /* two-raster MapAlgebra */ Datum RASTER_mapAlgebra2(PG_FUNCTION_ARGS); @@ -79,6 +81,89 @@ Datum RASTER_mapAlgebra2(PG_FUNCTION_ARGS); /* n-raster MapAlgebra */ /* ---------------------------------------------------------------- */ +/* + * Neighborhood callback for one-raster map algebra that implements ST_Sum4ma. + * The callback receives the moving-window values as a PostgreSQL float8 array + * and returns their sum. NULL cells follow the historical PL/pgSQL contract: + * a NULL nodata mode makes the result NULL, "ignore" skips NULL cells, and any + * other mode is interpreted as the numeric replacement value. The replacement + * mode is cast only when a NULL cell is actually encountered so wrapper-provided + * modes such as "NULL" and "value" remain valid for all-non-NULL windows. + */ +PG_FUNCTION_INFO_V1(RASTER_sum4ma); +Datum +RASTER_sum4ma(PG_FUNCTION_ARGS) +{ + ArrayType *matrix; + Datum *values; + bool *nulls; + int nitems; + int i; + double sum = 0; + char *nodatamode = NULL; + bool ignore_nodata = false; + bool has_nodata_replacement = false; + double nodata_replacement = 0; + + if (PG_ARGISNULL(0)) + ereport( + ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("st_sum4ma: matrix argument must not be NULL"))); + + if (!PG_ARGISNULL(1)) + { + nodatamode = text_to_cstring(PG_GETARG_TEXT_PP(1)); + if (strcmp(nodatamode, "ignore") == 0) + ignore_nodata = true; + } + + matrix = PG_GETARG_ARRAYTYPE_P(0); + if (ARR_NDIM(matrix) < 2) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("st_sum4ma: matrix argument must have at least 2 dimensions"))); + + deconstruct_array(matrix, FLOAT8OID, sizeof(float8), FLOAT8PASSBYVAL, 'd', &values, &nulls, &nitems); + + for (i = 0; i < nitems; i++) + { + if (nulls[i]) + { + if (ignore_nodata) + continue; + if (!nodatamode) + { + pfree(nulls); + pfree(values); + PG_FREE_IF_COPY(matrix, 0); + PG_RETURN_NULL(); + } + + /* + * Match the PL/pgSQL callback: wrapper-provided modes such as + * "NULL" and "value" are only cast when a NULL cell is present. + */ + if (!has_nodata_replacement) + { + nodata_replacement = + DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(nodatamode))); + has_nodata_replacement = true; + } + sum += nodata_replacement; + } + else + sum += DatumGetFloat8(values[i]); + } + + if (nodatamode) + pfree(nodatamode); + pfree(nulls); + pfree(values); + PG_FREE_IF_COPY(matrix, 0); + + PG_RETURN_FLOAT8(sum); +} + #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wgnu-variable-sized-type-not-at-end" diff --git a/raster/rt_pg/rtpostgis.sql.in b/raster/rt_pg/rtpostgis.sql.in index 96bb55ed8..aa09a7357 100644 --- a/raster/rt_pg/rtpostgis.sql.in +++ b/raster/rt_pg/rtpostgis.sql.in @@ -2541,30 +2541,9 @@ CREATE OR REPLACE FUNCTION st_min4ma(matrix float[][], nodatamode text, variadic LANGUAGE 'plpgsql' IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION st_sum4ma(matrix float[][], nodatamode text, variadic args text[]) - RETURNS float AS - $$ - DECLARE - _matrix float[][]; - sum float; - BEGIN - _matrix := matrix; - sum := 0; - FOR x in array_lower(matrix, 1)..array_upper(matrix, 1) LOOP - FOR y in array_lower(matrix, 2)..array_upper(matrix, 2) LOOP - IF _matrix[x][y] IS NULL THEN - IF nodatamode = 'ignore' THEN - _matrix[x][y] := 0; - ELSE - _matrix[x][y] := nodatamode::float; - END IF; - END IF; - sum := sum + _matrix[x][y]; - END LOOP; - END LOOP; - RETURN sum; - END; - $$ - LANGUAGE 'plpgsql' IMMUTABLE PARALLEL SAFE; + RETURNS float + AS 'MODULE_PATHNAME', 'RASTER_sum4ma' + LANGUAGE 'c' IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION st_mean4ma(matrix float[][], nodatamode text, variadic args text[]) RETURNS float AS diff --git a/raster/test/regress/rt_4ma.sql b/raster/test/regress/rt_4ma.sql index 1a3b214f3..57798b735 100644 --- a/raster/test/regress/rt_4ma.sql +++ b/raster/test/regress/rt_4ma.sql @@ -78,5 +78,20 @@ SELECT FROM raster_value_arrays ORDER BY id; +SELECT + 'sum4ma.nodata', + st_sum4ma(ARRAY[[1::double precision, NULL, 3]], NULL, VARIADIC NULL::text[]) IS NULL, + st_sum4ma(ARRAY[[1::double precision, NULL, 3]], 'ignore', VARIADIC NULL::text[]), + st_sum4ma(ARRAY[[1::double precision, NULL, 3]], '-8', VARIADIC NULL::text[]); + +SELECT + 'sum4ma.mode.no-null', + st_sum4ma(ARRAY[[1::double precision, 2, 3]], 'NULL', VARIADIC NULL::text[]), + st_sum4ma(ARRAY[[1::double precision, 2, 3]], 'value', VARIADIC NULL::text[]); + +SELECT + 'sum4ma.runtime-3d', + st_sum4ma('{{{1,2,3},{4,5,6}}}'::double precision[][], NULL, VARIADIC NULL::text[]); + DROP TABLE IF EXISTS raster_value_arrays; DROP FUNCTION IF EXISTS make_value_array(integer, integer, double precision, double precision, text); diff --git a/raster/test/regress/rt_4ma_expected b/raster/test/regress/rt_4ma_expected index d6ec1c2b2..c91079c10 100644 --- a/raster/test/regress/rt_4ma_expected +++ b/raster/test/regress/rt_4ma_expected @@ -15,3 +15,6 @@ NOTICE: table "raster_value_arrays" does not exist, skipping 16|{{{1,3.1,5.2},{NULL,NULL,11.5},{13.6,NULL,NULL}}}|5.000000|13.600000|6.880000|1.000000|12.600000|5.435715|34.400000 17|{{{NULL,3.14,NULL},{NULL,12.56,NULL},{NULL,NULL,25.12}}}|3.000000|25.120000|13.606667|3.140000|21.980000|11.027318|40.820000 18|{{{NULL,NULL,NULL},{NULL,NULL,NULL},{NULL,NULL,9}}}|1.000000|9.000000|9.000000|9.000000|0.000000||9.000000 +sum4ma.nodata|t|4|-4 +sum4ma.mode.no-null|6|6 +sum4ma.runtime-3d|21 ----------------------------------------------------------------------- Summary of changes: NEWS | 2 + raster/rt_pg/rtpg_mapalgebra.c | 85 +++++++++++++++++++++++++++++++++++++ raster/rt_pg/rtpostgis.sql.in | 27 ++---------- raster/test/regress/rt_4ma.sql | 15 +++++++ raster/test/regress/rt_4ma_expected | 3 ++ 5 files changed, 108 insertions(+), 24 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 11:53:24 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 18:53:24 -0000 Subject: [PostGIS] #4678: Rewrite all raster callback functions in C In-Reply-To: <046.dac98bad5b89f555a3759a1900bbd4cc@osgeo.org> References: <046.dac98bad5b89f555a3759a1900bbd4cc@osgeo.org> Message-ID: <061.ef7cb369625e0463214b99b0e8593847@osgeo.org> #4678: Rewrite all raster callback functions in C ---------------------+----------------------------- Reporter: robe | Owner: dustymugs Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: master Resolution: fixed | Keywords: ---------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"a401974f93be7586b3c7dbe9f7d686f3cad16061/git" a401974/git]: {{{#!CommitTicketReference repository="git" revision="a401974f93be7586b3c7dbe9f7d686f3cad16061" Move raster st_sum4ma callback to C Replace the PL/pgSQL two-dimensional st_sum4ma callback with a C implementation while preserving nodata handling, including lazy replacement-value casting for wrapper-provided modes. Closes #4678 Closes https://github.com/postgis/postgis/pull/1098 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 12:09:29 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 12:09:29 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-651-g92903a731 Message-ID: <20260621190929.DF1841B44EE@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 92903a731a5dc918318e57c0746ba407d84eccdc (commit) from a401974f93be7586b3c7dbe9f7d686f3cad16061 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 92903a731a5dc918318e57c0746ba407d84eccdc Author: Darafei Praliaskouski Date: Sun Jun 21 23:01:47 2026 +0400 loader: preserve numeric DBF metadata in pgsql2shp Decode numeric typmod precision and scale when selecting DBF field metadata so pgsql2shp preserves fixed numeric declarations that fit in the DBF field-width limit. Keep legacy 32,10 metadata for untyped numeric values. Add pgsql2shp dumper coverage for portable numeric typmods, and gate PostgreSQL 15+ negative-scale numeric coverage behind the configured PostgreSQL version. Closes #2850 Closes https://github.com/postgis/postgis/pull/1020 diff --git a/.gitignore b/.gitignore index 9b374cdea..57649dd75 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ doc/html/images/Makefile regression.out raster/test/regress/tests.mk regress/core/tests.mk +regress/dumper/tests.mk sfcgal/regress/tests.mk @@ -177,6 +178,7 @@ regress/Makefile regress/core/Makefile regress/core/tests.mk regress/dumper/Makefile +regress/dumper/tests.mk regress/loader/Makefile regress/real/download_data regress/real/Makefile diff --git a/GNUmakefile.in b/GNUmakefile.in index e65fd23e4..961f53c9b 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -288,7 +288,7 @@ postgis_revision.h: include $(top_builddir)/regress/core/tests.mk include $(top_srcdir)/regress/loader/tests.mk -include $(top_srcdir)/regress/dumper/tests.mk +include $(top_builddir)/regress/dumper/tests.mk ifeq ($(HAVE_SFCGAL),yes) override RUNTESTFLAGS := $(RUNTESTFLAGS) --sfcgal include $(top_builddir)/sfcgal/regress/tests.mk diff --git a/NEWS b/NEWS index 0f1dba4e5..117a044bc 100644 --- a/NEWS +++ b/NEWS @@ -94,6 +94,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed shapefiles (Darafei Praliaskouski) - Fix WKB and TWKB parser resource exhaustion on malformed input (Darafei Praliaskouski) + - #2850, Preserve pgsql2shp numeric precision and scale in DBF metadata + (Darafei Praliaskouski) - #6083, Pass configured dependency include paths to fuzzer smoke builds (Darafei Praliaskouski) - #3103, Add regression coverage for exact-schema find_srid and diff --git a/configure.ac b/configure.ac index 57157d133..9324966ee 100644 --- a/configure.ac +++ b/configure.ac @@ -1902,6 +1902,7 @@ AC_CONFIG_FILES([GNUmakefile regress/core/Makefile regress/core/tests.mk regress/dumper/Makefile + regress/dumper/tests.mk regress/loader/Makefile doc/Makefile doc/Makefile.comments diff --git a/loader/pgsql2shp-core.c b/loader/pgsql2shp-core.c index 14da7a716..334b2b7c2 100644 --- a/loader/pgsql2shp-core.c +++ b/loader/pgsql2shp-core.c @@ -59,6 +59,8 @@ static char *nullDBFValue(char fieldType); static int getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname); static int getTableInfo(SHPDUMPERSTATE *state); static int projFileCreate(SHPDUMPERSTATE *state); +static int numeric_typmod_precision(int typmod); +static int numeric_typmod_scale(int typmod); /** * @brief Make appropriate formatting of a DBF value based on type. @@ -87,6 +89,24 @@ core_asprintf(const char* format, ...) return value; } +static int +numeric_typmod_precision(int typmod) +{ + return ((typmod - 4) >> 16) & 0xffff; +} + +static int +numeric_typmod_scale(int typmod) +{ + int scale = (typmod - 4) & 0x7ff; + + /* PostgreSQL stores numeric scale as an 11-bit signed value. */ + if (scale & 0x400) + scale |= ~0x7ff; + + return scale; +} + static SHPObject * create_point_empty(SHPDUMPERSTATE *state, LWPOINT *lwpoint) { @@ -1613,21 +1633,52 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) } /* - * double or numeric types: + * double types: * 700: float4 * 701: float8 - * 1700: numeric - * - * - * TODO: stricter handling of sizes */ - else if (pgfieldtype == 700 || pgfieldtype == 701 || pgfieldtype == 1700) + else if (pgfieldtype == 700 || pgfieldtype == 701) { dbffieldtype = FTDouble; dbffieldsize = 32; dbffielddecs = 10; } + /* + * Numeric type (1700). Preserve declared precision and scale + * when PostgreSQL exposes a typmod and DBF can represent it. + */ + else if (pgfieldtype == 1700) + { + dbffieldtype = FTDouble; + dbffieldsize = 32; + dbffielddecs = 10; + + if (pgtypmod >= 0) + { + int precision = numeric_typmod_precision(pgtypmod); + int scale = numeric_typmod_scale(pgtypmod); + int integral_digits = precision - scale; + int dbfsize; + + if (integral_digits < 1) + integral_digits = 1; + + if (scale > 0) + dbfsize = 1 + integral_digits + 1 + scale; + else + dbfsize = 1 + precision - scale; + + if (dbfsize <= MAX_DBF_FIELD_SIZE) + { + dbffieldsize = dbfsize; + dbffielddecs = (scale > 0) ? scale : 0; + if (dbffielddecs == 0) + dbffieldtype = FTInteger; + } + } + } + /* * Boolean field, we use FTLogical */ diff --git a/regress/Makefile.in b/regress/Makefile.in index cc4b8dfff..32f6d41c2 100644 --- a/regress/Makefile.in +++ b/regress/Makefile.in @@ -57,7 +57,7 @@ check-unit: include $(builddir)/core/tests.mk include $(srcdir)/loader/tests.mk -include $(srcdir)/dumper/tests.mk +include $(builddir)/dumper/tests.mk include $(srcdir)/runtest.mk @@ -71,6 +71,7 @@ distclean: clean rm -f core/tests.mk rm -f loader/Makefile rm -f dumper/Makefile + rm -f dumper/tests.mk staged-install-sfcgal: @if test x"@SFCGAL@" != "x"; then \ diff --git a/regress/dumper/numeric.dmp b/regress/dumper/numeric.dmp new file mode 100644 index 000000000..0614d2e2c --- /dev/null +++ b/regress/dumper/numeric.dmp @@ -0,0 +1 @@ +SELECT 1.23::numeric(3,2) AS n32, 0.123456789012::numeric(12,12) AS n1212, 123::numeric(3,0) AS n30, (-123)::numeric(3,0) AS n30neg, 123.45::numeric(5,2) AS n52, 1.2345678901234::numeric AS nuntyped, ST_Point(0, 0) AS geom; diff --git a/regress/dumper/numeric_expected.dbf b/regress/dumper/numeric_expected.dbf new file mode 100644 index 000000000..fed815fc7 Binary files /dev/null and b/regress/dumper/numeric_expected.dbf differ diff --git a/regress/dumper/numeric_expected.shp b/regress/dumper/numeric_expected.shp new file mode 100644 index 000000000..0112cd743 Binary files /dev/null and b/regress/dumper/numeric_expected.shp differ diff --git a/regress/dumper/numeric_expected.shx b/regress/dumper/numeric_expected.shx new file mode 100644 index 000000000..cc0b42ae7 Binary files /dev/null and b/regress/dumper/numeric_expected.shx differ diff --git a/regress/dumper/numeric_negative_scale.dmp b/regress/dumper/numeric_negative_scale.dmp new file mode 100644 index 000000000..9820a6b38 --- /dev/null +++ b/regress/dumper/numeric_negative_scale.dmp @@ -0,0 +1 @@ +SELECT 1200::numeric(4,-2) AS n4m2, ST_Point(0, 0) AS geom; diff --git a/regress/dumper/numeric_negative_scale_expected.dbf b/regress/dumper/numeric_negative_scale_expected.dbf new file mode 100644 index 000000000..b3377c107 Binary files /dev/null and b/regress/dumper/numeric_negative_scale_expected.dbf differ diff --git a/regress/dumper/numeric_negative_scale_expected.shp b/regress/dumper/numeric_negative_scale_expected.shp new file mode 100644 index 000000000..0112cd743 Binary files /dev/null and b/regress/dumper/numeric_negative_scale_expected.shp differ diff --git a/regress/dumper/numeric_negative_scale_expected.shx b/regress/dumper/numeric_negative_scale_expected.shx new file mode 100644 index 000000000..cc0b42ae7 Binary files /dev/null and b/regress/dumper/numeric_negative_scale_expected.shx differ diff --git a/regress/dumper/tests.mk b/regress/dumper/tests.mk.in similarity index 71% rename from regress/dumper/tests.mk rename to regress/dumper/tests.mk.in index d3417dc8f..5d82f2ddf 100644 --- a/regress/dumper/tests.mk +++ b/regress/dumper/tests.mk.in @@ -4,16 +4,25 @@ # * http://postgis.net # * # * Copyright (C) 2020 Sandro Santilli +# * Copyright (C) 2026 Darafei Praliaskouski # * # * This is free software; you can redistribute and/or modify it under # * the terms of the GNU General Public Licence. See the COPYING file. # * # ********************************************************************** +POSTGIS_PGSQL_VERSION=@POSTGIS_PGSQL_VERSION@ + TESTS += \ $(top_srcdir)/regress/dumper/mfiledmp \ $(top_srcdir)/regress/dumper/literalsrid \ $(top_srcdir)/regress/dumper/realtable \ $(top_srcdir)/regress/dumper/nullsintable \ $(top_srcdir)/regress/dumper/null3d \ + $(top_srcdir)/regress/dumper/numeric \ $(top_srcdir)/regress/dumper/withclause + +ifeq ($(shell expr "$(POSTGIS_PGSQL_VERSION)" ">=" 150),1) + TESTS += \ + $(top_srcdir)/regress/dumper/numeric_negative_scale +endif ----------------------------------------------------------------------- Summary of changes: .gitignore | 2 + GNUmakefile.in | 2 +- NEWS | 2 + configure.ac | 1 + loader/pgsql2shp-core.c | 63 +++++++++++++++++++-- regress/Makefile.in | 3 +- regress/dumper/numeric.dmp | 1 + regress/dumper/numeric_expected.dbf | Bin 0 -> 293 bytes ...teralsrid_expected.shp => numeric_expected.shp} | Bin ...teralsrid_expected.shx => numeric_expected.shx} | Bin regress/dumper/numeric_negative_scale.dmp | 1 + regress/dumper/numeric_negative_scale_expected.dbf | Bin 0 -> 73 bytes ...ted.shp => numeric_negative_scale_expected.shp} | Bin ...ted.shx => numeric_negative_scale_expected.shx} | Bin regress/dumper/{tests.mk => tests.mk.in} | 9 +++ 15 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 regress/dumper/numeric.dmp create mode 100644 regress/dumper/numeric_expected.dbf copy regress/dumper/{literalsrid_expected.shp => numeric_expected.shp} (100%) copy regress/dumper/{literalsrid_expected.shx => numeric_expected.shx} (100%) create mode 100644 regress/dumper/numeric_negative_scale.dmp create mode 100644 regress/dumper/numeric_negative_scale_expected.dbf copy regress/dumper/{literalsrid_expected.shp => numeric_negative_scale_expected.shp} (100%) copy regress/dumper/{literalsrid_expected.shx => numeric_negative_scale_expected.shx} (100%) rename regress/dumper/{tests.mk => tests.mk.in} (71%) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 12:09:31 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 19:09:31 -0000 Subject: [PostGIS] #2850: Preserve scale and precision when generating shape file with pgsql2shp In-Reply-To: <053.bdf49a5f850985e5da9e511a5c685d0a@osgeo.org> References: <053.bdf49a5f850985e5da9e511a5c685d0a@osgeo.org> Message-ID: <068.73d8194cea8ada408ed0935d792354da@osgeo.org> #2850: Preserve scale and precision when generating shape file with pgsql2shp ------------------------------+----------------------------- Reporter: hopfgartner | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: utils/pgsql2shp | Version: 2.1.x Resolution: fixed | Keywords: pgsql2shp ------------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"92903a731a5dc918318e57c0746ba407d84eccdc/git" 92903a73/git]: {{{#!CommitTicketReference repository="git" revision="92903a731a5dc918318e57c0746ba407d84eccdc" loader: preserve numeric DBF metadata in pgsql2shp Decode numeric typmod precision and scale when selecting DBF field metadata so pgsql2shp preserves fixed numeric declarations that fit in the DBF field-width limit. Keep legacy 32,10 metadata for untyped numeric values. Add pgsql2shp dumper coverage for portable numeric typmods, and gate PostgreSQL 15+ negative-scale numeric coverage behind the configured PostgreSQL version. Closes #2850 Closes https://github.com/postgis/postgis/pull/1020 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 12:25:40 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 12:25:40 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-652-g65f051b33 Message-ID: <20260621192540.A59701B4769@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 65f051b339926d22ecfa5c2032d658178bb2a3e3 (commit) from 92903a731a5dc918318e57c0746ba407d84eccdc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 65f051b339926d22ecfa5c2032d658178bb2a3e3 Author: Darafei Praliaskouski Date: Sun Jun 21 23:24:17 2026 +0400 loader: quote id column in expected SQL diff --git a/regress/loader/LongOptions.sql.expected b/regress/loader/LongOptions.sql.expected index 59151e1a3..646eea3ce 100644 --- a/regress/loader/LongOptions.sql.expected +++ b/regress/loader/LongOptions.sql.expected @@ -1,7 +1,7 @@ SET CLIENT_ENCODING TO UTF8; SET STANDARD_CONFORMING_STRINGS TO ON; DROP TABLE IF EXISTS "loadedshp"; -CREATE TABLE IF NOT EXISTS "loadedshp" (gid serial PRIMARY KEY, +CREATE TABLE IF NOT EXISTS "loadedshp" ("gid" serial PRIMARY KEY, "the_geom" geometry(POINT,0)); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000000000000000000000F03F'); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000002240000000000000F0BF'); diff --git a/regress/loader/TestANALYZE.sql.expected b/regress/loader/TestANALYZE.sql.expected index 10769aea0..d43a641c2 100644 --- a/regress/loader/TestANALYZE.sql.expected +++ b/regress/loader/TestANALYZE.sql.expected @@ -1,9 +1,9 @@ SET CLIENT_ENCODING TO UTF8; SET STANDARD_CONFORMING_STRINGS TO ON; BEGIN; -CREATE TABLE "loadedshp" (gid serial, +CREATE TABLE "loadedshp" ("gid" serial, "the_geom" geometry(POINT,0)); -ALTER TABLE "loadedshp" ADD PRIMARY KEY (gid); +ALTER TABLE "loadedshp" ADD PRIMARY KEY ("gid"); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000000000000000000000F03F'); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000002240000000000000F0BF'); INSERT INTO "loadedshp" (the_geom) VALUES ('01010000000000000000002240000000000000F0BF'); ----------------------------------------------------------------------- Summary of changes: regress/loader/LongOptions.sql.expected | 2 +- regress/loader/TestANALYZE.sql.expected | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 12:33:23 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 19:33:23 -0000 Subject: [PostGIS] #5762: ST_LocateBetween with offset drops ZM In-Reply-To: <049.c224ab0e0704a7ff3e9738c48f228ccb@osgeo.org> References: <049.c224ab0e0704a7ff3e9738c48f228ccb@osgeo.org> Message-ID: <064.2a79c7db398fda097cf5c4c593b49f48@osgeo.org> #5762: ST_LocateBetween with offset drops ZM ----------------------+-------------------------- Reporter: pramsey | Owner: pramsey Type: defect | Status: new Priority: medium | Milestone: PostGIS GEOS Component: postgis | Version: master Resolution: | Keywords: ----------------------+-------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS GEOS -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 13:21:17 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 13:21:17 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-653-g633a4c566 Message-ID: <20260621202118.1EB231B5B8F@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 633a4c5663021efbd2ad8fa11f6a0e93ccda226d (commit) from 65f051b339926d22ecfa5c2032d658178bb2a3e3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 633a4c5663021efbd2ad8fa11f6a0e93ccda226d Author: Darafei Praliaskouski Date: Sun Jun 21 03:03:40 2026 +0400 Use xml2-config for fuzzer libxml links Prefer xml2-config for libxml2 linker flags in the standalone fuzzer smoke build while still allowing pkg-config as a fallback. This lets Windows buildbot environments with a private libxml2 installation provide the required library directory for geojson_import_fuzzer. Closes #6084 Closes https://github.com/postgis/postgis/pull/1080 diff --git a/fuzzers/Makefile b/fuzzers/Makefile index ebe7077e2..675e6176f 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -32,8 +32,10 @@ check: set -- $${cxx}; \ if [ "$$#" -eq 0 ] || ! command -v "$$1" >/dev/null 2>&1 || ! "$$@" --version >/dev/null 2>&1; then \ echo "C++ compiler '$${cxx}' not available; skipping fuzzer smoke check."; \ - elif ! command -v pkg-config >/dev/null 2>&1 || ! pkg-config --exists json-c proj libxml-2.0; then \ + elif ! command -v pkg-config >/dev/null 2>&1 || ! pkg-config --exists json-c proj; then \ echo "pkg-config metadata for fuzzer dependencies not found; skipping fuzzer smoke check."; \ + elif ! command -v xml2-config >/dev/null 2>&1 && ! pkg-config --exists libxml-2.0; then \ + echo "libxml2 fuzzer dependency helper not found; skipping fuzzer smoke check."; \ elif ! command -v geos-config >/dev/null 2>&1 || ! command -v gdal-config >/dev/null 2>&1; then \ echo "GEOS/GDAL fuzzer dependency helpers not found; skipping fuzzer smoke check."; \ else \ diff --git a/fuzzers/build_google_oss_fuzzers.sh b/fuzzers/build_google_oss_fuzzers.sh index b4161bd69..30a39a4c7 100755 --- a/fuzzers/build_google_oss_fuzzers.sh +++ b/fuzzers/build_google_oss_fuzzers.sh @@ -27,10 +27,15 @@ POSTGIS_BUILD_DIR="${POSTGIS_BUILD_DIR:-$POSTGIS_SOURCE_DIR}" FUZZERS_DIR="$POSTGIS_SOURCE_DIR/fuzzers" JSON_C_LIBS=$(pkg-config --libs json-c) GEOS_LIBS=$(geos-config --clibs) -PROJ_XML2_LIBS=$(pkg-config --libs proj libxml-2.0) +PROJ_LIBS=$(pkg-config --libs proj) +if command -v xml2-config >/dev/null 2>&1; then + XML2_LIBS=$(xml2-config --libs) +else + XML2_LIBS=$(pkg-config --libs libxml-2.0) +fi GDAL_CFLAGS=$(gdal-config --cflags) GDAL_LIBS=$(gdal-config --libs) -POSTGIS_FUZZER_LIBS="$JSON_C_LIBS $GEOS_LIBS $PROJ_XML2_LIBS" +POSTGIS_FUZZER_LIBS="$JSON_C_LIBS $GEOS_LIBS $PROJ_LIBS $XML2_LIBS" POSTGIS_PACKAGE_RUNTIME_LIBS="${POSTGIS_PACKAGE_RUNTIME_LIBS:-1}" target_local_cflags() ----------------------------------------------------------------------- Summary of changes: fuzzers/Makefile | 4 +++- fuzzers/build_google_oss_fuzzers.sh | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 13:21:21 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 20:21:21 -0000 Subject: [PostGIS] #6084: Winnie failing on fuzzy tests In-Reply-To: <046.33dbafa47b32d323f8a574c0f8223aeb@osgeo.org> References: <046.33dbafa47b32d323f8a574c0f8223aeb@osgeo.org> Message-ID: <061.3b872f5caa403207304fcda67418d732@osgeo.org> #6084: Winnie failing on fuzzy tests ---------------------------+--------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: QA/buildbots | Version: 3.6.x Resolution: fixed | Keywords: ---------------------------+--------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"633a4c5663021efbd2ad8fa11f6a0e93ccda226d/git" 633a4c5/git]: {{{#!CommitTicketReference repository="git" revision="633a4c5663021efbd2ad8fa11f6a0e93ccda226d" Use xml2-config for fuzzer libxml links Prefer xml2-config for libxml2 linker flags in the standalone fuzzer smoke build while still allowing pkg-config as a fallback. This lets Windows buildbot environments with a private libxml2 installation provide the required library directory for geojson_import_fuzzer. Closes #6084 Closes https://github.com/postgis/postgis/pull/1080 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 13:32:48 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 13:32:48 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-654-g4c65e7d66 Message-ID: <20260621203248.C94AB1B5DAC@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 4c65e7d664d7fb279c90f80674573b940a662dce (commit) from 633a4c5663021efbd2ad8fa11f6a0e93ccda226d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 4c65e7d664d7fb279c90f80674573b940a662dce Author: Darafei Praliaskouski Date: Sat Jun 20 22:16:20 2026 +0400 Infer geometry_columns constraints for direct views Teach geometry_columns to inherit constraint-derived geometry metadata from direct view and materialized-view columns by reading top-level rewrite-rule origin metadata. Keep expression outputs generic unless they carry an explicit typmod cast. Parse only the top-level target list so nested subqueries cannot make an expression column inherit base-table constraints. Closes #1705 Closes https://github.com/postgis/postgis/pull/1065 diff --git a/NEWS b/NEWS index 117a044bc..b3d2d98a0 100644 --- a/NEWS +++ b/NEWS @@ -100,6 +100,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed (Darafei Praliaskouski) - #3103, Add regression coverage for exact-schema find_srid and geometry_columns lookups (Darafei Praliaskouski) + - #1705, Infer constraint metadata for direct view and materialized view + geometry columns (Darafei Praliaskouski) - #6038, Avoid stale relation lookups in geometry_columns after topology objects are dropped (Darafei Praliaskouski) - #5655, [doc] Skip XML validation during `make check` when xsltproc is diff --git a/doc/using_postgis_dataman.xml b/doc/using_postgis_dataman.xml index b902f54af..d5b91fc75 100644 --- a/doc/using_postgis_dataman.xml +++ b/doc/using_postgis_dataman.xml @@ -1768,9 +1768,10 @@ SELECT populate_geometry_columns('myschema.my_special_pois'::regclass); -- set optional use_typmod argument to false SELECT populate_geometry_columns('myschema.my_special_pois'::regclass, false); -Although the old-constraint based method is still supported, a constraint-based geometry column used directly -in a view, will not register correctly in geometry_columns, as will a typmod one. -In this example we define a column using typmod and another using constraints. +Although the old constraint-based method is still supported, direct +pass-through view columns register correctly in geometry_columns +for both typmod-based and constraint-based source columns. In this example we +define a column using typmod and another using constraints. CREATE TABLE pois_ny(gid SERIAL PRIMARY KEY, poi_name text, cat text, geom geometry(POINT,4326)); SELECT AddGeometryColumn('pois_ny', 'geom_2160', 2160, 'POINT', 2, false); If we run in psql @@ -1809,20 +1810,21 @@ SELECT * SELECT f_table_name, f_geometry_column, srid, type FROM geometry_columns WHERE f_table_name = 'vw_pois_ny_parks'; -The typmod based geom view column registers correctly, -but the constraint based one does not. +Both the typmod based geom view column and the direct constraint based +view column register correctly. f_table_name | f_geometry_column | srid | type ------------------+-------------------+------+---------- vw_pois_ny_parks | geom | 4326 | POINT - vw_pois_ny_parks | geom_2160 | 0 | GEOMETRY + vw_pois_ny_parks | geom_2160 | 2160 | POINT -This may change in future versions of PostGIS, but for now -to force the constraint-based view column to register correctly, you need to do this: +If the view applies a spatial function to the geometry, such as +ST_Transform, you still need to cast the transformed +column explicitly so the view can expose the correct type and SRID: DROP VIEW vw_pois_ny_parks; CREATE VIEW vw_pois_ny_parks AS SELECT gid, poi_name, cat, geom, - geom_2160::geometry(POINT,2160) As geom_2160 + ST_Transform(geom, 2160)::geometry(POINT,2160) As geom_2160 FROM pois_ny WHERE cat = 'park'; SELECT f_table_name, f_geometry_column, srid, type diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 027170b68..d4025cda8 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -6575,6 +6575,99 @@ LANGUAGE 'sql' STABLE STRICT PARALLEL SAFE _COST_MEDIUM; -- Changed: 2.4.0 List also Parent partitioned tables -- Changed: 2.5.2 replace use of pg_constraint.consrc with pg_get_constraintdef, consrc removed pg12 +-- Extract base-column origin metadata only from a view rule's top-level target list. +-- pg_node_tree text also contains nested Query target lists for subqueries; treating +-- those as outer view columns would make expression outputs inherit constraints. +CREATE OR REPLACE FUNCTION _postgis_geometry_columns_view_column_origin( + view_rule pg_node_tree, + view_attnum smallint) +RETURNS TABLE(base_relid oid, base_attnum smallint) +AS $$ +DECLARE + rule_text text := view_rule::text; + rule_len integer := length(rule_text); + i integer := 1; + token text := ':targetList ('; + token_len integer := length(':targetList ('); + ch text; + prev_ch text; + in_quote boolean := false; + paren_depth integer := 0; + brace_depth integer := 0; + in_top_targetlist boolean := false; + entry_start integer := 0; + entry_text text; + match text[]; +BEGIN + WHILE i <= rule_len LOOP + IF NOT in_quote AND NOT in_top_targetlist + AND paren_depth = 1 + AND brace_depth = 1 + AND substr(rule_text, i, token_len) = token + THEN + in_top_targetlist := true; + paren_depth := paren_depth + 1; + i := i + token_len; + CONTINUE; + END IF; + + ch := substr(rule_text, i, 1); + + IF ch = '"' AND prev_ch IS DISTINCT FROM chr(92) THEN + in_quote := NOT in_quote; + ELSIF NOT in_quote THEN + IF in_top_targetlist + AND entry_start = 0 + AND paren_depth = 2 + AND brace_depth = 1 + AND substr(rule_text, i, 12) = '{TARGETENTRY' + THEN + entry_start := i; + END IF; + + IF ch = '(' THEN + paren_depth := paren_depth + 1; + ELSIF ch = ')' THEN + paren_depth := paren_depth - 1; + IF in_top_targetlist AND paren_depth = 1 THEN + RETURN; + END IF; + ELSIF ch = '{' THEN + brace_depth := brace_depth + 1; + ELSIF ch = '}' THEN + brace_depth := brace_depth - 1; + IF in_top_targetlist + AND entry_start > 0 + AND brace_depth = 1 + AND paren_depth = 2 + THEN + entry_text := substr(rule_text, entry_start, i - entry_start + 1); + entry_start := 0; + match := regexp_match( + entry_text, + $re$^\{TARGETENTRY :expr \{VAR [^}]*\} :resno ([0-9]+) :resname [^:]+ :ressortgroupref [0-9]+ :resorigtbl ([0-9]+) :resorigcol ([0-9]+) :resjunk false\}$re$ + ); + IF match IS NOT NULL + AND match[1]::smallint = view_attnum + AND match[2] <> '0' + AND match[3] <> '0' + THEN + base_relid := match[2]::oid; + base_attnum := match[3]::smallint; + RETURN NEXT; + RETURN; + END IF; + END IF; + END IF; + END IF; + + prev_ch := ch; + i := i + 1; + END LOOP; +END +$$ +LANGUAGE 'plpgsql' STABLE STRICT PARALLEL SAFE; + CREATE OR REPLACE VIEW geometry_columns AS WITH constraint_defs AS ( -- Trim trailing NOT VALID so metadata inference works before constraint validation (#4828). @@ -6595,6 +6688,17 @@ SELECT current_database()::character varying(256) AS f_table_catalog, JOIN pg_attribute a ON a.attrelid = c.oid AND NOT a.attisdropped JOIN pg_namespace n ON c.relnamespace = n.oid JOIN pg_type t ON a.atttypid = t.oid + -- Direct view columns have rewrite-rule target entries with origin metadata. + -- Use only top-level bare VAR target entries, so expressions keep needing explicit casts. + LEFT JOIN LATERAL ( + SELECT origin.base_relid, + origin.base_attnum + FROM pg_rewrite AS r + CROSS JOIN LATERAL _postgis_geometry_columns_view_column_origin(r.ev_action, a.attnum) AS origin + WHERE c.relkind = ANY (ARRAY['v'::"char", 'm'::"char"]) + AND r.ev_class = c.oid + AND r.rulename = '_RETURN' + ) AS vco ON true LEFT JOIN ( SELECT s.connamespace, s.conrelid, @@ -6602,7 +6706,7 @@ SELECT current_database()::character varying(256) AS f_table_catalog, (regexp_match(s.consrc, $$geometrytype\(\w+\)\s*=\s*'(\w+)'$$, 'i'))[1]::text AS type FROM constraint_defs AS s WHERE s.consrc ~* $$geometrytype\(\w+\)\s*=\s*'\w+'$$::text - ) st ON st.connamespace = n.oid AND st.conrelid = c.oid AND (a.attnum = ANY (st.conkey)) + ) st ON st.conrelid = COALESCE(vco.base_relid, c.oid) AND (COALESCE(vco.base_attnum, a.attnum) = ANY (st.conkey)) LEFT JOIN ( SELECT s.connamespace, s.conrelid, @@ -6610,7 +6714,7 @@ SELECT current_database()::character varying(256) AS f_table_catalog, (regexp_match(s.consrc, $$ndims\(\w+\)\s*=\s*(\d+)$$, 'i'))[1]::integer AS ndims FROM constraint_defs AS s WHERE s.consrc ~* $$ndims\(\w+\)\s*=\s*\d+$$::text - ) sn ON sn.connamespace = n.oid AND sn.conrelid = c.oid AND (a.attnum = ANY (sn.conkey)) + ) sn ON sn.conrelid = COALESCE(vco.base_relid, c.oid) AND (COALESCE(vco.base_attnum, a.attnum) = ANY (sn.conkey)) LEFT JOIN ( SELECT s.connamespace, s.conrelid, @@ -6618,7 +6722,7 @@ SELECT current_database()::character varying(256) AS f_table_catalog, (regexp_match(s.consrc, $$srid\(\w+\)\s*=\s*(\d+)$$, 'i'))[1]::integer As srid FROM constraint_defs AS s WHERE s.consrc ~* $$srid\(\w+\)\s*=\s*\d+$$::text - ) sr ON sr.connamespace = n.oid AND sr.conrelid = c.oid AND (a.attnum = ANY (sr.conkey)) + ) sr ON sr.conrelid = COALESCE(vco.base_relid, c.oid) AND (COALESCE(vco.base_attnum, a.attnum) = ANY (sr.conkey)) WHERE (c.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'm'::"char", 'f'::"char", 'p'::"char"])) AND NOT c.relname = 'raster_columns'::name AND t.typname = 'geometry'::name AND NOT pg_is_other_temp_schema(c.relnamespace) diff --git a/regress/core/tickets.sql b/regress/core/tickets.sql index b31490528..c8a6e69cb 100644 --- a/regress/core/tickets.sql +++ b/regress/core/tickets.sql @@ -1654,6 +1654,49 @@ SELECT f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, t ORDER BY f_table_name, f_geometry_column; DROP TABLE IF EXISTS test5829, test5978; +-- #1705, constraint-based geometry metadata for direct view columns +CREATE TABLE test1705 ( + gid integer, + geom geometry(Point, 4326), + geom_2160 geometry); +ALTER TABLE test1705 + ADD CONSTRAINT enforce_dims_geom_2160 + CHECK (st_ndims(geom_2160) = 2); +ALTER TABLE test1705 + ADD CONSTRAINT enforce_srid_geom_2160 + CHECK (st_srid(geom_2160) = 2160); +ALTER TABLE test1705 + ADD CONSTRAINT enforce_geotype_geom_2160 + CHECK (geometrytype(geom_2160) = 'POINT'::text OR geom_2160 IS NULL); +CREATE VIEW test1705_view AS + SELECT * + FROM test1705 + WHERE gid > 0; +CREATE VIEW test1705_alias_view AS + SELECT geom_2160 AS shape + FROM test1705; +CREATE VIEW test1705_buffer_view AS + SELECT ST_Buffer(geom_2160, 1) AS geom_2160 + FROM test1705; +CREATE VIEW test1705_nested_buffer_view AS + SELECT ST_Buffer(geom_2160, 1) AS geom_2160 + FROM (SELECT geom_2160 FROM test1705) AS nested; +CREATE VIEW test1705_scalar_buffer_view AS + SELECT ST_Buffer((SELECT geom_2160 FROM test1705 LIMIT 1), 1) AS geom_2160; +CREATE VIEW test1705_mixed_view AS + SELECT ST_Buffer(geom_2160, 1) AS buffered, + geom_2160 + FROM test1705; +CREATE MATERIALIZED VIEW test1705_matview AS + SELECT geom_2160 + FROM test1705; +SELECT '#1705', f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, type + FROM geometry_columns WHERE f_table_name IN ('test1705', 'test1705_view', 'test1705_alias_view', 'test1705_buffer_view', 'test1705_nested_buffer_view', 'test1705_scalar_buffer_view', 'test1705_mixed_view', 'test1705_matview') + ORDER BY f_table_name, f_geometry_column; +DROP MATERIALIZED VIEW test1705_matview; +DROP VIEW test1705_alias_view, test1705_buffer_view, test1705_nested_buffer_view, test1705_scalar_buffer_view, test1705_mixed_view, test1705_view; +DROP TABLE test1705; + -- ------------------------------------------------------------------------------------- -- #3103, geometry_columns/find_srid exact-match behavior CREATE SCHEMA test3103a; diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected index 9e968e2dd..93529c7b5 100644 --- a/regress/core/tickets_expected +++ b/regress/core/tickets_expected @@ -499,6 +499,17 @@ public.test5978.geometry SRID:4326 TYPE:POINT DIMS:2 public|test5829|geom|2|4326|GEOMETRY public|test5978|geometry|2|4326|POINT public|test5978|shape|2|4326|POINT +#1705|public|test1705|geom|2|4326|POINT +#1705|public|test1705|geom_2160|2|2160|POINT +#1705|public|test1705_alias_view|shape|2|2160|POINT +#1705|public|test1705_buffer_view|geom_2160|2|0|GEOMETRY +#1705|public|test1705_matview|geom_2160|2|2160|POINT +#1705|public|test1705_mixed_view|buffered|2|0|GEOMETRY +#1705|public|test1705_mixed_view|geom_2160|2|2160|POINT +#1705|public|test1705_nested_buffer_view|geom_2160|2|0|GEOMETRY +#1705|public|test1705_scalar_buffer_view|geom_2160|2|0|GEOMETRY +#1705|public|test1705_view|geom|2|4326|POINT +#1705|public|test1705_view|geom_2160|2|2160|POINT #3103.1|4326 #3103.2|3857 #3103.3|test3103b|3857 ----------------------------------------------------------------------- Summary of changes: NEWS | 2 + doc/using_postgis_dataman.xml | 20 ++++---- postgis/postgis.sql.in | 110 ++++++++++++++++++++++++++++++++++++++++-- regress/core/tickets.sql | 43 +++++++++++++++++ regress/core/tickets_expected | 11 +++++ 5 files changed, 174 insertions(+), 12 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 13:32:50 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 20:32:50 -0000 Subject: [PostGIS] #1705: Get constraint-based columns in views to register correctly In-Reply-To: <046.f59c33df505f5793f73572c674293d41@osgeo.org> References: <046.f59c33df505f5793f73572c674293d41@osgeo.org> Message-ID: <061.3715c1a48d7f99650a81826289a47641@osgeo.org> #1705: Get constraint-based columns in views to register correctly --------------------------+----------------------------- Reporter: robe | Owner: robe Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"4c65e7d664d7fb279c90f80674573b940a662dce/git" 4c65e7d6/git]: {{{#!CommitTicketReference repository="git" revision="4c65e7d664d7fb279c90f80674573b940a662dce" Infer geometry_columns constraints for direct views Teach geometry_columns to inherit constraint-derived geometry metadata from direct view and materialized-view columns by reading top-level rewrite-rule origin metadata. Keep expression outputs generic unless they carry an explicit typmod cast. Parse only the top-level target list so nested subqueries cannot make an expression column inherit base-table constraints. Closes #1705 Closes https://github.com/postgis/postgis/pull/1065 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 14:12:51 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 14:12:51 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-655-ga57ccdcac Message-ID: <20260621211251.E5BCE1B6B40@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via a57ccdcaccaceb74534024c795fabd51989ef69e (commit) from 4c65e7d664d7fb279c90f80674573b940a662dce (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a57ccdcaccaceb74534024c795fabd51989ef69e Author: Darafei Praliaskouski Date: Sat Jun 20 11:22:37 2026 +0400 pgsql2shp: avoid temp tables for query dumps Describe query exports with a zero-row derived relation and scan the same derived relation directly instead of materializing the query into a temporary table. This lets low-privilege and read-only-compatible query dumps proceed without TEMP privileges while preserving the existing table export path. Add a dumper regression that revokes TEMP on the regression database and exports a SELECT query with a trailing semicolon. Closes #2045 diff --git a/NEWS b/NEWS index b3d2d98a0..8d59c8d32 100644 --- a/NEWS +++ b/NEWS @@ -59,6 +59,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed * Enhancements * + - #2045, pgsql2shp query dumps no longer require temporary table + privileges (Darafei Praliaskouski) - #1577, [loader] Report unsupported .zip archive input before trying to open shapefile sidecar files (Darafei Praliaskouski) - #3158, Move geometry and geography typmod bit helpers out of the diff --git a/loader/pgsql2shp-core.c b/loader/pgsql2shp-core.c index 334b2b7c2..bfb80d0b8 100644 --- a/loader/pgsql2shp-core.c +++ b/loader/pgsql2shp-core.c @@ -44,7 +44,7 @@ /* Maximum DBF field width (according to ARCGIS) */ #define MAX_DBF_FIELD_SIZE 254 - +#define USERQUERY_SOURCE_ALIAS "__pgsql2shp_query" /* Prototypes */ static int reverse_points(int num_points, double *x, double *y, double *z, double *m); @@ -56,7 +56,7 @@ static SHPObject *create_multipolygon(SHPDUMPERSTATE *state, LWMPOLY *lwmultipol static SHPObject *create_linestring(SHPDUMPERSTATE *state, LWLINE *lwlinestring); static SHPObject *create_multilinestring(SHPDUMPERSTATE *state, LWMLINE *lwmultilinestring); static char *nullDBFValue(char fieldType); -static int getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname); +static int getMaxFieldSize(SHPDUMPERSTATE *state, char *fname); static int getTableInfo(SHPDUMPERSTATE *state); static int projFileCreate(SHPDUMPERSTATE *state); static int numeric_typmod_precision(int typmod); @@ -566,45 +566,94 @@ is_clockwise(int num_points, double *x, double *y, double *z) } } +static char * +trim_user_query(const char *usrquery) +{ + char *query = strdup(usrquery); + char *end; + + if (!query) + return NULL; + + end = query + strlen(query); + + while (end > query && isspace((unsigned char)end[-1])) + end--; + + while (end > query && end[-1] == ';') + { + end--; + while (end > query && isspace((unsigned char)end[-1])) + end--; + } + + *end = '\0'; + return query; +} + +static char * +ShpDumperGetDataSource(SHPDUMPERSTATE *state, const char *alias) +{ + char *source; + + if (state->config->usrquery) + { + char *query = trim_user_query(state->config->usrquery); + if (!query) + return NULL; + source = core_asprintf("(%s) AS \"%s\"", query, alias ? alias : USERQUERY_SOURCE_ALIAS); + free(query); + return source; + } + + if (state->schema) + source = core_asprintf( + "\"%s\".\"%s\"%s%s", state->schema, state->table, alias ? " AS " : "", alias ? alias : ""); + else + source = core_asprintf("\"%s\"%s%s", state->table, alias ? " AS " : "", alias ? alias : ""); + + return source; +} /* - * Return the maximum octet_length from given table. + * Return the maximum octet_length from the selected source. * Return -1 on error. */ static int -getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname) +getMaxFieldSize(SHPDUMPERSTATE *state, char *fname) { int size; + char *source; + char *quoted; stringbuffer_t query; - PGresult *res; + PGresult *res = NULL; /*( this is ugly: don't forget counting the length */ /* when changing the fixed query strings ) */ + source = ShpDumperGetDataSource(state, NULL); + quoted = quote_identifier(fname); + if (!source || !quoted) + { + free(source); + free(quoted); + return -1; + } + stringbuffer_init(&query); - if ( schema ) - { - stringbuffer_aprintf( - &query, - "select max(octet_length(\"%s\"::text)) from \"%s\".\"%s\"", - fname, schema, table); - } - else - { - stringbuffer_aprintf( - &query, - "select max(octet_length(\"%s\"::text)) from \"%s\"", - fname, table); - } + stringbuffer_aprintf(&query, "select max(octet_length(%s::text)) from %s", quoted, source); + free(quoted); + free(source); LWDEBUGF(4, "maxFieldLenQuery: %s\n", stringbuffer_getstring(&query)); - res = PQexec(conn, stringbuffer_getstring(&query)); + res = PQexec(state->conn, stringbuffer_getstring(&query)); stringbuffer_release(&query); if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) { - printf( _("Querying for maximum field length: %s"), - PQerrorMessage(conn)); + printf(_("Querying for maximum field length: %s"), PQerrorMessage(state->conn)); + if (res) + PQclear(res); return -1; } @@ -775,7 +824,26 @@ projFileCreate(SHPDUMPERSTATE *state) * Escaping quotes in the schema and table in query may not be necessary except to prevent malicious attacks * or should someone be crazy enough to have quotes or other weird character in their table, column or schema names **************************************************/ - if (schema) + if (state->config->usrquery) + { + char *source = ShpDumperGetDataSource(state, "g"); + char *quoted_geo_col_name = quote_identifier(geo_col_name); + if (!source || !quoted_geo_col_name) + { + free(source); + free(quoted_geo_col_name); + snprintf(state->message, SHPDUMPERMSGLEN, _("WARNING: Out of memory building prj query")); + return SHPDUMPERWARN; + } + query = core_asprintf( + "SELECT COALESCE((SELECT CASE WHEN COUNT(DISTINCT sr.srid) > 1 THEN 'm' ELSE MAX(sr.srtext) END As srtext " + " FROM %s INNER JOIN spatial_ref_sys sr ON sr.srid = ST_SRID((g.%s)::geometry)) , ' ') As srtext ", + source, + quoted_geo_col_name); + free(quoted_geo_col_name); + free(source); + } + else if (schema) { PQescapeStringConn(state->conn, esc_schema, schema, strlen(schema), &error); query = core_asprintf( @@ -803,8 +871,12 @@ projFileCreate(SHPDUMPERSTATE *state) if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) { - snprintf(state->message, SHPDUMPERMSGLEN, _("WARNING: Could not execute prj query: %s"), PQresultErrorMessage(res)); - PQclear(res); + snprintf(state->message, + SHPDUMPERMSGLEN, + _("WARNING: Could not execute prj query: %s"), + res ? PQresultErrorMessage(res) : PQerrorMessage(state->conn)); + if (res) + PQclear(res); free(query); return SHPDUMPERWARN; } @@ -905,8 +977,28 @@ getTableInfo(SHPDUMPERSTATE *state) if (state->geo_col_name) { + if (state->config->usrquery) + { + char *source = ShpDumperGetDataSource(state, NULL); + char *quoted_geo_col_name = quote_identifier(state->geo_col_name); + if (!source || !quoted_geo_col_name) + { + free(source); + free(quoted_geo_col_name); + snprintf(state->message, SHPDUMPERMSGLEN, _("ERROR: Out of memory building table metadata query")); + return SHPDUMPERERR; + } + + query = core_asprintf( + "SELECT count(1), max(ST_zmflag(%s::geometry)), geometrytype(%s::geometry) FROM %s GROUP BY 3", + quoted_geo_col_name, + quoted_geo_col_name, + source); + free(quoted_geo_col_name); + free(source); + } /* Include geometry information */ - if (state->schema) + else if (state->schema) { query = core_asprintf( "SELECT count(1), max(ST_zmflag(\"%s\"::geometry)), geometrytype(\"%s\"::geometry) FROM \"%s\".\"%s\" GROUP BY 3", @@ -922,7 +1014,18 @@ getTableInfo(SHPDUMPERSTATE *state) else { /* Otherwise... just a row count will do */ - if (state->schema) + if (state->config->usrquery) + { + char *source = ShpDumperGetDataSource(state, NULL); + if (!source) + { + snprintf(state->message, SHPDUMPERMSGLEN, _("ERROR: Out of memory building table metadata query")); + return SHPDUMPERERR; + } + query = core_asprintf("SELECT count(1) FROM %s", source); + free(source); + } + else if (state->schema) { query = core_asprintf( "SELECT count(1) FROM \"%s\".\"%s\"", @@ -941,10 +1044,14 @@ getTableInfo(SHPDUMPERSTATE *state) res = PQexec(state->conn, query); free(query); - if (PQresultStatus(res) != PGRES_TUPLES_OK) + if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) { - snprintf(state->message, SHPDUMPERMSGLEN, _("ERROR: Could not execute table metadata query: %s"), PQresultErrorMessage(res)); - PQclear(res); + snprintf(state->message, + SHPDUMPERMSGLEN, + _("ERROR: Could not execute table metadata query: %s"), + res ? PQresultErrorMessage(res) : PQerrorMessage(state->conn)); + if (res) + PQclear(res); return SHPDUMPERERR; } @@ -1338,11 +1445,12 @@ ShpDumperConnectDatabase(SHPDUMPERSTATE *state) int ShpDumperOpenTable(SHPDUMPERSTATE *state) { - PGresult *res; + PGresult *res = NULL; char buf[256]; int gidfound = 0, i, j, status; int ret = SHPDUMPEROK; + int fieldtuples; stringbuffer_t sb; char *quoted = NULL; @@ -1355,25 +1463,39 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) return SHPDUMPERERR; } - /* If a user-defined query has been specified, create and point the state to our new table */ + /* If a user-defined query has been specified, describe its output columns + * without materializing it. */ if (state->config->usrquery) { - state->table = core_asprintf("__pgsql2shp%lu_tmp_table", (long)getpid()); - stringbuffer_init(&sb); - stringbuffer_aprintf(&sb, - "CREATE TEMP TABLE \"%s\" AS %s", - state->table, state->config->usrquery); - res = PQexec(state->conn, stringbuffer_getstring(&sb)); - stringbuffer_release(&sb); - - /* Execute the code to create the table */ - if (PQresultStatus(res) != PGRES_COMMAND_OK) + char *source = ShpDumperGetDataSource(state, NULL); + if (!source) { - snprintf(state->message, SHPDUMPERMSGLEN, _("Error executing user query: %s"), PQresultErrorMessage(res)); - PQclear(res); + snprintf(state->message, SHPDUMPERMSGLEN, _("Out of memory building user query")); + return SHPDUMPERERR; + } + state->table = strdup(USERQUERY_SOURCE_ALIAS); + if (!state->table) + { + free(source); + snprintf(state->message, SHPDUMPERMSGLEN, _("Out of memory building user query")); + return SHPDUMPERERR; + } + stringbuffer_init(&sb); + stringbuffer_aprintf(&sb, "SELECT * FROM %s LIMIT 0", source); + free(source); + + res = PQexec(state->conn, stringbuffer_getstring(&sb)); + stringbuffer_release(&sb); + if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) + { + snprintf(state->message, + SHPDUMPERMSGLEN, + _("Error executing user query: %s"), + res ? PQresultErrorMessage(res) : PQerrorMessage(state->conn)); + if (res) + PQclear(res); return SHPDUMPERERR; } - PQclear(res); } else { @@ -1383,51 +1505,58 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) state->schema = strdup(state->config->schema); } - stringbuffer_init(&sb); - /* Get the list of columns and their types for the selected table */ - if (state->schema) + if (!state->config->usrquery) { - stringbuffer_aprintf(&sb, - "SELECT a.attname, a.atttypid, " - "a.atttypmod, a.attlen FROM " - "pg_attribute a, pg_class c, pg_namespace n WHERE " - "n.nspname = '%s' AND a.attrelid = c.oid AND " - "n.oid = c.relnamespace AND " - "a.atttypid != 0 AND " - "a.attnum > 0 AND c.relname = '%s'", - state->schema, - state->table); - } - else - { - stringbuffer_aprintf(&sb, - "SELECT a.attname, a.atttypid, " - "a.atttypmod, a.attlen FROM " - "pg_attribute a, pg_class c WHERE " - "a.attrelid = c.oid and a.attnum > 0 AND " - "a.atttypid != 0 AND " - "c.relname = '%s' AND " - "pg_catalog.pg_table_is_visible(c.oid)", - state->table); - } + stringbuffer_init(&sb); + /* Get the list of columns and their types for the selected table */ + if (state->schema) + { + stringbuffer_aprintf(&sb, + "SELECT a.attname, a.atttypid, " + "a.atttypmod, a.attlen FROM " + "pg_attribute a, pg_class c, pg_namespace n WHERE " + "n.nspname = '%s' AND a.attrelid = c.oid AND " + "n.oid = c.relnamespace AND " + "a.atttypid != 0 AND " + "a.attnum > 0 AND c.relname = '%s'", + state->schema, + state->table); + } + else + { + stringbuffer_aprintf(&sb, + "SELECT a.attname, a.atttypid, " + "a.atttypmod, a.attlen FROM " + "pg_attribute a, pg_class c WHERE " + "a.attrelid = c.oid and a.attnum > 0 AND " + "a.atttypid != 0 AND " + "c.relname = '%s' AND " + "pg_catalog.pg_table_is_visible(c.oid)", + state->table); + } - LWDEBUGF(3, "query is: %s\n", stringbuffer_getstring(&sb)); + LWDEBUGF(3, "query is: %s\n", stringbuffer_getstring(&sb)); - res = PQexec(state->conn, stringbuffer_getstring(&sb)); - stringbuffer_release(&sb); + res = PQexec(state->conn, stringbuffer_getstring(&sb)); + stringbuffer_release(&sb); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - snprintf(state->message, SHPDUMPERMSGLEN, _("Error querying for attributes: %s"), PQresultErrorMessage(res)); - PQclear(res); - return SHPDUMPERERR; - } + if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) + { + snprintf(state->message, + SHPDUMPERMSGLEN, + _("Error querying for attributes: %s"), + res ? PQresultErrorMessage(res) : PQerrorMessage(state->conn)); + if (res) + PQclear(res); + return SHPDUMPERERR; + } - if (!PQntuples(res)) - { - snprintf(state->message, SHPDUMPERMSGLEN, _("Table %s does not exist"), state->table); - PQclear(res); - return SHPDUMPERERR; + if (!PQntuples(res)) + { + snprintf(state->message, SHPDUMPERMSGLEN, _("Table %s does not exist"), state->table); + PQclear(res); + return SHPDUMPERERR; + } } /* If a shapefile name was specified, use it. Otherwise simply use the table name. */ @@ -1465,15 +1594,16 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) * Scan the result setting fields to be returned in mainscan * query, filling the type_ary, and creating .dbf and .shp files. */ - state->dbffieldnames = malloc(sizeof(char *) * PQntuples(res)); - state->dbffieldtypes = malloc(sizeof(int) * PQntuples(res)); - state->pgfieldnames = malloc(sizeof(char *) * PQntuples(res)); - state->pgfieldlens = malloc(sizeof(int) * PQntuples(res)); - state->pgfieldtypmods = malloc(sizeof(int) * PQntuples(res)); + fieldtuples = state->config->usrquery ? PQnfields(res) : PQntuples(res); + state->dbffieldnames = malloc(sizeof(char *) * fieldtuples); + state->dbffieldtypes = malloc(sizeof(int) * fieldtuples); + state->pgfieldnames = malloc(sizeof(char *) * fieldtuples); + state->pgfieldlens = malloc(sizeof(int) * fieldtuples); + state->pgfieldtypmods = malloc(sizeof(int) * fieldtuples); state->fieldcount = 0; int tmpint = 1; - for (i = 0; i < PQntuples(res); i++) + for (i = 0; i < fieldtuples; i++) { char *ptr; @@ -1483,10 +1613,20 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) int dbffieldtype, dbffieldsize, dbffielddecs; char *dbffieldname; - pgfieldname = PQgetvalue(res, i, 0); - pgfieldtype = atoi(PQgetvalue(res, i, 1)); - pgtypmod = atoi(PQgetvalue(res, i, 2)); - pgfieldlen = atoi(PQgetvalue(res, i, 3)); + if (state->config->usrquery) + { + pgfieldname = PQfname(res, i); + pgfieldtype = PQftype(res, i); + pgtypmod = PQfmod(res, i); + pgfieldlen = PQfsize(res, i); + } + else + { + pgfieldname = PQgetvalue(res, i, 0); + pgfieldtype = atoi(PQgetvalue(res, i, 1)); + pgtypmod = atoi(PQgetvalue(res, i, 2)); + pgfieldlen = atoi(PQgetvalue(res, i, 3)); + } dbffieldtype = -1; dbffieldsize = 0; dbffielddecs = 0; @@ -1785,7 +1925,7 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) * we can do is query the table for the maximum field * size. */ - dbffieldsize = getMaxFieldSize(state->conn, state->schema, state->table, pgfieldname); + dbffieldsize = getMaxFieldSize(state, pgfieldname); if (dbffieldsize == -1) { free(dbffieldname); @@ -1921,7 +2061,17 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) if (state->config->binary) stringbuffer_append(&sb, "BINARY "); - stringbuffer_append(&sb, "CURSOR FOR SELECT "); + if (state->config->usrquery) + { + /* A holdable cursor materializes the export rows at COMMIT, letting + * us count and rewind the cursor without requiring CREATE TEMP + * privileges or re-running the final user query. */ + stringbuffer_append(&sb, "SCROLL CURSOR WITH HOLD FOR SELECT "); + } + else + { + stringbuffer_append(&sb, "CURSOR FOR SELECT "); + } for (i = 0; i < state->fieldcount; i++) { @@ -1972,17 +2122,17 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) free(quoted); } - if (state->schema) { - stringbuffer_aprintf(&sb, - " FROM \"%s\".\"%s\"", - state->schema, state->table); - } - else - { - stringbuffer_aprintf(&sb, - " FROM \"%s\"", - state->table); + char *source = ShpDumperGetDataSource(state, NULL); + if (!source) + { + snprintf(state->message, SHPDUMPERMSGLEN, _("Out of memory building main scan query")); + PQclear(res); + stringbuffer_release(&sb); + return SHPDUMPERERR; + } + stringbuffer_aprintf(&sb, " FROM %s", source); + free(source); } /* Order by 'gid' (if found) */ @@ -2003,8 +2153,12 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) res = PQexec(state->conn, "BEGIN"); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - snprintf(state->message, SHPDUMPERMSGLEN, _("Error starting transaction: %s"), PQresultErrorMessage(res)); - PQclear(res); + snprintf(state->message, + SHPDUMPERMSGLEN, + _("Error starting transaction: %s"), + res ? PQresultErrorMessage(res) : PQerrorMessage(state->conn)); + if (res) + PQclear(res); return SHPDUMPERERR; } @@ -2016,13 +2170,60 @@ ShpDumperOpenTable(SHPDUMPERSTATE *state) res = PQexec(state->conn, state->main_scan_query); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - snprintf(state->message, SHPDUMPERMSGLEN, _("Error executing main scan query: %s"), PQresultErrorMessage(res)); - PQclear(res); + snprintf(state->message, + SHPDUMPERMSGLEN, + _("Error executing main scan query: %s"), + res ? PQresultErrorMessage(res) : PQerrorMessage(state->conn)); + if (res) + PQclear(res); return SHPDUMPERERR; } PQclear(res); + if (state->config->usrquery) + { + res = PQexec(state->conn, "COMMIT"); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + snprintf(state->message, + SHPDUMPERMSGLEN, + _("Error materializing main scan query: %s"), + res ? PQresultErrorMessage(res) : PQerrorMessage(state->conn)); + if (res) + PQclear(res); + return SHPDUMPERERR; + } + PQclear(res); + + res = PQexec(state->conn, "MOVE FORWARD ALL FROM cur"); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + snprintf(state->message, + SHPDUMPERMSGLEN, + _("Error counting main scan cursor: %s"), + res ? PQresultErrorMessage(res) : PQerrorMessage(state->conn)); + if (res) + PQclear(res); + return SHPDUMPERERR; + } + state->rowcount = atoi(PQcmdTuples(res)); + PQclear(res); + + res = PQexec(state->conn, "MOVE ABSOLUTE 0 FROM cur"); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + snprintf(state->message, + SHPDUMPERMSGLEN, + _("Error rewinding main scan cursor: %s"), + res ? PQresultErrorMessage(res) : PQerrorMessage(state->conn)); + if (res) + PQclear(res); + return SHPDUMPERERR; + } + PQclear(res); + } + /* Setup initial scan state */ state->currow = 0; state->curresrow = 0; @@ -2064,10 +2265,15 @@ int ShpLoaderGenerateShapeRow(SHPDUMPERSTATE *state) PQclear(state->fetchres); state->fetchres = PQexec(state->conn, state->fetch_query); - if (PQresultStatus(state->fetchres) != PGRES_TUPLES_OK) + if (!state->fetchres || PQresultStatus(state->fetchres) != PGRES_TUPLES_OK) { - snprintf(state->message, SHPDUMPERMSGLEN, _("Error executing fetch query: %s"), PQresultErrorMessage(state->fetchres)); - PQclear(state->fetchres); + snprintf(state->message, + SHPDUMPERMSGLEN, + _("Error executing fetch query: %s"), + state->fetchres ? PQresultErrorMessage(state->fetchres) : PQerrorMessage(state->conn)); + if (state->fetchres) + PQclear(state->fetchres); + state->fetchres = NULL; return SHPDUMPERERR; } diff --git a/regress/dumper/noquerytemp-post.sql b/regress/dumper/noquerytemp-post.sql new file mode 100644 index 000000000..a603e5ccd --- /dev/null +++ b/regress/dumper/noquerytemp-post.sql @@ -0,0 +1,8 @@ +do $$ +begin + execute format('grant temporary on database %I to %I', current_database(), current_user); + execute format('grant temporary on database %I to public', current_database()); +end; +$$; +drop table c; +delete from spatial_ref_sys where srid = 1; diff --git a/regress/dumper/noquerytemp-pre.sql b/regress/dumper/noquerytemp-pre.sql new file mode 100644 index 000000000..ba8c55339 --- /dev/null +++ b/regress/dumper/noquerytemp-pre.sql @@ -0,0 +1,12 @@ +insert into spatial_ref_sys(srid,srtext) values (1,'fake["srs"],text'); +create table c (i int, g geometry, b boolean, """qColumn" varchar(20)); +insert into c values (1,'SRID=1;POINT(0 0)', true, 'quote test'); + +-- Query dumps must describe and scan the SELECT without creating temp tables. +-- Revoking TEMP makes the regression fail if pgsql2shp materializes the query. +do $$ +begin + execute format('revoke temporary on database %I from %I', current_database(), current_user); + execute format('revoke temporary on database %I from public', current_database()); +end; +$$; diff --git a/regress/dumper/noquerytemp.dmp b/regress/dumper/noquerytemp.dmp new file mode 100644 index 000000000..8a32f2a5e --- /dev/null +++ b/regress/dumper/noquerytemp.dmp @@ -0,0 +1 @@ +select * from c; diff --git a/regress/dumper/noquerytemp_expected.dbf b/regress/dumper/noquerytemp_expected.dbf new file mode 100644 index 000000000..f0147df7c Binary files /dev/null and b/regress/dumper/noquerytemp_expected.dbf differ diff --git a/regress/dumper/noquerytemp_expected.prj b/regress/dumper/noquerytemp_expected.prj new file mode 100644 index 000000000..ab83d5d0e --- /dev/null +++ b/regress/dumper/noquerytemp_expected.prj @@ -0,0 +1 @@ +fake["srs"],text \ No newline at end of file diff --git a/regress/dumper/noquerytemp_expected.shp b/regress/dumper/noquerytemp_expected.shp new file mode 100644 index 000000000..0112cd743 Binary files /dev/null and b/regress/dumper/noquerytemp_expected.shp differ diff --git a/regress/dumper/noquerytemp_expected.shx b/regress/dumper/noquerytemp_expected.shx new file mode 100644 index 000000000..cc0b42ae7 Binary files /dev/null and b/regress/dumper/noquerytemp_expected.shx differ diff --git a/regress/dumper/tests.mk.in b/regress/dumper/tests.mk.in index 5d82f2ddf..7b852ffd7 100644 --- a/regress/dumper/tests.mk.in +++ b/regress/dumper/tests.mk.in @@ -17,6 +17,7 @@ TESTS += \ $(top_srcdir)/regress/dumper/mfiledmp \ $(top_srcdir)/regress/dumper/literalsrid \ $(top_srcdir)/regress/dumper/realtable \ + $(top_srcdir)/regress/dumper/noquerytemp \ $(top_srcdir)/regress/dumper/nullsintable \ $(top_srcdir)/regress/dumper/null3d \ $(top_srcdir)/regress/dumper/numeric \ ----------------------------------------------------------------------- Summary of changes: NEWS | 2 + loader/pgsql2shp-core.c | 426 +++++++++++++++------ regress/dumper/noquerytemp-post.sql | 8 + regress/dumper/noquerytemp-pre.sql | 12 + regress/dumper/noquerytemp.dmp | 1 + ...table_expected.dbf => noquerytemp_expected.dbf} | Bin ...lsrid_expected.prj => noquerytemp_expected.prj} | 0 ...lsrid_expected.shp => noquerytemp_expected.shp} | Bin ...lsrid_expected.shx => noquerytemp_expected.shx} | Bin regress/dumper/tests.mk.in | 1 + 10 files changed, 340 insertions(+), 110 deletions(-) create mode 100644 regress/dumper/noquerytemp-post.sql create mode 100644 regress/dumper/noquerytemp-pre.sql create mode 100644 regress/dumper/noquerytemp.dmp copy regress/dumper/{realtable_expected.dbf => noquerytemp_expected.dbf} (100%) copy regress/dumper/{literalsrid_expected.prj => noquerytemp_expected.prj} (100%) copy regress/dumper/{literalsrid_expected.shp => noquerytemp_expected.shp} (100%) copy regress/dumper/{literalsrid_expected.shx => noquerytemp_expected.shx} (100%) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 14:12:53 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 21:12:53 -0000 Subject: [PostGIS] #2045: pgsql2shp should not require temp table creation privs when dumping a query In-Reply-To: <046.3581ba5aa86ecb0845354540c6dcf1cb@osgeo.org> References: <046.3581ba5aa86ecb0845354540c6dcf1cb@osgeo.org> Message-ID: <061.f3e6b1d0034533febbf6dc9d1ab01fbc@osgeo.org> #2045: pgsql2shp should not require temp table creation privs when dumping a query ----------------------------------+----------------------------- Reporter: strk | Owner: stefanpetrea Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: utils/loader-dumper | Version: master Resolution: fixed | Keywords: gsoc ----------------------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"a57ccdcaccaceb74534024c795fabd51989ef69e/git" a57ccdca/git]: {{{#!CommitTicketReference repository="git" revision="a57ccdcaccaceb74534024c795fabd51989ef69e" pgsql2shp: avoid temp tables for query dumps Describe query exports with a zero-row derived relation and scan the same derived relation directly instead of materializing the query into a temporary table. This lets low-privilege and read-only-compatible query dumps proceed without TEMP privileges while preserving the existing table export path. Add a dumper regression that revokes TEMP on the regression database and exports a SELECT query with a trailing semicolon. Closes #2045 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 14:21:47 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 14:21:47 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-656-g226a7ef5f Message-ID: <20260621212147.910CB1B704D@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 226a7ef5fef9669372a5d63de0d6ef23dabb4929 (commit) from a57ccdcaccaceb74534024c795fabd51989ef69e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 226a7ef5fef9669372a5d63de0d6ef23dabb4929 Author: Darafei Praliaskouski Date: Sat Jun 20 02:56:51 2026 +0400 Fix X3D 2D polygon serialization Emit Coordinate child nodes for indexed 2D line and polygon X3D output instead of writing bare coordinate text into the parent element. Reuse the indexed face output path for polygons inside geometry collections so collection wrapping produces a valid Shape payload. Closes #2838 Closes https://github.com/postgis/postgis/pull/987 diff --git a/NEWS b/NEWS index 8d59c8d32..36b96fe56 100644 --- a/NEWS +++ b/NEWS @@ -94,6 +94,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed when padding is not requested (Darafei Praliaskouski) - #2623, Generate a pgsql2shp GID field when exporting geometry-only shapefiles (Darafei Praliaskouski) + - #2838, Emit valid X3D Coordinate nodes for 2D polygon output + (Darafei Praliaskouski) - Fix WKB and TWKB parser resource exhaustion on malformed input (Darafei Praliaskouski) - #2850, Preserve pgsql2shp numeric precision and scale in DBF metadata diff --git a/liblwgeom/cunit/cu_out_x3d.c b/liblwgeom/cunit/cu_out_x3d.c index 8a0ffa1db..2418e31c2 100644 --- a/liblwgeom/cunit/cu_out_x3d.c +++ b/liblwgeom/cunit/cu_out_x3d.c @@ -3,6 +3,7 @@ * PostGIS - Spatial Types for PostgreSQL * http://postgis.net * Copyright 2011-2016 Regina Obe + * Copyright 2026 Darafei Praliaskouski * * This is free software; you can redistribute and/or modify it under * the terms of the GNU General Public Licence. See the COPYING file. @@ -75,12 +76,25 @@ static void out_x3d3_test_geoms(void) "", 0, 0); + /* 2D Linestring */ + do_x3d3_test("LINESTRING(0 1,2 3,4 5)", + "", + 0, + 0); + /* Polygon **/ do_x3d3_test( "POLYGON((15 10 3,13.536 6.464 3,10 5 3,6.464 6.464 3,5 10 3,6.464 13.536 3,10 15 3,13.536 13.536 3,15 10 3))", "", 3, 0); + /* 2D Polygon */ + do_x3d3_test( + "POLYGON((0 0,1 0,1 1,0 0))", + "", + 0, + 0); + /* TODO: Polygon - with internal ring - the answer is clearly wrong */ /** do_x3d3_test( "POLYGON((0 1 3,2 3 3,4 5 3,0 1 3),(6 7 3,8 9 3,10 11 3,6 7 3))", @@ -104,23 +118,38 @@ static void out_x3d3_test_geoms(void) "", 0, 0); + /* 2D Multiline */ + do_x3d3_test( + "MULTILINESTRING((0 1,2 3,4 5),(6 7,8 9,10 11))", + "", + 0, + 0); + /* MultiPolygon */ do_x3d3_test( "MULTIPOLYGON(((0 1 1,2 3 1,4 5 1,0 1 1)),((6 7 1,8 9 1,10 11 1,6 7 1)))", "", 0, 0); + /* 2D MultiPolygon */ + do_x3d3_test( + "MULTIPOLYGON(((0 1,2 3,4 5,0 1)),((6 7,8 9,10 11,6 7)))", + "", + 0, + 0); + /* PolyhedralSurface */ do_x3d3_test( "POLYHEDRALSURFACE( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)), ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)), ((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)), ((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)), ((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )", "", 0, 0); - /* TODO: returns garbage at moment correctly implement GeometryCollection -- */ - /** do_x3d3_test( - "GEOMETRYCOLLECTION(POINT(0 1 3),LINESTRING(2 3 3,4 5 3))", - "", - NULL, 0); **/ + /* GeometryCollection with 2D Polygon */ + do_x3d3_test( + "GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 0)))", + "", + 0, + 0); /* TODO: Implement Empty GeometryCollection correctly or throw a not-implemented */ /** do_x3d3_test( diff --git a/liblwgeom/lwout_x3d.c b/liblwgeom/lwout_x3d.c index b1a8d7be4..4737fd09e 100644 --- a/liblwgeom/lwout_x3d.c +++ b/liblwgeom/lwout_x3d.c @@ -19,6 +19,7 @@ ********************************************************************** * * Copyright 2011-2017 Arrival 3D, Regina Obe + * Copyright 2026 Darafei Praliaskouski * **********************************************************************/ @@ -117,13 +118,13 @@ asx3d3_point_sb(const LWPOINT *point, stringbuffer_t *sb) { /** for point we just output the coordinates **/ - return ptarray_to_x3d3_sb(point->point, precision, opts, 0, sb); + return ptarray_to_x3d3_sb(point->point, precision, opts, 0, LW_FALSE, sb); } static int -asx3d3_line_coords_sb(const LWLINE *line, int precision, int opts, stringbuffer_t *sb) +asx3d3_line_coords_sb(const LWLINE *line, int precision, int opts, int force_3d, stringbuffer_t *sb) { - return ptarray_to_x3d3_sb(line->points, precision, opts, lwline_is_closed(line), sb); + return ptarray_to_x3d3_sb(line->points, precision, opts, lwline_is_closed(line), force_3d, sb); } /* Calculate the coordIndex property of the IndexedLineSet for the multilinestring @@ -238,8 +239,7 @@ asx3d3_line_sb(const LWLINE *line, else stringbuffer_aprintf(sb, ""); @@ -259,7 +259,7 @@ asx3d3_poly_sb(const LWPOLY *poly, for (i=0; inrings; i++) { if (i) stringbuffer_aprintf(sb, " "); /* inner ring points start */ - ptarray_to_x3d3_sb(poly->rings[i], precision, opts, 1, sb); + ptarray_to_x3d3_sb(poly->rings[i], precision, opts, 1, LW_TRUE, sb); } return LW_SUCCESS; } @@ -271,7 +271,7 @@ asx3d3_triangle_sb(const LWTRIANGLE *triangle, __attribute__((__unused__)) const char *defid, stringbuffer_t *sb) { - return ptarray_to_x3d3_sb(triangle->points, precision, opts, 1, sb); + return ptarray_to_x3d3_sb(triangle->points, precision, opts, 1, LW_TRUE, sb); } @@ -284,6 +284,7 @@ asx3d3_multi_sb(const LWCOLLECTION *col, int precision, int opts, const char *de char *x3dtype; uint32_t i; int dimension=2; + int has_coordinate_node = LW_FALSE; if (FLAGS_GET_Z(col->flags)) dimension = 3; LWGEOM *subgeom; @@ -292,38 +293,49 @@ asx3d3_multi_sb(const LWCOLLECTION *col, int precision, int opts, const char *de switch (col->type) { - case MULTIPOINTTYPE: - x3dtype = "PointSet"; - if ( dimension == 2 ){ /** Use Polypoint2D instead **/ - x3dtype = "Polypoint2D"; - stringbuffer_aprintf(sb, "<%s %s point='", x3dtype, defid); - } - else { - stringbuffer_aprintf(sb, "<%s %s>", x3dtype, defid); - } - break; - case MULTILINETYPE: - x3dtype = "IndexedLineSet"; - stringbuffer_aprintf(sb, "<%s %s coordIndex='", x3dtype, defid); - asx3d3_mline_coordindex_sb((const LWMLINE *)col, sb); - stringbuffer_aprintf(sb, "'>"); - break; - case MULTIPOLYGONTYPE: - x3dtype = "IndexedFaceSet"; - stringbuffer_aprintf(sb, "<%s %s convex='false' coordIndex='", x3dtype, defid); - asx3d3_mpoly_coordindex_sb((const LWMPOLY *)col, sb); - stringbuffer_aprintf(sb, "'>"); - break; - default: - lwerror("asx3d3_multi_buf: '%s' geometry type not supported", lwtype_name(col->type)); - return 0; - } - if (dimension == 3){ - if ( X3D_USE_GEOCOORDS(opts) ) - stringbuffer_aprintf(sb, ""); + has_coordinate_node = LW_TRUE; + break; + case MULTIPOLYGONTYPE: + x3dtype = "IndexedFaceSet"; + stringbuffer_aprintf(sb, "<%s %s convex='false' coordIndex='", x3dtype, defid); + asx3d3_mpoly_coordindex_sb((const LWMPOLY *)col, sb); + stringbuffer_aprintf(sb, "'>"); + has_coordinate_node = LW_TRUE; + break; + default: + lwerror("asx3d3_multi_buf: '%s' geometry type not supported", lwtype_name(col->type)); + return 0; + } + + /* Indexed X3D nodes always need a Coordinate child; only 2D multipoints + * can store coordinates directly on the Polypoint2D node. */ + if (has_coordinate_node) + { + if (X3D_USE_GEOCOORDS(opts)) + stringbuffer_aprintf(sb, + "ngeoms; i++) { @@ -335,7 +347,7 @@ asx3d3_multi_sb(const LWCOLLECTION *col, int precision, int opts, const char *de } else if (subgeom->type == LINETYPE) { - asx3d3_line_coords_sb((LWLINE*)subgeom, precision, opts, sb); + asx3d3_line_coords_sb((LWLINE *)subgeom, precision, opts, has_coordinate_node, sb); stringbuffer_aprintf(sb, " "); } else if (subgeom->type == POLYGONTYPE) @@ -346,7 +358,8 @@ asx3d3_multi_sb(const LWCOLLECTION *col, int precision, int opts, const char *de } /* Close outmost tag */ - if (dimension == 3){ + if (has_coordinate_node) + { stringbuffer_aprintf(sb, "' />", x3dtype); } else { stringbuffer_aprintf(sb, "' />"); } @@ -474,7 +487,9 @@ asx3d3_collection_sb(const LWCOLLECTION *col, int precision, int opts, const cha } else if ( subgeom->type == POLYGONTYPE ) { - asx3d3_poly_sb((LWPOLY *)subgeom, precision, opts, 0, defid, sb); + LWCOLLECTION *tmp = (LWCOLLECTION *)lwgeom_as_multi(subgeom); + asx3d3_multi_sb(tmp, precision, opts, defid, sb); + lwcollection_free(tmp); } else if ( subgeom->type == TINTYPE ) { @@ -508,14 +523,14 @@ asx3d3_collection_sb(const LWCOLLECTION *col, int precision, int opts, const cha /** In X3D3, coordinates are separated by a space separator */ static int -ptarray_to_x3d3_sb(POINTARRAY *pa, int precision, int opts, int is_closed, stringbuffer_t *sb ) +ptarray_to_x3d3_sb(POINTARRAY *pa, int precision, int opts, int is_closed, int force_3d, stringbuffer_t *sb) { uint32_t i; char x[OUT_DOUBLE_BUFFER_SIZE]; char y[OUT_DOUBLE_BUFFER_SIZE]; char z[OUT_DOUBLE_BUFFER_SIZE]; - if ( ! FLAGS_GET_Z(pa->flags) ) + if (!FLAGS_GET_Z(pa->flags) && !force_3d) { for (i=0; inpoints; i++) { @@ -537,6 +552,30 @@ ptarray_to_x3d3_sb(POINTARRAY *pa, int precision, int opts, int is_closed, strin } } } + else if (!FLAGS_GET_Z(pa->flags)) + { + for (i = 0; i < pa->npoints; i++) + { + /** Only output the point if it is not the last point of a closed object or it is a non-closed + * type **/ + if (!is_closed || i < (pa->npoints - 1)) + { + POINT2D pt; + getPoint2d_p(pa, i, &pt); + + lwprint_double(pt.x, precision, x); + lwprint_double(pt.y, precision, y); + + if (i) + stringbuffer_append_len(sb, " ", 1); + + if ((opts & LW_X3D_FLIP_XY)) + stringbuffer_aprintf(sb, "%s %s 0", y, x); + else + stringbuffer_aprintf(sb, "%s %s 0", x, y); + } + } + } else { for (i=0; inpoints; i++) diff --git a/liblwgeom/lwout_x3d.h b/liblwgeom/lwout_x3d.h index ca8c6db83..0efb67d95 100644 --- a/liblwgeom/lwout_x3d.h +++ b/liblwgeom/lwout_x3d.h @@ -19,6 +19,7 @@ ********************************************************************** * * Copyright 2011-2017 Arrival 3D, Regina Obe + * Copyright 2026 Darafei Praliaskouski * **********************************************************************/ @@ -45,4 +46,4 @@ static int asx3d3_tin_sb(const LWTIN *tin, int precision, int opts, const char * static int asx3d3_collection_sb(const LWCOLLECTION *col, int precision, int opts, const char *defid, stringbuffer_t *sb); -static int ptarray_to_x3d3_sb(POINTARRAY *pa, int precision, int opts, int is_closed, stringbuffer_t *sb ); +static int ptarray_to_x3d3_sb(POINTARRAY *pa, int precision, int opts, int is_closed, int force_3d, stringbuffer_t *sb); diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected index 93529c7b5..639472965 100644 --- a/regress/core/tickets_expected +++ b/regress/core/tickets_expected @@ -423,8 +423,8 @@ ERROR: BOX2D_construct: args can not be empty points #4399|ST_AsTWKB|\x030001040000020201000001 #4399|ST_AsTWKB|\x070001030001040000020201000001 #4399|ST_AsTWKB|\x0310 -#4399|ST_AsX3D|0 0 1 1 0 1 -#4399|ST_AsX3D| +#4399|ST_AsX3D|0 0 0 1 1 0 0 1 0 +#4399|ST_AsX3D| #4399|ST_AsX3D| #4399|ST_GeoHash|s00 #4399|ST_GeoHash|s00 ----------------------------------------------------------------------- Summary of changes: NEWS | 2 + liblwgeom/cunit/cu_out_x3d.c | 39 +++++++++++-- liblwgeom/lwout_x3d.c | 125 +++++++++++++++++++++++++++--------------- liblwgeom/lwout_x3d.h | 3 +- regress/core/tickets_expected | 4 +- 5 files changed, 122 insertions(+), 51 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Sun Jun 21 14:21:49 2026 From: trac at osgeo.org (PostGIS) Date: Sun, 21 Jun 2026 21:21:49 -0000 Subject: [PostGIS] #2838: Finish up X3D implementation for all types In-Reply-To: <046.ad169e8ae348b4fbaef6f9e8586c774a@osgeo.org> References: <046.ad169e8ae348b4fbaef6f9e8586c774a@osgeo.org> Message-ID: <061.ea3a7bca3b217ce3495c9d83f3c68932@osgeo.org> #2838: Finish up X3D implementation for all types ----------------------+----------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: ----------------------+----------------------------- Changes (by Darafei Praliaskouski ): * resolution: => fixed * status: new => closed Comment: In [changeset:"226a7ef5fef9669372a5d63de0d6ef23dabb4929/git" 226a7ef/git]: {{{#!CommitTicketReference repository="git" revision="226a7ef5fef9669372a5d63de0d6ef23dabb4929" Fix X3D 2D polygon serialization Emit Coordinate child nodes for indexed 2D line and polygon X3D output instead of writing bare coordinate text into the parent element. Reuse the indexed face output path for polygons inside geometry collections so collection wrapping produces a valid Shape payload. Closes #2838 Closes https://github.com/postgis/postgis/pull/987 }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Sun Jun 21 18:39:14 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 18:39:14 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-657-g902880616 Message-ID: <20260622013914.DB1441B9FED@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via 902880616da9cf054786b24bd243a7e454c3c34a (commit) from 226a7ef5fef9669372a5d63de0d6ef23dabb4929 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 902880616da9cf054786b24bd243a7e454c3c34a Author: Teramoto Ikuhiro Date: Mon Jun 22 01:06:28 2026 +0000 Translated PostGIS Manual using Weblate (Japanese) Currently translated at 98.7% (5508 of 5579 strings) Translation: postgis/PostGIS Manual Translate-URL: https://weblate.osgeo.org/projects/postgis/postgis-manual/ja/ diff --git a/doc/po/ja/postgis-manual.po b/doc/po/ja/postgis-manual.po index 38219613e..6724ff217 100644 --- a/doc/po/ja/postgis-manual.po +++ b/doc/po/ja/postgis-manual.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: postgis 3.5\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n" "POT-Creation-Date: 2026-06-12 20:29+0000\n" -"PO-Revision-Date: 2026-06-18 08:39+0000\n" +"PO-Revision-Date: 2026-06-22 01:39+0000\n" "Last-Translator: Teramoto Ikuhiro \n" "Language-Team: Japanese \n" @@ -11485,11 +11485,16 @@ msgid "" "between some geometries), it produces a Minimum Spanning Forest, and each " "connected component is assigned a unique tree ID." msgstr "" +"" +"Minimum Spanning Tree (????????????????????" +"??????????????????????????????????????" +"???? (?: ?????????????????)??????????????" +"????????????????????????ID??????" #. Tag: para #, no-c-format msgid "Requires GEOS >= 3.15.0" -msgstr "" +msgstr "GEOS >= 3.15.0 ?????" #. Tag: para #, no-c-format @@ -11497,6 +11502,8 @@ msgid "" ", , " msgstr "" +", , " #. Tag: refpurpose #, no-c-format @@ -13293,7 +13300,7 @@ msgstr "" #. Tag: refpurpose #, no-c-format msgid "Computes the unique edges of a polygonal coverage." -msgstr "" +msgstr "?????????????????????????" #. Tag: para #, no-c-format @@ -13302,6 +13309,9 @@ msgid "" "coverage. A polygonal coverage is a set of non-overlapping polygons where " "adjacent polygons have matching vertices along shared edges." msgstr "" +"???????????????????MULTILINESTRING????????" +"??????????????????????????????????????" +"?????????????????????????" #. Tag: para #, no-c-format @@ -13309,11 +13319,15 @@ msgid "" "The edgetype parameter can be used to select which " "edges are returned:" msgstr "" +"edgetype???????????????????????" +"??????????????????:" #. Tag: para #, no-c-format msgid "0 (ALL) - all unique edges (default)" msgstr "" +"0 (ALL) - ??????????? " +"(?????)" #. Tag: para #, no-c-format @@ -13321,6 +13335,8 @@ msgid "" "1 (EXTERIOR) - only exterior edges (non-" "shared)" msgstr "" +"1 (EXTERIOR) - ????????????? " +"(??????)" #. Tag: para #, no-c-format @@ -13328,6 +13344,8 @@ msgid "" "2 (INTERIOR) - only interior edges " "(shared)" msgstr "" +"2 (INTERIOR) - ????????????? " +"(?????)" #. Tag: para #, no-c-format @@ -13335,6 +13353,8 @@ msgid "" ", , " msgstr "" +", , " #. Tag: refpurpose #, no-c-format @@ -17548,7 +17568,7 @@ msgstr "" #, no-c-format msgid "" "Returns the interpolated measure of a geometry closest to a point in 3D." -msgstr "" +msgstr "3???????????????M???????" #. Tag: para #, no-c-format @@ -17559,6 +17579,10 @@ msgid "" "such as flight trajectories, where " "would give incorrect results by ignoring the Z dimension." msgstr "" +"????ZM??????????????????????M???????????" +"??3?? (XYZ)??????????????????Z??????????? Z" +"???????????????????" +"??????????????????????" #. Tag: para #, no-c-format @@ -17566,13 +17590,17 @@ msgid "" "The line must have both Z and M dimensions. The point should have a Z " "dimension." msgstr "" +"????Z??M?????????????????????Z??????????" +"??????" #. Tag: para -#, no-c-format +#, fuzzy, no-c-format msgid "" ", , , " "" msgstr "" +", , , " +"" #. Tag: refpurpose #, no-c-format ----------------------------------------------------------------------- Summary of changes: doc/po/ja/postgis-manual.po | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Sun Jun 21 23:39:13 2026 From: git at osgeo.org (git at osgeo.org) Date: Sun, 21 Jun 2026 23:39:13 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-658-gac4a2e171 Message-ID: <20260622063913.E1A0C1BD801@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via ac4a2e171257465041ccdd4065b0378d2f1e834f (commit) from 902880616da9cf054786b24bd243a7e454c3c34a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit ac4a2e171257465041ccdd4065b0378d2f1e834f Author: Teramoto Ikuhiro Date: Mon Jun 22 06:22:47 2026 +0000 Translated PostGIS Manual using Weblate (Japanese) Currently translated at 98.8% (5514 of 5579 strings) Translation: postgis/PostGIS Manual Translate-URL: https://weblate.osgeo.org/projects/postgis/postgis-manual/ja/ diff --git a/doc/po/ja/postgis-manual.po b/doc/po/ja/postgis-manual.po index 6724ff217..25b4bb42b 100644 --- a/doc/po/ja/postgis-manual.po +++ b/doc/po/ja/postgis-manual.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: postgis 3.5\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n" "POT-Creation-Date: 2026-06-12 20:29+0000\n" -"PO-Revision-Date: 2026-06-22 01:39+0000\n" +"PO-Revision-Date: 2026-06-22 06:39+0000\n" "Last-Translator: Teramoto Ikuhiro \n" "Language-Team: Japanese \n" @@ -18099,6 +18099,11 @@ msgid "" "is Massachusetts State Plane Feet and transformed area is in square meters " "since EPSG:26986 is state plane Massachusetts meters." msgstr "" +"???????????????????????????????" +"??????????? (EPSG:26986) ???????????EPSG:2249?????" +"??????????????????????????????????" +"EPSG:26986?????????????????????????????????" +"????????" #. Tag: para #, no-c-format @@ -19005,6 +19010,9 @@ msgid "" "length is desired without reprojection. The spheroid is specified by a text " "value as follows:" msgstr "" +"????????????????????????????????????/??" +"???????????????????????????????????" +"???????????:" #. Tag: para #, no-c-format @@ -22947,7 +22955,7 @@ msgstr "" #. Tag: title #, no-c-format msgid "Examples: 2.5D geometries" -msgstr "" +msgstr "?: 2.5????????" #. Tag: para #, no-c-format @@ -22956,6 +22964,9 @@ msgid "" "with Z ordinates, but where calculations are performed in 2D). Compare to " "the same example using ." msgstr "" +"???3???????????????????????????????2.5??" +"????????????? (Z???????????????2???????)" +"?????????????????" #. Tag: para #, no-c-format @@ -23581,6 +23592,10 @@ msgid "" "linkend=\"ST_Difference\"/>, , " msgstr "" +", , , , , , , " #. Tag: title #, no-c-format @@ -24134,7 +24149,7 @@ msgstr "" msgid "" "Returns a smoothed version of a geometry, using the Catmull-Rom spline " "algorithm" -msgstr "" +msgstr "Catmull-Rom?????????????????????????????" #. Tag: para #, no-c-format ----------------------------------------------------------------------- Summary of changes: doc/po/ja/postgis-manual.po | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Mon Jun 22 00:46:03 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 07:46:03 -0000 Subject: [PostGIS] #2355: Upgrade to change box cast to assignment In-Reply-To: <046.67c8caa7732ac9b859c6a02cf7a27bd5@osgeo.org> References: <046.67c8caa7732ac9b859c6a02cf7a27bd5@osgeo.org> Message-ID: <061.8188a05a066ae45d0546c51b4d00d46a@osgeo.org> #2355: Upgrade to change box cast to assignment -------------------------+----------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: worksforme | Keywords: -------------------------+----------------------------- Changes (by komzpa): * resolution: => worksforme * status: new => closed Comment: - New-install related commit: https://gitea.osgeo.org/postgis/postgis/commit/7543b7c1ab90d8edff0f6cdbdb3ab50c81dd431e - Upgrade machinery evidence: current generated upgrade SQL contains: DROP CAST IF EXISTS (geometry AS box); CREATE CAST (geometry AS box) WITH FUNCTION box(geometry) AS ASSIGNMENT; - Generic cast drop/recreate machinery commit predates the ticket: https://gitea.osgeo.org/postgis/postgis/commit/9936c19597b5125c70d9892a5c60fafeaeb30cce -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 00:53:06 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 07:53:06 -0000 Subject: [PostGIS] #1877: windows stack builder handle passwords with special characters In-Reply-To: <046.384261dddc8ebf3cb8aa6adb469e990d@osgeo.org> References: <046.384261dddc8ebf3cb8aa6adb469e990d@osgeo.org> Message-ID: <061.c158d2b55d8577397d96e6f52549a092@osgeo.org> #1877: windows stack builder handle passwords with special characters -----------------------+----------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: packages | Version: 2.0.x Resolution: wontfix | Keywords: -----------------------+----------------------------- Changes (by robe): * resolution: => wontfix * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 00:57:30 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 07:57:30 -0000 Subject: [PostGIS] #2853: regress test for pgsql2shp -m switch In-Reply-To: <046.ce34cfd7641b71bad3a4de202949c980@osgeo.org> References: <046.ce34cfd7641b71bad3a4de202949c980@osgeo.org> Message-ID: <061.aa758adee8ad289e793039307380c2ab@osgeo.org> #2853: regress test for pgsql2shp -m switch ----------------------+----------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: low | Milestone: PostGIS Fund Me Component: postgis | Version: 2.1.x Resolution: fixed | Keywords: ----------------------+----------------------------- Changes (by komzpa): * resolution: => fixed * status: new => closed Comment: Fixed by zezzagio and strk in https://gitea.osgeo.org/postgis/postgis/commit/3334fd0675c98c79a6a8527a05fc0e8c4c371835 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 00:59:27 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 07:59:27 -0000 Subject: [PostGIS] #5340: totopogeom doc miss default value for tolerance In-Reply-To: <053.94a339b456852044fe7bf911175aafce@osgeo.org> References: <053.94a339b456852044fe7bf911175aafce@osgeo.org> Message-ID: <068.5c44fa7c36ff1557b00a08c9db65fb74@osgeo.org> #5340: totopogeom doc miss default value for tolerance --------------------------+--------------------------- Reporter: PanierAvide | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: topology | Version: 3.3.x Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * resolution: => fixed * status: new => closed Comment: Fixed by strk in https://gitea.osgeo.org/postgis/postgis/commit/58374818b0c985b5a825fdd18dbee1238c0cc83a -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:00:14 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:00:14 -0000 Subject: [PostGIS] #4594: Remove AddGeometryColumn from shp2pgsql In-Reply-To: <049.9983ca2b3b454fa7488c30641c60e8a8@osgeo.org> References: <049.9983ca2b3b454fa7488c30641c60e8a8@osgeo.org> Message-ID: <064.23cb4eab28665c211baa76ac95593c58@osgeo.org> #4594: Remove AddGeometryColumn from shp2pgsql --------------------------+----------------------------- Reporter: pramsey | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by komzpa): * resolution: => fixed * status: new => closed Comment: Fixed in https://gitea.osgeo.org/postgis/postgis/commit/0482d073a2d174a544428664fa7cebcd36b7d96a -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:01:39 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:01:39 -0000 Subject: [PostGIS] #1770: long transaction In-Reply-To: <049.fdd7d6eed0e78cc109a4b6fe6a049cb8@osgeo.org> References: <049.fdd7d6eed0e78cc109a4b6fe6a049cb8@osgeo.org> Message-ID: <064.7be944dcef5dd6618196ff55fe3044bb@osgeo.org> #1770: long transaction ----------------------+------------------------------ Reporter: cruizch | Owner: cruizch Type: patch | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: 2.0.x Resolution: wontfix | Keywords: long transaction ----------------------+------------------------------ Changes (by komzpa): * resolution: => wontfix * status: new => closed Comment: Long transactions removed at https://gitea.osgeo.org/postgis/postgis/commit/9a746f869c5486706b08bf60d35a0c61d923888d -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:04:07 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:04:07 -0000 Subject: [PostGIS] #2602: In some cases ST_Distance (geography) would be faster building the index each time In-Reply-To: <049.8230d089b4c70adba7b4afcc46678408@osgeo.org> References: <049.8230d089b4c70adba7b4afcc46678408@osgeo.org> Message-ID: <064.cd0cdb1ce06ae1637f7902bc5bd516a3@osgeo.org> #2602: In some cases ST_Distance (geography) would be faster building the index each time ----------------------+----------------------------- Reporter: niqueco | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: ----------------------+----------------------------- Changes (by komzpa): * resolution: => fixed * status: new => closed Comment: Fixed https://gitea.osgeo.org/postgis/postgis/commit/68524cbacb87d691c1d0fd02905e3f4d55e57327 / duplicated by #3528 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:05:31 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:05:31 -0000 Subject: [PostGIS] #4228: Replace aggregate ST_Cluster* functions with window versions In-Reply-To: <049.dd12486443dc0c0cdecb0a344c44adce@osgeo.org> References: <049.dd12486443dc0c0cdecb0a344c44adce@osgeo.org> Message-ID: <064.d7da4fe4d5be03cd2f4b9f351776979a@osgeo.org> #4228: Replace aggregate ST_Cluster* functions with window versions --------------------------+----------------------------- Reporter: dbaston | Owner: komzpa Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by komzpa): * resolution: => fixed * status: reopened => closed Comment: Window cluster versions committed at https://gitea.osgeo.org/postgis/postgis/commit/d3cf06c2e0366ec1e5461b0ed50f4106cbdf44c6 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:07:14 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:07:14 -0000 Subject: [PostGIS] #5094: Expose a function to fetch spatial_ref_sys records from libproj In-Reply-To: <046.c9fdf51fe04ee9f62a9142f7e7f34487@osgeo.org> References: <046.c9fdf51fe04ee9f62a9142f7e7f34487@osgeo.org> Message-ID: <061.526b779ffcee047516b2d23ce08a608c@osgeo.org> #5094: Expose a function to fetch spatial_ref_sys records from libproj --------------------------+----------------------------- Reporter: strk | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by komzpa): * resolution: => fixed * status: new => closed Comment: Implemented in https://gitea.osgeo.org/postgis/postgis/commit/b85f9dcf6af50b90bf3112c86a47b1a08d601c79 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:09:05 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:09:05 -0000 Subject: [PostGIS] #5272: make install behaviour driven by PATH In-Reply-To: <046.6cf42fe31c03a20d5ac71af868907e02@osgeo.org> References: <046.6cf42fe31c03a20d5ac71af868907e02@osgeo.org> Message-ID: <061.eef75061112c5be130c1dbe36686c379@osgeo.org> #5272: make install behaviour driven by PATH ----------------------+----------------------------- Reporter: strk | Owner: strk Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: install | Version: Resolution: fixed | Keywords: ----------------------+----------------------------- Changes (by komzpa): * resolution: => fixed * status: new => closed Comment: Addressed in https://gitea.osgeo.org/postgis/postgis/commit/7af31bf2cb1968d7f9f3a275e9723702788b8615 / #5973 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:14:08 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:14:08 -0000 Subject: [PostGIS] #5423: Out-of-tree EPUB generation does not work In-Reply-To: <046.a48616ad888f48cdc105318192843102@osgeo.org> References: <046.a48616ad888f48cdc105318192843102@osgeo.org> Message-ID: <061.212b64c32a9c51ccbb7a1b47f9df106a@osgeo.org> #5423: Out-of-tree EPUB generation does not work ----------------------------+----------------------------- Reporter: strk | Owner: robe Type: defect | Status: new Priority: medium | Milestone: PostGIS Fund Me Component: documentation | Version: master Resolution: | Keywords: ----------------------------+----------------------------- Comment (by komzpa): after fix enable it on woodie (note to supersede #5420) -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:14:43 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:14:43 -0000 Subject: [PostGIS] #5420: Have woodie build the PDF, EPUB and cheatsheets In-Reply-To: <046.34e420f8c54b18fd4503e367a3047809@osgeo.org> References: <046.34e420f8c54b18fd4503e367a3047809@osgeo.org> Message-ID: <061.e1d8048e8268e7978a3a16d76002fe7d@osgeo.org> #5420: Have woodie build the PDF, EPUB and cheatsheets ---------------------------+----------------------------- Reporter: strk | Owner: robe Type: task | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: QA/buildbots | Version: master Resolution: fixed | Keywords: ---------------------------+----------------------------- Changes (by komzpa): * resolution: => fixed * status: new => closed Comment: This is addressed, epub to be fixed in #5423 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:17:44 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:17:44 -0000 Subject: [PostGIS] #442: liblwgeom standard handing of declaring type/empty/dimensionality support In-Reply-To: <049.7060fe6636fe33cb4e6801d4a1338f23@osgeo.org> References: <049.7060fe6636fe33cb4e6801d4a1338f23@osgeo.org> Message-ID: <064.155fd8441873d54f581052c96eeadcd5@osgeo.org> #442: liblwgeom standard handing of declaring type/empty/dimensionality support --------------------------+----------------------------- Reporter: pramsey | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: worksforme | Keywords: --------------------------+----------------------------- Changes (by komzpa): * resolution: => worksforme * status: new => closed Comment: Many refactorings happened since this ticket, not an eyesore anymore. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:18:44 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:18:44 -0000 Subject: [PostGIS] #2699: More garden test fixes for geometry In-Reply-To: <046.8415292392c914fec95bb1c36cf30f12@osgeo.org> References: <046.8415292392c914fec95bb1c36cf30f12@osgeo.org> Message-ID: <061.68e1fed0dce76cfdac642c77d7310470@osgeo.org> #2699: More garden test fixes for geometry ----------------------+----------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: 2.1.x Resolution: fixed | Keywords: ----------------------+----------------------------- Changes (by komzpa): * resolution: => fixed * status: new => closed Comment: garden tests work well, https://github.com/postgis/postgis/actions/runs/27934424481/job/82652838260 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:27:35 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:27:35 -0000 Subject: [PostGIS] #1765: Incorrect ST_Extent example in README_Raster.txt In-Reply-To: <049.9bb3d49de15978fd4a89d1600e71b7f6@osgeo.org> References: <049.9bb3d49de15978fd4a89d1600e71b7f6@osgeo.org> Message-ID: <064.614d136b9a204e5d4a2984d069c93ef5@osgeo.org> #1765: Incorrect ST_Extent example in README_Raster.txt ----------------------------+----------------------------- Reporter: mloskot | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: documentation | Version: 2.0.x Resolution: wontfix | Keywords: extent ----------------------------+----------------------------- Changes (by komzpa): * resolution: => wontfix * status: new => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 01:39:09 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 08:39:09 -0000 Subject: [PostGIS] #2627: st_linetocurve() pta_desegmentize needs implementation for npoints < 4 In-Reply-To: <048.75e422ae58efb873efde14b5e0988c95@osgeo.org> References: <048.75e422ae58efb873efde14b5e0988c95@osgeo.org> Message-ID: <063.13b668d8b9e1e6777806227860606588@osgeo.org> #2627: st_linetocurve() pta_desegmentize needs implementation for npoints < 4 --------------------------+----------------------------- Reporter: mjurce | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: 2.0.x Resolution: wontfix | Keywords: curves --------------------------+----------------------------- Changes (by komzpa): * resolution: => wontfix * status: new => closed Comment: The option I see is to perform either https://postgis.net/docs/ST_ChaikinSmoothing.html or https://postgis.net/docs/manual-dev/ST_CatmullRomSmoothing.html to give the line more points so that interpretation of curvature is less surprising. Additionally look at hot new https://postgis.net/docs/manual- dev/ST_MakeNurbsCurve.html. Otherwise it is not clear how to implement this, if you wish to contribute a patch you're welcome to do it. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 02:11:30 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 09:11:30 -0000 Subject: [PostGIS] #882: ST_UnionAsTIN, ST_UnionAsPolyghedralSurface In-Reply-To: <046.32d92da2e7d25e19da93a355b5f100d3@osgeo.org> References: <046.32d92da2e7d25e19da93a355b5f100d3@osgeo.org> Message-ID: <061.c15dd9e8c8a2411ebae1da4c1a22b9a2@osgeo.org> #882: ST_UnionAsTIN, ST_UnionAsPolyghedralSurface --------------------------+----------------------------- Reporter: robe | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+----------------------------- Changes (by komzpa): * resolution: => fixed * status: new => closed Comment: Triangles form a TIN naturally nowadays: {{{ 13:10:37 [kom] > select ST_AsText(ST_Collect('TRIANGLE((0 0, 1 1, 2 3, 0 0))', 'TRIANGLE((0 0, 1 1, 2 3, 0 0))')); ???????????????????????????????????????????????? ? st_astext ? ???????????????????????????????????????????????? ? TIN(((0 0,1 1,2 3,0 0)),((0 0,1 1,2 3,0 0))) ? ???????????????????????????????????????????????? (1 row) Time: 0,923 ms }}} -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 02:19:59 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 09:19:59 -0000 Subject: [PostGIS] #2127: [raster] raster2pgsql support for projection In-Reply-To: <046.d768d2557612d4ffcb11305757367135@osgeo.org> References: <046.d768d2557612d4ffcb11305757367135@osgeo.org> Message-ID: <061.0405eb178172a560a5a222f0252a3477@osgeo.org> #2127: [raster] raster2pgsql support for projection --------------------------+----------------------------- Reporter: robe | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: master Resolution: duplicate | Keywords: --------------------------+----------------------------- Changes (by komzpa): * resolution: => duplicate * status: new => closed Comment: Duplicated by #3743 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 02:23:43 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 09:23:43 -0000 Subject: [PostGIS] #5532: Improve validation of PostGIS Manual docbook In-Reply-To: <046.01aba4c7cf04b56a357e187afeae37ac@osgeo.org> References: <046.01aba4c7cf04b56a357e187afeae37ac@osgeo.org> Message-ID: <061.d0d428eb3e6575cb4ce7d72cfd80e5cc@osgeo.org> #5532: Improve validation of PostGIS Manual docbook ----------------------------+--------------------------- Reporter: strk | Owner: strk Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: documentation | Version: master Resolution: fixed | Keywords: ----------------------------+--------------------------- Changes (by komzpa): * resolution: => fixed * status: assigned => closed -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 04:37:47 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 11:37:47 -0000 Subject: [PostGIS] #4484: Data Extension for postgis use for documentation and possibly tests In-Reply-To: <046.48c9bbe6b51a01beab5bcb2fb7fdd224@osgeo.org> References: <046.48c9bbe6b51a01beab5bcb2fb7fdd224@osgeo.org> Message-ID: <061.e21e42ff8460197082b8a75aaeb21d34@osgeo.org> #4484: Data Extension for postgis use for documentation and possibly tests ----------------------+----------------------------- Reporter: robe | Owner: robe Type: defect | Status: assigned Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: | Keywords: ----------------------+----------------------------- Changes (by komzpa): * milestone: PostGIS Performance => PostGIS Fund Me -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:40:20 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:40:20 -0000 Subject: [PostGIS] #589: [raster] Implement ST_SameAlignment In-Reply-To: <049.65a2a827a302cb4e201f914b3e27ad42@osgeo.org> References: <049.65a2a827a302cb4e201f914b3e27ad42@osgeo.org> Message-ID: <064.220fccf9c6e800be462257beab484633@osgeo.org> #589: [raster] Implement ST_SameAlignment ----------------------+--------------------------- Reporter: pracine | Owner: dustymugs Type: task | Status: closed Priority: medium | Milestone: PostGIS 2.0.0 Component: raster | Version: master Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 2.0.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:40:34 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:40:34 -0000 Subject: [PostGIS] #110: shp2pgsql new option to not batch commit In-Reply-To: <046.efd4c6b6c8ac47119aed11228a3dd0ae@osgeo.org> References: <046.efd4c6b6c8ac47119aed11228a3dd0ae@osgeo.org> Message-ID: <061.7072b7e374fe988191412bdbc17bdb51@osgeo.org> #110: shp2pgsql new option to not batch commit --------------------------+--------------------------- Reporter: robe | Owner: mcayland Type: enhancement | Status: closed Priority: low | Milestone: PostGIS 2.0.0 Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 2.0.0 Old description: > '''What steps will reproduce the problem?''' > 1. If you have some geometries that fail insert such as polygons without > closed rings, it kills the current batch and gives a more or less > meaningless message > 2. This has happened to me a lot and a lot of users we train. A lot of > the > time the data should just rightfully not be added. > 3. Write now to overcome this I generate a .sql file and use sed to > remove > the begin commits which means I can't use the normal | to directly load > > I think the simplest option is to allow users with a flag to have the > option to not have begin commits so that everything is in its own > transaction. That way at least a whole batch of good records aren't lost > because of one bad apple. > > I know we have talked about other options such as allowing these beasts > into the database or nulling the geometry if invalid etc -- though those > options are trickier to implement and may not handle all cases. New description: '''What steps will reproduce the problem?''' 1. If you have some geometries that fail insert such as polygons without closed rings, it kills the current batch and gives a more or less meaningless message 2. This has happened to me a lot and a lot of users we train. A lot of the time the data should just rightfully not be added. 3. Write now to overcome this I generate a .sql file and use sed to remove the begin commits which means I can't use the normal | to directly load I think the simplest option is to allow users with a flag to have the option to not have begin commits so that everything is in its own transaction. That way at least a whole batch of good records aren't lost because of one bad apple. I know we have talked about other options such as allowing these beasts into the database or nulling the geometry if invalid etc -- though those options are trickier to implement and may not handle all cases. -- -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:41:38 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:41:38 -0000 Subject: [PostGIS] #883: [raster] Make every rtpostgis.sql function immutable strict when possible In-Reply-To: <049.92224b0e35c1d7f03bf04062b7fdd77d@osgeo.org> References: <049.92224b0e35c1d7f03bf04062b7fdd77d@osgeo.org> Message-ID: <064.b8fcefff579fb67f169f9cd6c258d587@osgeo.org> #883: [raster] Make every rtpostgis.sql function immutable strict when possible ----------------------+--------------------------- Reporter: pracine | Owner: pracine Type: task | Status: closed Priority: medium | Milestone: PostGIS 2.0.0 Component: raster | Version: master Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 2.0.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:41:56 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:41:56 -0000 Subject: [PostGIS] #1124: shp2pgsql, shp2pgsql-gui switch to create unlogged table In-Reply-To: <046.0334c2840999f9e846977c850b0a606c@osgeo.org> References: <046.0334c2840999f9e846977c850b0a606c@osgeo.org> Message-ID: <061.9779c929d063925f435298da4a430ba6@osgeo.org> #1124: shp2pgsql, shp2pgsql-gui switch to create unlogged table --------------------------+--------------------------- Reporter: robe | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:42:08 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:42:08 -0000 Subject: [PostGIS] #1374: [raster] raster2pgsql: option to list supported raster types In-Reply-To: <051.23d963a1cb262389f776b1f98040533c@osgeo.org> References: <051.23d963a1cb262389f776b1f98040533c@osgeo.org> Message-ID: <066.bf5a03fcdbded8d85b81dcb2e34561ce@osgeo.org> #1374: [raster] raster2pgsql: option to list supported raster types --------------------------+--------------------------- Reporter: dustymugs | Owner: pracine Type: enhancement | Status: closed Priority: low | Milestone: PostGIS 2.0.0 Component: raster | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 2.0.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:42:23 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:42:23 -0000 Subject: [PostGIS] #1375: [raster] raster2pgsql: add ability to specify ranges of band indices for -b flag In-Reply-To: <051.a789d33a178c8b25a4441ccb85bb72de@osgeo.org> References: <051.a789d33a178c8b25a4441ccb85bb72de@osgeo.org> Message-ID: <066.f7287356a203220fa2093f725065e139@osgeo.org> #1375: [raster] raster2pgsql: add ability to specify ranges of band indices for -b flag --------------------------+--------------------------- Reporter: dustymugs | Owner: pracine Type: enhancement | Status: closed Priority: low | Milestone: PostGIS 2.0.0 Component: raster | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 2.0.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:43:15 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:43:15 -0000 Subject: [PostGIS] #1408: PDF generator sets transparency to black In-Reply-To: <046.00cd0d815732906567acbf797834bd88@osgeo.org> References: <046.00cd0d815732906567acbf797834bd88@osgeo.org> Message-ID: <061.47f46d77a4f74373933b13881ed99f72@osgeo.org> #1408: PDF generator sets transparency to black ----------------------------+--------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: documentation | Version: master Resolution: fixed | Keywords: ----------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:43:39 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:43:39 -0000 Subject: [PostGIS] #1599: normalize_address() confused by country In-Reply-To: <051.d971ae23b4cc45973d91a5cb2a22fabe@osgeo.org> References: <051.d971ae23b4cc45973d91a5cb2a22fabe@osgeo.org> Message-ID: <066.8a5218e2064ba6386faf8d75ec86914c@osgeo.org> #1599: normalize_address() confused by country ----------------------------------+--------------------------- Reporter: mikepease | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: pagc_address_parser | Version: master Resolution: fixed | Keywords: ----------------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:44:08 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:44:08 -0000 Subject: [PostGIS] #1621: Get rid of upgrade intermediary files In-Reply-To: <046.891246c503e1e41c714650246960c9f5@osgeo.org> References: <046.891246c503e1e41c714650246960c9f5@osgeo.org> Message-ID: <061.2b609c903d22b547d03c50364b3a2ebe@osgeo.org> #1621: Get rid of upgrade intermediary files --------------------+--------------------------- Reporter: robe | Owner: strk Type: task | Status: closed Priority: low | Milestone: PostGIS 2.0.0 Component: build | Version: master Resolution: fixed | Keywords: --------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 2.0.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:44:45 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:44:45 -0000 Subject: [PostGIS] #5420: Have woodie build the PDF, EPUB and cheatsheets In-Reply-To: <046.34e420f8c54b18fd4503e367a3047809@osgeo.org> References: <046.34e420f8c54b18fd4503e367a3047809@osgeo.org> Message-ID: <061.818a051d92e0895e9c071d3ad6c12861@osgeo.org> #5420: Have woodie build the PDF, EPUB and cheatsheets ---------------------------+--------------------------- Reporter: strk | Owner: robe Type: task | Status: closed Priority: medium | Milestone: PostGIS 3.4.0 Component: QA/buildbots | Version: master Resolution: fixed | Keywords: ---------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.4.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:52:45 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:52:45 -0000 Subject: [PostGIS] #1705: Get constraint-based columns in views to register correctly In-Reply-To: <046.f59c33df505f5793f73572c674293d41@osgeo.org> References: <046.f59c33df505f5793f73572c674293d41@osgeo.org> Message-ID: <061.ee90c350e2e3d2e5d5e1523e091910fc@osgeo.org> #1705: Get constraint-based columns in views to register correctly --------------------------+--------------------------- Reporter: robe | Owner: robe Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:54:53 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:54:53 -0000 Subject: [PostGIS] #1625: ST_Within and ST_DWithin disagree In-Reply-To: <046.b610ade23d0c42e5c98a3c2a66c8034d@osgeo.org> References: <046.b610ade23d0c42e5c98a3c2a66c8034d@osgeo.org> Message-ID: <061.921cd2e22c65f42e520ccb867a955f23@osgeo.org> #1625: ST_Within and ST_DWithin disagree ----------------------+--------------------------- Reporter: strk | Owner: pramsey Type: defect | Status: closed Priority: medium | Milestone: PostGIS 2.0.0 Component: postgis | Version: master Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 2.0.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:55:13 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:55:13 -0000 Subject: [PostGIS] #1793: Missing documentation for ST_MemCollect(geometry) In-Reply-To: <049.02ab7592f85d2f938c81932fec52b267@osgeo.org> References: <049.02ab7592f85d2f938c81932fec52b267@osgeo.org> Message-ID: <064.6b4e4b1dc6a205dc278b327fa568e9f0@osgeo.org> #1793: Missing documentation for ST_MemCollect(geometry) ----------------------------+--------------------------- Reporter: Mike Taves | Owner: Mike Taves Type: task | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: documentation | Version: master Resolution: fixed | Keywords: ----------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:57:09 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:57:09 -0000 Subject: [PostGIS] #1833: full record json output ala ST_ASGeoJSON that works against a row In-Reply-To: <046.fc8ba51cbd47e5be856f6b5d3d03ce08@osgeo.org> References: <046.fc8ba51cbd47e5be856f6b5d3d03ce08@osgeo.org> Message-ID: <061.04b7b98796c47be34c08f5ef2f7a9722@osgeo.org> #1833: full record json output ala ST_ASGeoJSON that works against a row --------------------------+--------------------------- Reporter: robe | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.0.0 Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.0.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:58:23 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:58:23 -0000 Subject: [PostGIS] #2021: [raster] Multi-band support for ST_Union In-Reply-To: <051.a31ac5b1a5e985867b4057e212417db6@osgeo.org> References: <051.a31ac5b1a5e985867b4057e212417db6@osgeo.org> Message-ID: <066.b40caf3028c9a772ef01ce27ad8d167c@osgeo.org> #2021: [raster] Multi-band support for ST_Union --------------------------+--------------------------- Reporter: dustymugs | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 2.1.0 Component: raster | Version: master Resolution: fixed | Keywords: history --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 2.1.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 12:58:59 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 19:58:59 -0000 Subject: [PostGIS] #2131: Replace regress_lots_of_points.sql data with generated query In-Reply-To: <046.4d65b614b6d300fc0805a9b4f5eb4703@osgeo.org> References: <046.4d65b614b6d300fc0805a9b4f5eb4703@osgeo.org> Message-ID: <061.3c6e97a9c6d06924b34188846574ad47@osgeo.org> #2131: Replace regress_lots_of_points.sql data with generated query --------------------------+--------------------------- Reporter: strk | Owner: pramsey Type: enhancement | Status: closed Priority: low | Milestone: PostGIS 3.2.0 Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.2.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:18:17 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:18:17 -0000 Subject: [PostGIS] #3158: Move TYPMOD handling out of liblwgeom In-Reply-To: <046.5cb75fc32521ff3f73d112af9a9c36a6@osgeo.org> References: <046.5cb75fc32521ff3f73d112af9a9c36a6@osgeo.org> Message-ID: <061.8e93e68855cead9b6572ba2f089c5219@osgeo.org> #3158: Move TYPMOD handling out of liblwgeom ------------------------+--------------------------- Reporter: strk | Owner: strk Type: task | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: liblwgeom | Version: master Resolution: fixed | Keywords: ------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:18:35 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:18:35 -0000 Subject: [PostGIS] #4315: PG12: Optimize FunctionCall parameter size in rtpg_mapalgebra.c In-Reply-To: <052.a4497d9d8fe6ef329b875d65f8f7d485@osgeo.org> References: <052.a4497d9d8fe6ef329b875d65f8f7d485@osgeo.org> Message-ID: <067.2f72008ff34d6435c0bd201453ccc7b2@osgeo.org> #4315: PG12: Optimize FunctionCall parameter size in rtpg_mapalgebra.c --------------------------+--------------------------- Reporter: Algunenano | Owner: dustymugs Type: enhancement | Status: closed Priority: low | Milestone: PostGIS 3.7.0 Component: raster | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:18:48 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:18:48 -0000 Subject: [PostGIS] #4798: ST_AsGeoJSON should warn about duplicate keys In-Reply-To: <048.9e70b822005c858f142b8907d42c527a@osgeo.org> References: <048.9e70b822005c858f142b8907d42c527a@osgeo.org> Message-ID: <063.682aaedd3040764260853d9b3fe4ea05@osgeo.org> #4798: ST_AsGeoJSON should warn about duplicate keys --------------------------+---------------------------------- Reporter: tobwen | Owner: pramsey Type: enhancement | Status: closed Priority: low | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: fixed | Keywords: geojson, json, jsonb --------------------------+---------------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:20:31 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:20:31 -0000 Subject: [PostGIS] #4208: Single geometry versions of ST_MaxDistance and ST_LongestLine In-Reply-To: <048.ce7865e78c985a85aced1bd781b0b1db@osgeo.org> References: <048.ce7865e78c985a85aced1bd781b0b1db@osgeo.org> Message-ID: <063.e7a3c911f2bb5209de8552b118e075af@osgeo.org> #4208: Single geometry versions of ST_MaxDistance and ST_LongestLine ----------------------+--------------------------- Reporter: komzpa | Owner: komzpa Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: 2.4.x Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:20:44 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:20:44 -0000 Subject: [PostGIS] #2045: pgsql2shp should not require temp table creation privs when dumping a query In-Reply-To: <046.3581ba5aa86ecb0845354540c6dcf1cb@osgeo.org> References: <046.3581ba5aa86ecb0845354540c6dcf1cb@osgeo.org> Message-ID: <061.18fce2f4cca61794947635575d34b05c@osgeo.org> #2045: pgsql2shp should not require temp table creation privs when dumping a query ----------------------------------+--------------------------- Reporter: strk | Owner: stefanpetrea Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: utils/loader-dumper | Version: master Resolution: fixed | Keywords: gsoc ----------------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:20:57 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:20:57 -0000 Subject: [PostGIS] #2623: pgsql2shp creates a dbf with 0 records when the table only has a geometry column In-Reply-To: <048.b1aa54927956b8e2f02375fd738fddc8@osgeo.org> References: <048.b1aa54927956b8e2f02375fd738fddc8@osgeo.org> Message-ID: <063.083eac9d11ac71653fec5e0390bfc0d0@osgeo.org> #2623: pgsql2shp creates a dbf with 0 records when the table only has a geometry column ----------------------------------+--------------------------- Reporter: winkey | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: utils/loader-dumper | Version: 2.0.x Resolution: fixed | Keywords: ----------------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:21:18 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:21:18 -0000 Subject: [PostGIS] #4678: Rewrite all raster callback functions in C In-Reply-To: <046.dac98bad5b89f555a3759a1900bbd4cc@osgeo.org> References: <046.dac98bad5b89f555a3759a1900bbd4cc@osgeo.org> Message-ID: <061.40ba68d6fbcecb2d691cd626d22ac9c3@osgeo.org> #4678: Rewrite all raster callback functions in C ---------------------+--------------------------- Reporter: robe | Owner: dustymugs Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: raster | Version: master Resolution: fixed | Keywords: ---------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:22:00 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:22:00 -0000 Subject: [PostGIS] #3103: geometry_columns, find_srid performance regress tests In-Reply-To: <046.65fc534dcf2886ce4898173ee4d8dce3@osgeo.org> References: <046.65fc534dcf2886ce4898173ee4d8dce3@osgeo.org> Message-ID: <061.9e4c3cb2ffefb1f0ff685ad1e1164b51@osgeo.org> #3103: geometry_columns, find_srid performance regress tests ----------------------+--------------------------- Reporter: robe | Owner: robe Type: task | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: 2.1.x Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:22:31 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:22:31 -0000 Subject: [PostGIS] #2863: ST_Height and ST_Width (or ST_XSize, ST_YSize, ST_ZSize) for geometry In-Reply-To: <046.03185e0efb3b00ea70f42d155b5920d1@osgeo.org> References: <046.03185e0efb3b00ea70f42d155b5920d1@osgeo.org> Message-ID: <061.5e204c9021c56e169bbc5674eae0e05f@osgeo.org> #2863: ST_Height and ST_Width (or ST_XSize, ST_YSize, ST_ZSize) for geometry --------------------------+--------------------------- Reporter: robe | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:22:41 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:22:41 -0000 Subject: [PostGIS] #2935: shp2pgsql: There should be a way to add a delete table statement even when just preparing the DDL In-Reply-To: <052.ab34beef46750988c2fd266980d622a1@osgeo.org> References: <052.ab34beef46750988c2fd266980d622a1@osgeo.org> Message-ID: <067.f0241fe011fc93755bc6be0eae53450b@osgeo.org> #2935: shp2pgsql: There should be a way to add a delete table statement even when just preparing the DDL ----------------------------------+--------------------------- Reporter: jimktrains | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: utils/loader-dumper | Version: 2.1.x Resolution: fixed | Keywords: shp2pgsql ----------------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:22:52 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:22:52 -0000 Subject: [PostGIS] #3179: Make libpgcommon notice handlers warn on truncation In-Reply-To: <046.62f03f936d70354d3aa40c21aa112941@osgeo.org> References: <046.62f03f936d70354d3aa40c21aa112941@osgeo.org> Message-ID: <061.80daa3d6d5c8422c04a00d75ac1cdf98@osgeo.org> #3179: Make libpgcommon notice handlers warn on truncation --------------------------+--------------------------- Reporter: strk | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:23:06 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:23:06 -0000 Subject: [PostGIS] #4385: [raster2pgsql] -I option recreates index for each insertion In-Reply-To: <047.bf5123fe514f4eb3652182f7b4cd41fb@osgeo.org> References: <047.bf5123fe514f4eb3652182f7b4cd41fb@osgeo.org> Message-ID: <062.80571acf3ac5fee054ffb5a6806d58da@osgeo.org> #4385: [raster2pgsql] -I option recreates index for each insertion --------------------------+--------------------------- Reporter: RaphJ | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: raster | Version: 2.4.x Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 13:24:10 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 20:24:10 -0000 Subject: [PostGIS] #3770: ST_ConvexHullAgg In-Reply-To: <046.9172b3c7668978feedc2f1efe641f74f@osgeo.org> References: <046.9172b3c7668978feedc2f1efe641f74f@osgeo.org> Message-ID: <061.0e83c81b0b59b318fdd7b37926ee375d@osgeo.org> #3770: ST_ConvexHullAgg --------------------------+----------------------------- Reporter: robe | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: postgis | Version: master Resolution: wontfix | Keywords: --------------------------+----------------------------- Changes (by komzpa): * resolution: => wontfix * status: new => closed Comment: Per https://github.com/postgis/postgis/pull/464#issuecomment-545552401 this is hopeless -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Mon Jun 22 13:50:40 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 22 Jun 2026 13:50:40 -0700 (PDT) Subject: [SCM] postgis.net branch website updated. clarity-final-188-g8d7838e Message-ID: <20260622205042.A80D01A0393@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "postgis.net". The branch, website has been updated via 8d7838eeda67e8481e5218795de3c389909980f9 (commit) from 59afecfb5f09b9ef4cf53049a1a87ae86d4c3f8d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 8d7838eeda67e8481e5218795de3c389909980f9 Author: Regina Obe Date: Mon Jun 22 16:50:09 2026 -0400 PostGIS Tiger Geocoder 2025.1 release diff --git a/content/news/2026/06-22_postgis-tiger-geocoder-2025.1.md b/content/news/2026/06-22_postgis-tiger-geocoder-2025.1.md new file mode 100644 index 0000000..876ce05 --- /dev/null +++ b/content/news/2026/06-22_postgis-tiger-geocoder-2025.1.md @@ -0,0 +1,81 @@ +--- +title: PostGIS Tiger Geocoder 2025.1 +layout: post +category: news +tags: [release,tiger_geocoder, tiger-2025, tiger-2025.1] +author: Regina Obe +date: "2026-06-22" +thumbnail: +--- + +The PostGIS development team is pleased to provide `postgis_tiger_geocoder` extension. +This is the very first release since the break from the PostGIS core. +This version requires PostgreSQL 16 and above and should work with any supported PostGIS version. + +PostGIS 3.6 series is the last series to include `postgis_tiger_geocoder`. +PostGIS 3.7 will be shipped without `postgis_tiger_geocoder`. + +Moving forward `postgis_tiger_geocoder` has its own dedicated repo at [OSGeo Gitea postgis_tiger_geocoder](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder) +under the PostGIS org. + +The versioning model has also changed to be versioned based on the year of the [Census US Tiger dataset](https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html) that is current at time of it's release. + + + +* **2025.1** [source]({{< loc "postgis.release_source">}}/postgis_tiger_geocoder/postgis_tiger_geocoder-2025.1.tar.gz) [md5]({{< loc "postgis.dev_download">}}/postgis_tiger_geocoder/postgis_tiger_geocoder-2025.1.tar.gz.md5) [NEWS](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/src/tag/2025.1/NEWS.md) [README](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/src/tag/2025.1/README.md) [docs](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/src/tag/2025.1/postgis_tiger_geocoder.md) + +For installing, refer to [Installing the extension](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/src/tag/2025.1/README.md#installing-the-extension) + +If you are upgrading from an older release do: + +```sql +ALTER EXTENSION postgis_tiger_geocoder UPDATE; +``` + +If you get an `ERROR: extension "postgis_tiger_geocoder" has no update path from version "x to version "2025.1"` +or you are upgrading from a development version, do: + +```sql +ALTER EXTENSION postgis_tiger_geocoder UPDATE TO "ANY"; +ALTER EXTENSION postgis_tiger_geocoder UPDATE; +``` + + +## Breaking Changes + +- Remove support for PostgreSQL < 16 (Regina Obe) +- `postgis_tiger_geocoder` moved out of the main PostGIS tree into its own + repository during the PostGIS 3.7 cycle (Paul Ramsey, Regina Obe) +- quote_ident tiger loader schema and table names (Paul Ramsey) +- No longer set search path of database to include tiger. + Users are expected to do this themselves. +- Refer to [README](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder#readme) for guidance (Regina Obe) + +## Security + +- [GT-26](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/pulls/26), quote_ident tiger loader schema and table names (Paul Ramsey) +- [GT-3](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/pulls/3), Prefix operators with system name space (Paul Ramsey) + +## Enhancements + +- [TR-6013](https://trac.osgeo.org/postgis/ticket/6013), update the geocoder to load TIGER 2025 data (Regina Obe) + +## Bug Fixes + +- [GT-2](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/issues/2), strip trailing country + names before built-in `normalize_address()` parsing +- [GT-10](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/issues/10), support `SH` and compact + `SH121` input for state-highway geocoding +- [GT-13](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/issues/13), generate SP-GiST indexes + for `missing_indexes_generate_script()` LIKE-search helpers +- [GT-20](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/issues/20), escape user-provided address fragments before + interpolating them into `normalize_address()` regular expressions +- [GT-24](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/pulls/24), create `tiger_data` schema from shell tiger loader scripts + (Darafei Praliaskouski) +- [TR-1599](https://trac.osgeo.org/postgis/ticket/1599), [73892dce](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/commit/73892dce), improve country-aware address normalization in `normalize_address()` + and related wrapper paths (Darafei Praliaskouski) +- [TR-2459](https://trac.osgeo.org/postgis/ticket/2459), [73892dce](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/commit/73892dce), speed up `pagc_normalize_address()` by avoiding redundant wrapper + parsing while preserving ZIP+4 and country details from the structured parser + (Darafei Praliaskouski) +- [TR-1461](https://trac.osgeo.org/postgis/ticket/1461), [73892dce](https://gitea.osgeo.org/postgis/postgis_tiger_geocoder/commit/73892dce), `geocode_intersection()` now tolerates irregular spacing in highway + names such as `I- 635` vs `I-635` (Darafei Praliaskouski) ----------------------------------------------------------------------- Summary of changes: .../2026/06-22_postgis-tiger-geocoder-2025.1.md | 81 ++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 content/news/2026/06-22_postgis-tiger-geocoder-2025.1.md hooks/post-receive -- postgis.net From git at osgeo.org Mon Jun 22 14:34:53 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 22 Jun 2026 14:34:53 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.3 updated. 3.3.10-12-g5964d6f1a Message-ID: <20260622213453.A311B1A0928@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.3 has been updated via 5964d6f1ae4d2ea69f2a8a76f260674bab2e93b4 (commit) from 856f0504287b904c9dca0fa8307db152704297ae (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5964d6f1ae4d2ea69f2a8a76f260674bab2e93b4 Author: Paul Ramsey Date: Mon Jun 22 14:34:08 2026 -0700 Avoid out-of-bounds write, uninitialized memory. diff --git a/extensions/address_standardizer/gamma.c b/extensions/address_standardizer/gamma.c index dcb16f7d0..96b7d72be 100644 --- a/extensions/address_standardizer/gamma.c +++ b/extensions/address_standardizer/gamma.c @@ -122,7 +122,7 @@ RULES *rules_init( ERR_PARAM *err_p ) { rules->rule_number = 0; rules->last_node = EPSILON; - PAGC_ALLOC_STRUC(r_p,RULE_PARAM,err_p,NULL) ; + PAGC_CALLOC_STRUC(r_p,RULE_PARAM,1,err_p,NULL) ; rules->r_p = r_p; /* -- initialize the statistics record -- */ diff --git a/extensions/address_standardizer/std_pg_hash.c b/extensions/address_standardizer/std_pg_hash.c index 9b6d6af1c..100d35838 100644 --- a/extensions/address_standardizer/std_pg_hash.c +++ b/extensions/address_standardizer/std_pg_hash.c @@ -534,12 +534,12 @@ static int parse_rule(char *buf, int *rule) while (1) { + if (nr >= MAX_RULE_LENGTH) return -1; *r = strtol( p, &q, 10 ); if (p == q) break; p = q; nr++; r++; - if (nr > MAX_RULE_LENGTH) return -1; } return nr; ----------------------------------------------------------------------- Summary of changes: extensions/address_standardizer/gamma.c | 2 +- extensions/address_standardizer/std_pg_hash.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Mon Jun 22 14:34:56 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 22 Jun 2026 14:34:56 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.4 updated. 3.4.6-14-g24ea85852 Message-ID: <20260622213456.B7ACC1A084A@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.4 has been updated via 24ea85852f981ae830f145b31f552932d3a1b698 (commit) from 4201384f1cf1518cecb9008b394f9d3478386033 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 24ea85852f981ae830f145b31f552932d3a1b698 Author: Paul Ramsey Date: Mon Jun 22 14:34:08 2026 -0700 Avoid out-of-bounds write, uninitialized memory. diff --git a/extensions/address_standardizer/gamma.c b/extensions/address_standardizer/gamma.c index 0824c6535..d802e86fb 100644 --- a/extensions/address_standardizer/gamma.c +++ b/extensions/address_standardizer/gamma.c @@ -122,7 +122,7 @@ RULES *rules_init( ERR_PARAM *err_p ) { rules->rule_number = 0; rules->last_node = EPSILON; - PAGC_ALLOC_STRUC(r_p,RULE_PARAM,err_p,NULL) ; + PAGC_CALLOC_STRUC(r_p,RULE_PARAM,1,err_p,NULL) ; rules->r_p = r_p; /* -- initialize the statistics record -- */ diff --git a/extensions/address_standardizer/std_pg_hash.c b/extensions/address_standardizer/std_pg_hash.c index 9b6d6af1c..100d35838 100644 --- a/extensions/address_standardizer/std_pg_hash.c +++ b/extensions/address_standardizer/std_pg_hash.c @@ -534,12 +534,12 @@ static int parse_rule(char *buf, int *rule) while (1) { + if (nr >= MAX_RULE_LENGTH) return -1; *r = strtol( p, &q, 10 ); if (p == q) break; p = q; nr++; r++; - if (nr > MAX_RULE_LENGTH) return -1; } return nr; ----------------------------------------------------------------------- Summary of changes: extensions/address_standardizer/gamma.c | 2 +- extensions/address_standardizer/std_pg_hash.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Mon Jun 22 14:34:59 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 22 Jun 2026 14:34:59 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.5 updated. 3.5.7-2-gaf18826ce Message-ID: <20260622213459.86AEC1A09B1@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.5 has been updated via af18826ce1375c9bd518a7bf6e71e9bc4b4bfdff (commit) from b1bf0d52d1f1eb043b2b6aeecfd2edec4cdb65c8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit af18826ce1375c9bd518a7bf6e71e9bc4b4bfdff Author: Paul Ramsey Date: Mon Jun 22 14:34:08 2026 -0700 Avoid out-of-bounds write, uninitialized memory. diff --git a/extensions/address_standardizer/gamma.c b/extensions/address_standardizer/gamma.c index 0824c6535..d802e86fb 100644 --- a/extensions/address_standardizer/gamma.c +++ b/extensions/address_standardizer/gamma.c @@ -122,7 +122,7 @@ RULES *rules_init( ERR_PARAM *err_p ) { rules->rule_number = 0; rules->last_node = EPSILON; - PAGC_ALLOC_STRUC(r_p,RULE_PARAM,err_p,NULL) ; + PAGC_CALLOC_STRUC(r_p,RULE_PARAM,1,err_p,NULL) ; rules->r_p = r_p; /* -- initialize the statistics record -- */ diff --git a/extensions/address_standardizer/std_pg_hash.c b/extensions/address_standardizer/std_pg_hash.c index 63f490415..a83be783a 100644 --- a/extensions/address_standardizer/std_pg_hash.c +++ b/extensions/address_standardizer/std_pg_hash.c @@ -534,12 +534,12 @@ static int parse_rule(char *buf, int *rule) while (1) { + if (nr >= MAX_RULE_LENGTH) return -1; *r = strtol( p, &q, 10 ); if (p == q) break; p = q; nr++; r++; - if (nr > MAX_RULE_LENGTH) return -1; } return nr; ----------------------------------------------------------------------- Summary of changes: extensions/address_standardizer/gamma.c | 2 +- extensions/address_standardizer/std_pg_hash.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From git at osgeo.org Mon Jun 22 14:35:04 2026 From: git at osgeo.org (git at osgeo.org) Date: Mon, 22 Jun 2026 14:35:04 -0700 (PDT) Subject: [SCM] PostGIS branch stable-3.6 updated. 3.6.4-7-g84829064e Message-ID: <20260622213504.C2E641A0ABE@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, stable-3.6 has been updated via 84829064ea5a5824334a0c038eec20cc81f58ab1 (commit) from 86bf6bf1965bc03b53a391da5a17f1ff134f1fd2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 84829064ea5a5824334a0c038eec20cc81f58ab1 Author: Paul Ramsey Date: Mon Jun 22 14:34:08 2026 -0700 Avoid out-of-bounds write, uninitialized memory. diff --git a/extensions/address_standardizer/gamma.c b/extensions/address_standardizer/gamma.c index 0824c6535..d802e86fb 100644 --- a/extensions/address_standardizer/gamma.c +++ b/extensions/address_standardizer/gamma.c @@ -122,7 +122,7 @@ RULES *rules_init( ERR_PARAM *err_p ) { rules->rule_number = 0; rules->last_node = EPSILON; - PAGC_ALLOC_STRUC(r_p,RULE_PARAM,err_p,NULL) ; + PAGC_CALLOC_STRUC(r_p,RULE_PARAM,1,err_p,NULL) ; rules->r_p = r_p; /* -- initialize the statistics record -- */ diff --git a/extensions/address_standardizer/std_pg_hash.c b/extensions/address_standardizer/std_pg_hash.c index 63f490415..a83be783a 100644 --- a/extensions/address_standardizer/std_pg_hash.c +++ b/extensions/address_standardizer/std_pg_hash.c @@ -534,12 +534,12 @@ static int parse_rule(char *buf, int *rule) while (1) { + if (nr >= MAX_RULE_LENGTH) return -1; *r = strtol( p, &q, 10 ); if (p == q) break; p = q; nr++; r++; - if (nr > MAX_RULE_LENGTH) return -1; } return nr; ----------------------------------------------------------------------- Summary of changes: extensions/address_standardizer/gamma.c | 2 +- extensions/address_standardizer/std_pg_hash.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- PostGIS From trac at osgeo.org Mon Jun 22 14:41:01 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 21:41:01 -0000 Subject: [PostGIS] #3148: Another GUC for PROJSO or can we just figure out the PROJSO? In-Reply-To: <046.ee32686c220db4c21bddc46ee29b5f75@osgeo.org> References: <046.ee32686c220db4c21bddc46ee29b5f75@osgeo.org> Message-ID: <061.91b17ef70e449dfddc96533c1b062410@osgeo.org> #3148: Another GUC for PROJSO or can we just figure out the PROJSO? ----------------------+----------------------------- Reporter: robe | Owner: dustymugs Type: defect | Status: closed Priority: medium | Milestone: PostGIS Fund Me Component: raster | Version: master Resolution: wontfix | Keywords: ----------------------+----------------------------- Changes (by robe): * resolution: => wontfix * status: new => closed Comment: no longer relevant as new versions have come. -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:06:34 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:06:34 -0000 Subject: [PostGIS] #2116: [raster] ST_Value(rast, point) should have an option for when the geometry is at the edge of a pixel. In-Reply-To: <049.184b021042a2a264232009fc82a49b97@osgeo.org> References: <049.184b021042a2a264232009fc82a49b97@osgeo.org> Message-ID: <064.bf9325e787a148cea3ff0286ec68e853@osgeo.org> #2116: [raster] ST_Value(rast, point) should have an option for when the geometry is at the edge of a pixel. --------------------------+--------------------------- Reporter: pracine | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: raster | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:06:50 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:06:50 -0000 Subject: [PostGIS] #2137: [raster] Add handling for overviews present in source rasters In-Reply-To: <051.d6372aba8ea05ff27e76005fb2a32a8f@osgeo.org> References: <051.d6372aba8ea05ff27e76005fb2a32a8f@osgeo.org> Message-ID: <066.727d49d4afffe068ced56c61ab979621@osgeo.org> #2137: [raster] Add handling for overviews present in source rasters --------------------------+--------------------------- Reporter: dustymugs | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: raster | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:07:20 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:07:20 -0000 Subject: [PostGIS] #2386: [raster] raster2pgsql misses man page In-Reply-To: <049.a71bcf3f0930afe5cfd69e569d623fa4@osgeo.org> References: <049.a71bcf3f0930afe5cfd69e569d623fa4@osgeo.org> Message-ID: <064.e77f6f8b1902e857b3a96d15d6032317@osgeo.org> #2386: [raster] raster2pgsql misses man page ----------------------+--------------------------- Reporter: mwanner | Owner: dustymugs Type: defect | Status: closed Priority: low | Milestone: PostGIS 3.7.0 Component: raster | Version: 2.0.x Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:08:49 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:08:49 -0000 Subject: [PostGIS] #2645: ST_LineInterpolatePoint incorrect output for 3D linestring In-Reply-To: <058.61d8199c4d0e5d3ef5866a436b80713f@osgeo.org> References: <058.61d8199c4d0e5d3ef5866a436b80713f@osgeo.org> Message-ID: <073.9df9587a929d2d0be8a2e7e8f325365b@osgeo.org> #2645: ST_LineInterpolatePoint incorrect output for 3D linestring -------------------------------+--------------------------- Reporter: bencaradocdavies | Owner: pramsey Type: defect | Status: closed Priority: critical | Milestone: PostGIS 3.0.0 Component: postgis | Version: 2.1.x Resolution: fixed | Keywords: -------------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.0.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:09:02 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:09:02 -0000 Subject: [PostGIS] #2804: [raster] ST_MapAlgebra support for user callbacks without userarg parameter In-Reply-To: <051.795f502ef74ec7bea384a80a9ad68cf0@osgeo.org> References: <051.795f502ef74ec7bea384a80a9ad68cf0@osgeo.org> Message-ID: <066.a8d577ff2d8682c71d1e5ff891b42254@osgeo.org> #2804: [raster] ST_MapAlgebra support for user callbacks without userarg parameter --------------------------+--------------------------- Reporter: dustymugs | Owner: dustymugs Type: enhancement | Status: closed Priority: low | Milestone: PostGIS 3.7.0 Component: raster | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:09:28 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:09:28 -0000 Subject: [PostGIS] #2820: Add automated tests for index creation at loading time In-Reply-To: <046.9cbd969f87141e9164bbf0d32c5951c8@osgeo.org> References: <046.9cbd969f87141e9164bbf0d32c5951c8@osgeo.org> Message-ID: <061.e3fe332b4aec77c935a95284ef9f82f0@osgeo.org> #2820: Add automated tests for index creation at loading time ---------------------------+--------------------------- Reporter: strk | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 2.1.4 Component: QA/testsuite | Version: 2.1.x Resolution: fixed | Keywords: ---------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 2.1.4 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:09:49 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:09:49 -0000 Subject: [PostGIS] #2820: Add automated tests for index creation at loading time In-Reply-To: <046.9cbd969f87141e9164bbf0d32c5951c8@osgeo.org> References: <046.9cbd969f87141e9164bbf0d32c5951c8@osgeo.org> Message-ID: <061.6c1fea49e5bcf594002f16db34891c21@osgeo.org> #2820: Add automated tests for index creation at loading time ---------------------------+--------------------------- Reporter: strk | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: QA/testsuite | Version: 2.1.x Resolution: fixed | Keywords: ---------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS 2.1.4 => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:10:14 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:10:14 -0000 Subject: [PostGIS] #2832: [raster] raster2pgsql pads overviews with single tiles In-Reply-To: <046.0f7875322653f25dd79166d5196b29be@osgeo.org> References: <046.0f7875322653f25dd79166d5196b29be@osgeo.org> Message-ID: <061.302cb4e5eb29cac961e9960cb4d152e1@osgeo.org> #2832: [raster] raster2pgsql pads overviews with single tiles ---------------------+--------------------------- Reporter: strk | Owner: dustymugs Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: raster | Version: master Resolution: fixed | Keywords: ---------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:12:48 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:12:48 -0000 Subject: [PostGIS] #4659: raster2pgsql option to create or append In-Reply-To: <054.d8e8c491bae5338c14c83abf05e6913c@osgeo.org> References: <054.d8e8c491bae5338c14c83abf05e6913c@osgeo.org> Message-ID: <069.c7a0c2f67249181219c50876cb7bf118@osgeo.org> #4659: raster2pgsql option to create or append ---------------------------+--------------------------- Reporter: andrewharvey | Owner: dustymugs Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: raster | Version: 2.5.x -- EOL Resolution: fixed | Keywords: ---------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:17:29 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:17:29 -0000 Subject: [PostGIS] #4332: Improve Doc Function Reference categories In-Reply-To: <048.aa6cb8cd91a6294995f196cedf2c1861@osgeo.org> References: <048.aa6cb8cd91a6294995f196cedf2c1861@osgeo.org> Message-ID: <063.2511a8c3e81a0ae7059cdf0d5be9c6d2@osgeo.org> #4332: Improve Doc Function Reference categories ----------------------------+--------------------------- Reporter: mdavis | Owner: mdavis Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: documentation | Version: master Resolution: fixed | Keywords: ----------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:18:42 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:18:42 -0000 Subject: [PostGIS] #4575: GRANT select on topology metadata tables to public In-Reply-To: <046.2d82eb7cdc47b468c9e48448502d4223@osgeo.org> References: <046.2d82eb7cdc47b468c9e48448502d4223@osgeo.org> Message-ID: <061.678763d564db2dee685b5f9756e3ee85@osgeo.org> #4575: GRANT select on topology metadata tables to public -----------------------+--------------------------- Reporter: strk | Owner: strk Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.2.0 Component: topology | Version: master Resolution: fixed | Keywords: -----------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.2.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:19:09 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:19:09 -0000 Subject: [PostGIS] #3743: raster2pgsql correctly support the -s from_srid:to_srid In-Reply-To: <046.4f75087fbeecf5a3f22400d858787773@osgeo.org> References: <046.4f75087fbeecf5a3f22400d858787773@osgeo.org> Message-ID: <061.17efdf400f7d45dc07a10b38ea83d8a5@osgeo.org> #3743: raster2pgsql correctly support the -s from_srid:to_srid --------------------------+--------------------------- Reporter: robe | Owner: robe Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: raster | Version: 2.3.x Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:20:11 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:20:11 -0000 Subject: [PostGIS] #3192: Automatically convert SRID<0 to SRID=0 in topology.topology In-Reply-To: <046.77e6505549f15f864d7f144628aa6f85@osgeo.org> References: <046.77e6505549f15f864d7f144628aa6f85@osgeo.org> Message-ID: <061.4068d28a7596c45911fdd72bfc1e07d9@osgeo.org> #3192: Automatically convert SRID<0 to SRID=0 in topology.topology --------------------------+--------------------------- Reporter: strk | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.2.0 Component: topology | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.2.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:22:48 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:22:48 -0000 Subject: [PostGIS] #3163: lwlinearreferencing.c doesn't conform to code style In-Reply-To: <049.1f5dad599d28c1d43646cb1436e71fb3@osgeo.org> References: <049.1f5dad599d28c1d43646cb1436e71fb3@osgeo.org> Message-ID: <064.847f65a23d661208caa69ad95dd56dc8@osgeo.org> #3163: lwlinearreferencing.c doesn't conform to code style ----------------------+--------------------------- Reporter: pramsey | Owner: strk Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.0.0 Component: postgis | Version: master Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.0.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:23:08 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:23:08 -0000 Subject: [PostGIS] #3033: FID column name option In-Reply-To: <051.a9f8099418272e5572442ade236e5c7a@osgeo.org> References: <051.a9f8099418272e5572442ade236e5c7a@osgeo.org> Message-ID: <066.23973af92efdc7d4ddfa4ea524813d0b@osgeo.org> #3033: FID column name option ----------------------------------+--------------------------- Reporter: mohayemin | Owner: robe Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: utils/loader-dumper | Version: 2.1.x Resolution: fixed | Keywords: ----------------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:23:45 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:23:45 -0000 Subject: [PostGIS] #2991: ST_Transform using PROJ.4 strings In-Reply-To: <049.322707570f2d21da7f7f8698fdda860b@osgeo.org> References: <049.322707570f2d21da7f7f8698fdda860b@osgeo.org> Message-ID: <064.7f38ee9bd168bf4c131d03c68e50fdf5@osgeo.org> #2991: ST_Transform using PROJ.4 strings --------------------------+--------------------------- Reporter: Mike Taves | Owner: pramsey Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 2.3.1 Component: postgis | Version: Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 2.3.1 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:24:29 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:24:29 -0000 Subject: [PostGIS] #2902: Add a postgis_geos_noop function In-Reply-To: <046.126b891938be45e966b46bf05ebcbf46@osgeo.org> References: <046.126b891938be45e966b46bf05ebcbf46@osgeo.org> Message-ID: <061.83e8c3dd3f00537b55b20e42a50914c0@osgeo.org> #2902: Add a postgis_geos_noop function --------------------------+--------------------------- Reporter: strk | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.0.0 Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.0.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:24:41 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:24:41 -0000 Subject: [PostGIS] #2850: Preserve scale and precision when generating shape file with pgsql2shp In-Reply-To: <053.bdf49a5f850985e5da9e511a5c685d0a@osgeo.org> References: <053.bdf49a5f850985e5da9e511a5c685d0a@osgeo.org> Message-ID: <068.d98f94e135aa52e5f6dca03948fbc04c@osgeo.org> #2850: Preserve scale and precision when generating shape file with pgsql2shp ------------------------------+--------------------------- Reporter: hopfgartner | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: utils/pgsql2shp | Version: 2.1.x Resolution: fixed | Keywords: pgsql2shp ------------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:25:05 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:25:05 -0000 Subject: [PostGIS] #2898: Define a guideline for function cost In-Reply-To: <046.2c7fdb97efac9cf2e14076f570f01a09@osgeo.org> References: <046.2c7fdb97efac9cf2e14076f570f01a09@osgeo.org> Message-ID: <061.30bfdb0ee547f51bd2749a5c3f94e11f@osgeo.org> #2898: Define a guideline for function cost --------------------------+--------------------------- Reporter: strk | Owner: strk Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: fixed | Keywords: --------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:27:33 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:27:33 -0000 Subject: [PostGIS] #2583: Add TIN Z support to ST_AsEWKT and ST_GeomFromEWKT In-Reply-To: <055.5cc3a79ad5d97a04aae04515c31b5a54@osgeo.org> References: <055.5cc3a79ad5d97a04aae04515c31b5a54@osgeo.org> Message-ID: <070.89fb0e443d6a3cb1e0ba1f2d7379b548@osgeo.org> #2583: Add TIN Z support to ST_AsEWKT and ST_GeomFromEWKT ----------------------------+--------------------------- Reporter: smathermather | Owner: smathermather Type: enhancement | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: 2.1.x Resolution: fixed | Keywords: ----------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:27:45 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:27:45 -0000 Subject: [PostGIS] #2838: Finish up X3D implementation for all types In-Reply-To: <046.ad169e8ae348b4fbaef6f9e8586c774a@osgeo.org> References: <046.ad169e8ae348b4fbaef6f9e8586c774a@osgeo.org> Message-ID: <061.d4ba2633a17396adf8a4105f32ee2116@osgeo.org> #2838: Finish up X3D implementation for all types ----------------------+--------------------------- Reporter: robe | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.7.0 Component: postgis | Version: master Resolution: fixed | Keywords: ----------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:28:03 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:28:03 -0000 Subject: [PostGIS] #4658: add --long-options to raster2pgsql In-Reply-To: <054.69f8cb697ca25d558fde3c5d068ea926@osgeo.org> References: <054.69f8cb697ca25d558fde3c5d068ea926@osgeo.org> Message-ID: <069.c68aa587a8370fe53d2fc030c0d8fbfe@osgeo.org> #4658: add --long-options to raster2pgsql ---------------------------+--------------------------- Reporter: andrewharvey | Owner: dustymugs Type: enhancement | Status: closed Priority: low | Milestone: PostGIS 3.7.0 Component: raster | Version: 2.5.x -- EOL Resolution: fixed | Keywords: ---------------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.7.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From trac at osgeo.org Mon Jun 22 15:28:26 2026 From: trac at osgeo.org (PostGIS) Date: Mon, 22 Jun 2026 22:28:26 -0000 Subject: [PostGIS] #5440: Remove ability to translate some portions of manual In-Reply-To: <046.9e42eb5e12d7af22c17e529241c68854@osgeo.org> References: <046.9e42eb5e12d7af22c17e529241c68854@osgeo.org> Message-ID: <061.855e54ff69eaa2f45f3f60e2f174c4ea@osgeo.org> #5440: Remove ability to translate some portions of manual ---------------------+--------------------------- Reporter: strk | Owner: robe Type: defect | Status: closed Priority: medium | Milestone: PostGIS 3.4.0 Component: l18n | Version: master Resolution: fixed | Keywords: ---------------------+--------------------------- Changes (by komzpa): * milestone: PostGIS Fund Me => PostGIS 3.4.0 -- Ticket URL: PostGIS The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project. From git at osgeo.org Tue Jun 23 01:39:14 2026 From: git at osgeo.org (git at osgeo.org) Date: Tue, 23 Jun 2026 01:39:14 -0700 (PDT) Subject: [SCM] PostGIS branch master updated. 3.6.0rc2-659-ga7e0df295 Message-ID: <20260623083914.EE85F1A851D@trac.osgeo.org> This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "PostGIS". The branch, master has been updated via a7e0df29543af698fb8aa98770e1af5e0410ef54 (commit) from ac4a2e171257465041ccdd4065b0378d2f1e834f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a7e0df29543af698fb8aa98770e1af5e0410ef54 Author: Arthur Bazin Date: Tue Jun 23 07:59:25 2026 +0000 Translated PostGIS Manual using Weblate (French) Currently translated at 94.6% (5278 of 5579 strings) Translation: postgis/PostGIS Manual Translate-URL: https://weblate.osgeo.org/projects/postgis/postgis-manual/fr/ diff --git a/doc/po/fr/postgis-manual.po b/doc/po/fr/postgis-manual.po index 6cb8d2143..5ad02f597 100644 --- a/doc/po/fr/postgis-manual.po +++ b/doc/po/fr/postgis-manual.po @@ -8,13 +8,14 @@ # Vincent Bre , 2025. # Edouard Choiniere , 2025. # Weblate , 2025. +# Arthur Bazin , 2026. msgid "" msgstr "" "Project-Id-Version: postgis 3.5\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n" "POT-Creation-Date: 2026-06-12 20:29+0000\n" -"PO-Revision-Date: 2025-07-01 00:47+0000\n" -"Last-Translator: Weblate \n" +"PO-Revision-Date: 2026-06-23 08:39+0000\n" +"Last-Translator: Arthur Bazin \n" "Language-Team: French \n" "Language: fr\n" @@ -22,7 +23,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.4.3\n" +"X-Generator: Weblate 5.16.2\n" #. Tag: chapter #, no-c-format @@ -58,6 +59,13 @@ msgid "" "You can also use the more cross-platform approach of setting the " "corresponding ." msgstr "" +"Les rasters de syst?me de fichiers (out-db) ainsi que les pilotes raster " +"sont d?sactiv?s par d?faut. Pour r?activer ceux-ci, vous devez d?finir les " +"variables d'environnement suivantes POSTGIS_GDAL_ENABLED_DRIVERS et POSTGIS_ENABLE_OUTDB_RASTERS dans " +"l'environnement serveur. Vous pouvez ?galement utiliser l'approche " +"multiplateforme en d?finissant la " +"correspondant." #. Tag: para #, no-c-format @@ -105,6 +113,12 @@ msgid "" "CLUSTER/environment where the " "placeholders refer to the PostgreSQL major version and cluster name." msgstr "" +"La d?finition de variables d'environnement varie en fonction du syst?me " +"d'exploitation. Pour PostgreSQL install? sur Ubuntu ou Debian via apt-" +"postgresql, la meilleure fa?on est d'?diter /etc/postgresql/" +"MAJOR/CLUSTER/" +"environment o? les espaces r?serv?s se r?f?rent ? la version " +"majeure de PostgreSQL et au nom du cluster." #. Tag: para #, no-c-format @@ -312,7 +326,7 @@ msgstr "" #. Tag: title #, no-c-format msgid "Soft upgrade using extensions" -msgstr "" +msgstr "Mise ? niveau progressive (Soft upgrade) utilisant des extensions" #. Tag: para #, no-c-format @@ -321,6 +335,9 @@ msgid "" "upgrade using extensions as well. Doing a minor upgrade with extensions is " "fairly painless." msgstr "" +"Si vous avez install? PostGIS ? l'origine avec des extensions, vous devez " +"?galement effectuer une mise ? jour en utilisant des extensions. Faire une " +"mise ? jour mineure avec les extensions est assez facile." #. Tag: para #, no-c-format @@ -328,6 +345,9 @@ msgid "" "Use the function to upgrade " "to the latest version you have installed." msgstr "" +"Vous devez utiliser la fonction pour passer ? la derni?re version " +"que vous avez install?e." #. Tag: para #, no-c-format @@ -338,6 +358,11 @@ msgid "" "postgis_raster objects are folded back into the main " "extension." msgstr "" +"Si vous mettez ? jour une base de donn?es reposant sur PostGIS 2.5, ex?cutez " +"la commande ALTER EXTENSION suivi de " +"postgis_extensions_upgrade() pour s'assurer que les objets " +"postgis_raster h?rit?s sont r?cup?r?s dans l'extension " +"principale." #. Tag: para #, no-c-format @@ -415,7 +440,7 @@ msgstr "" #. Tag: title #, no-c-format msgid "Soft upgrade without extensions" -msgstr "" +msgstr "Mise ? niveau progressive (Soft Upgrade) sans extensions" #. Tag: para #, no-c-format @@ -702,6 +727,9 @@ msgid "" "postgresql.conf or postgresql.auto.conf by using " "the ALTER SYSTEM command." msgstr "" +"La configuration PostgreSQL peut ?tre modifi?e au niveau du serveur sans " +"toucher ? postgresql.conf, ni ? postgresql.auto.conf en utilisant la commande ALTER SYSTEM." #. Tag: para #, no-c-format @@ -740,6 +768,10 @@ msgid "" "they are in an inherited hierarchy and avoids paying the planner penalty " "otherwise." msgstr "" +"Ceci est g?n?ralement utilis? pour le partitionnement de table. La valeur " +"par d?faut \"partition\" oblige le planificateur ? analyser les tables en ne " +"consid?rant les contraintes que si ells sont dans une hi?rarchie h?rit?e ce " +"qui ?vite d'?tre p?naliser par le planificateur." #. Tag: link #, no-c-format @@ -749,7 +781,7 @@ msgstr "shared_buffers" #. Tag: para #, no-c-format msgid "Default: ~128MB" -msgstr "" +msgstr "D?faut : ~128MB" #. Tag: para #, no-c-format @@ -769,6 +801,11 @@ msgid "" "and therefore also bounds how many workers can participate in parallel " "queries." msgstr "" +"max_worker_processes " +"contr?le le nombre maximum de processus d'arri?re-plan disponibles pour le " +"serveur et limite donc ?galement le nombre de workers pouvant participer ? " +"des requ?tes parall?les." #. Tag: para #, no-c-format ----------------------------------------------------------------------- Summary of changes: doc/po/fr/postgis-manual.po | 49 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) hooks/post-receive -- PostGIS