[SCM] PostGIS branch master updated. 3.7.0beta1-122-g124f43a0a0

git at osgeo.org git at osgeo.org
Tue Jul 28 00:36:37 PDT 2026


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  124f43a0a0d28052b7ccc398dd9915a91c4906f0 (commit)
       via  29317b896d1bc7d9f1a5eccc2f5d521f3610f607 (commit)
      from  89d330399de6558439007d2e835d6693e9601089 (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 124f43a0a0d28052b7ccc398dd9915a91c4906f0
Merge: 89d330399d 29317b896d
Author: Darafei Praliaskouski <komzpa at gmail.com>
Date:   Tue Jul 28 00:36:36 2026 -0700

    Merge pull request 'Escape garden log labels in generated SQL' (!524) from Komzpa/postgis:codex/garden-log-label-sql-quote-20260726 into master
    
    Generated garden SQL embeds constructed log labels in single-quoted `INSERT` values. A documented function label containing an apostrophe could therefore break the generated statement. The existing escaping template also dropped leading or adjacent apostrophes and normalized whitespace.
    
    This change sends all four affected log-label expressions through the escaping template and corrects that template to double every apostrophe while preserving the remaining text verbatim.
    
    A focused XSL regression imports the production garden stylesheet and covers plain text, single, leading, adjacent, and trailing apostrophes, plus whitespace preservation. The regression is part of the documentation `check-unit` target.
    
    Reviewed-on: https://gitea.osgeo.org/postgis/postgis/pulls/524


commit 29317b896d1bc7d9f1a5eccc2f5d521f3610f607
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Sun Jul 26 14:25:18 2026 +0300

    Escape garden log labels in generated SQL

diff --git a/doc/Makefile.in b/doc/Makefile.in
index 4c257a8865..e8a4a1dc24 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -353,6 +353,12 @@ endif
 CHECK_UNIT_TARGET = check-docbook-qa-unit
 CHECK_HTML_BLOCK_LABELS_DEPS =
 
+ifneq ($(PYTHON3),)
+ifneq ($(XSLTPROC),)
+CHECK_UNIT_TARGET += check-gardentest-escaping
+endif
+endif
+
 ifeq ($(CAN_CHECK_XML),yes)
 CHECK_UNIT_TARGET += check-xml check-docbook-markup
 ifneq ($(PYTHON3),)
@@ -783,6 +789,9 @@ else
 	$(PYTHON3) $(abs_top_srcdir)/utils/test_docbook_qa.py
 endif
 
+check-gardentest-escaping: $(abs_top_srcdir)/utils/test_gardentest_escaping.py $(srcdir)/xsl/test_gardentest_escaping.xsl $(srcdir)/xsl/postgis_gardentest.sql.xsl
+	$(PYTHON3) $(abs_top_srcdir)/utils/test_gardentest_escaping.py --xsltproc "$(XSLTPROC)"
+
 check-html-block-labels: $(CHECK_HTML_BLOCK_LABELS_DEPS)
 ifeq ($(PYTHON3),)
 	@echo "Skipping $@: python3 is not available."
diff --git a/doc/xsl/postgis_gardentest.sql.xsl b/doc/xsl/postgis_gardentest.sql.xsl
index ad9b808017..37ac1083e8 100644
--- a/doc/xsl/postgis_gardentest.sql.xsl
+++ b/doc/xsl/postgis_gardentest.sql.xsl
@@ -608,7 +608,7 @@ SELECT '<xsl:value-of select="$log_label" /> Geography: End Testing';
 <!--Test functions that take no arguments and take no geometries/geographies -->
 	<xsl:when test="($numparamgeoms = '0' and $numparamgeogs = '0') and not(contains($fnexclude,db:funcdef/db:function))">SELECT  'Starting <xsl:value-of select="db:funcdef/db:function" />(<xsl:value-of select="$fnargs" />)';
 INSERT INTO <xsl:value-of select="$var_logtable" />(log_label, func, log_start, log_sql)
-			  	VALUES('<xsl:value-of select="$log_label" /> <xsl:value-of select="$geoftype" />','<xsl:value-of select="$fnname" />', clock_timestamp(),
+				VALUES('<xsl:call-template name="escapesinglequotes"><xsl:with-param name="arg1"><xsl:value-of select="$log_label" /> <xsl:value-of select="$geoftype" /></xsl:with-param></xsl:call-template>','<xsl:value-of select="$fnname" />', clock_timestamp(),
 			  	    '<xsl:call-template name="escapesinglequotes">
  <xsl:with-param name="arg1">SELECT  <xsl:value-of select="db:funcdef/db:function" />(<xsl:value-of select="$fnfakeparams" />) As output;</xsl:with-param></xsl:call-template>');
 
@@ -626,7 +626,7 @@ SELECT  'Ending <xsl:value-of select="db:funcdef/db:function" />(<xsl:value-of s
 		SELECT '<xsl:value-of select="$geoftype" /> <xsl:value-of select="$fnname" /><xsl:text> </xsl:text><xsl:value-of select="@ID" />: Start Testing';
 
 	INSERT INTO <xsl:value-of select="$var_logtable" />(log_label, func, g1, log_start, log_sql)
-			  	VALUES('<xsl:value-of select="$log_label" /> <xsl:value-of select="$geoftype" />  <xsl:text> </xsl:text><xsl:value-of select="@ID" /><xsl:text> </xsl:text>','<xsl:value-of select="$fnname" />', '<xsl:value-of select="@ID" />', clock_timestamp(),
+				VALUES('<xsl:call-template name="escapesinglequotes"><xsl:with-param name="arg1"><xsl:value-of select="$log_label" /> <xsl:value-of select="$geoftype" />  <xsl:text> </xsl:text><xsl:value-of select="@ID" /><xsl:text> </xsl:text></xsl:with-param></xsl:call-template>','<xsl:value-of select="$fnname" />', '<xsl:value-of select="@ID" />', clock_timestamp(),
 			  	'<xsl:call-template name="escapesinglequotes">
  <xsl:with-param name="arg1">SELECT <xsl:value-of select="$fnname" />(<xsl:value-of select="$fnfakeparams" />)<xsl:value-of select="$over_clause" />  As result
 							FROM (<xsl:value-of select="." />) As foo1
@@ -651,7 +651,7 @@ SELECT '<xsl:value-of select="$fnname" /> <xsl:text> </xsl:text><xsl:value-of se
 			<xsl:choose>
 			  <xsl:when test="($numparamgeogs > '0' or $numparamgeoms > '0')">
 	INSERT INTO <xsl:value-of select="$var_logtable" />(log_label, func, g1, g2,  log_start, log_sql)
-			  	VALUES('<xsl:value-of select="$log_label" /> <xsl:value-of select="$geoftype" /> <xsl:text> </xsl:text> <xsl:value-of select="@ID" />','<xsl:value-of select="$fnname" />','<xsl:value-of select="$geom1id" />', '<xsl:value-of select="@ID" />', clock_timestamp(),
+				VALUES('<xsl:call-template name="escapesinglequotes"><xsl:with-param name="arg1"><xsl:value-of select="$log_label" /> <xsl:value-of select="$geoftype" /> <xsl:text> </xsl:text> <xsl:value-of select="@ID" /></xsl:with-param></xsl:call-template>','<xsl:value-of select="$fnname" />','<xsl:value-of select="$geom1id" />', '<xsl:value-of select="@ID" />', clock_timestamp(),
 			  			'<xsl:call-template name="escapesinglequotes">
  <xsl:with-param name="arg1">SELECT <xsl:value-of select="$fnname" />(<xsl:value-of select="$fnfakeparams" />) As result, ST_AsText(foo1.the_geom) As ref1_geom, ST_AsText(foo2.the_geom) As ref2_geom
 	FROM (<xsl:value-of select="$from1" />) As foo1 CROSS JOIN (<xsl:value-of select="." />) As foo2
@@ -664,7 +664,7 @@ SELECT '<xsl:value-of select="$fnname" /> <xsl:text> </xsl:text><xsl:value-of se
 			</xsl:when>
 			  <xsl:otherwise>
 			  	INSERT INTO <xsl:value-of select="$var_logtable" />(log_label, func, g1, g2, log_start, log_sql)
-			  	VALUES('<xsl:value-of select="$log_label" /> Other <xsl:text> </xsl:text><xsl:value-of select="$geom1id" /><xsl:text> </xsl:text><xsl:value-of select="@ID" />','<xsl:value-of select="$fnname" />', '<xsl:value-of select="$geom1id" />','<xsl:value-of select="@DI" />', clock_timestamp(),
+				VALUES('<xsl:call-template name="escapesinglequotes"><xsl:with-param name="arg1"><xsl:value-of select="$log_label" /> Other <xsl:text> </xsl:text><xsl:value-of select="$geom1id" /><xsl:text> </xsl:text><xsl:value-of select="@ID" /></xsl:with-param></xsl:call-template>','<xsl:value-of select="$fnname" />', '<xsl:value-of select="$geom1id" />','<xsl:value-of select="@DI" />', clock_timestamp(),
 			  	'<xsl:call-template name="escapesinglequotes">
  <xsl:with-param name="arg1">SELECT <xsl:value-of select="$fnname" />(<xsl:value-of select="$fnfakeparams" />)</xsl:with-param></xsl:call-template>');
 
@@ -852,15 +852,15 @@ SELECT '<xsl:value-of select="$fnname" /><xsl:text> </xsl:text><xsl:value-of sel
      <xsl:param name="arg1"/>
      <xsl:variable name="apostrophe">'</xsl:variable>
      <xsl:choose>
-      <!-- this string has at least on single quote -->
+      <!-- this string has at least one single quote -->
       <xsl:when test="contains($arg1, $apostrophe)">
-      <xsl:if test="string-length(normalize-space(substring-before($arg1, $apostrophe))) > 0"><xsl:value-of select="substring-before($arg1, $apostrophe)" disable-output-escaping="yes"/>''</xsl:if>
+      <xsl:value-of select="substring-before($arg1, $apostrophe)"/><xsl:text>''</xsl:text>
        <xsl:call-template name="escapesinglequotes">
-        <xsl:with-param name="arg1"><xsl:value-of select="substring-after($arg1, $apostrophe)" disable-output-escaping="yes"/></xsl:with-param>
+        <xsl:with-param name="arg1" select="substring-after($arg1, $apostrophe)"/>
        </xsl:call-template>
       </xsl:when>
-      <!-- no quotes found in string, just print it -->
-      <xsl:when test="string-length(normalize-space($arg1)) > 0"><xsl:value-of select="normalize-space($arg1)"/></xsl:when>
+      <!-- no quotes found in string, so preserve it verbatim -->
+      <xsl:otherwise><xsl:value-of select="$arg1"/></xsl:otherwise>
      </xsl:choose>
     </xsl:template>
 
diff --git a/doc/xsl/test_gardentest_escaping.xsl b/doc/xsl/test_gardentest_escaping.xsl
new file mode 100644
index 0000000000..736789f674
--- /dev/null
+++ b/doc/xsl/test_gardentest_escaping.xsl
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:import href="postgis_gardentest.sql.xsl"/>
+  <xsl:output method="text" encoding="UTF-8"/>
+
+  <xsl:template name="case">
+    <xsl:param name="name"/>
+    <xsl:param name="value"/>
+    <xsl:value-of select="$name"/><xsl:text>|</xsl:text>
+    <xsl:call-template name="escapesinglequotes">
+      <xsl:with-param name="arg1" select="$value"/>
+    </xsl:call-template>
+    <xsl:text>
</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="/">
+    <xsl:call-template name="case"><xsl:with-param name="name" select="'plain'"/><xsl:with-param name="value" select="'plain'"/></xsl:call-template>
+    <xsl:call-template name="case"><xsl:with-param name="name" select="'one'"/><xsl:with-param name="value" select=""O'Brien""/></xsl:call-template>
+    <xsl:call-template name="case"><xsl:with-param name="name" select="'leading'"/><xsl:with-param name="value" select=""'start""/></xsl:call-template>
+    <xsl:call-template name="case"><xsl:with-param name="name" select="'adjacent'"/><xsl:with-param name="value" select=""a''b""/></xsl:call-template>
+    <xsl:call-template name="case"><xsl:with-param name="name" select="'trailing'"/><xsl:with-param name="value" select=""end'""/></xsl:call-template>
+    <xsl:call-template name="case"><xsl:with-param name="name" select="'whitespace'"/><xsl:with-param name="value" select="'  keep  spaces  '"/></xsl:call-template>
+  </xsl:template>
+</xsl:stylesheet>
diff --git a/utils/test_gardentest_escaping.py b/utils/test_gardentest_escaping.py
new file mode 100644
index 0000000000..36b6114364
--- /dev/null
+++ b/utils/test_gardentest_escaping.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+
+import argparse
+import subprocess
+import sys
+import unittest
+from pathlib import Path
+
+
+EXPECTED = (
+    "plain|plain\n"
+    "one|O''Brien\n"
+    "leading|''start\n"
+    "adjacent|a''''b\n"
+    "trailing|end''\n"
+    "whitespace|  keep  spaces" + "  \n"
+)
+
+
+class GardenTestEscapingTest(unittest.TestCase):
+    def test_escapesinglequotes_preserves_all_characters(self):
+        root = Path(__file__).resolve().parents[1]
+        stylesheet = root / "doc" / "xsl" / "test_gardentest_escaping.xsl"
+        result = subprocess.run(
+            [self.xsltproc, "--nonet", str(stylesheet), "-"],
+            input="<test/>\n",
+            text=True,
+            capture_output=True,
+            check=True,
+        )
+        self.assertEqual(EXPECTED, result.stdout)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument("--xsltproc", required=True)
+    args, unittest_args = parser.parse_known_args()
+    GardenTestEscapingTest.xsltproc = args.xsltproc
+    unittest.main(argv=[sys.argv[0], *unittest_args])

-----------------------------------------------------------------------

Summary of changes:
 doc/Makefile.in                      |  9 +++++++++
 doc/xsl/postgis_gardentest.sql.xsl   | 18 ++++++++---------
 doc/xsl/test_gardentest_escaping.xsl | 24 ++++++++++++++++++++++
 utils/test_gardentest_escaping.py    | 39 ++++++++++++++++++++++++++++++++++++
 4 files changed, 81 insertions(+), 9 deletions(-)
 create mode 100644 doc/xsl/test_gardentest_escaping.xsl
 create mode 100644 utils/test_gardentest_escaping.py


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list