summaryrefslogtreecommitdiff
path: root/contrib/xml2
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/xml2')
-rw-r--r--contrib/xml2/.gitignore4
-rw-r--r--contrib/xml2/Makefile10
-rw-r--r--contrib/xml2/expected/xml2.out78
-rw-r--r--contrib/xml2/expected/xml2_1.out60
-rw-r--r--contrib/xml2/pgxml.sql.in77
-rw-r--r--contrib/xml2/sql/xml2.sql62
-rw-r--r--contrib/xml2/uninstall_pgxml.sql33
-rw-r--r--contrib/xml2/xml2--1.0.sql70
-rw-r--r--contrib/xml2/xml2--unpackaged--1.0.sql26
-rw-r--r--contrib/xml2/xml2.control6
-rw-r--r--contrib/xml2/xpath.c173
-rw-r--r--contrib/xml2/xslt_proc.c52
12 files changed, 416 insertions, 235 deletions
diff --git a/contrib/xml2/.gitignore b/contrib/xml2/.gitignore
new file mode 100644
index 0000000000..5dcb3ff972
--- /dev/null
+++ b/contrib/xml2/.gitignore
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/contrib/xml2/Makefile b/contrib/xml2/Makefile
index dd45a914c9..ad325723c9 100644
--- a/contrib/xml2/Makefile
+++ b/contrib/xml2/Makefile
@@ -1,15 +1,15 @@
-# $PostgreSQL: pgsql/contrib/xml2/Makefile,v 1.14 2010/03/01 18:07:59 tgl Exp $
+# contrib/xml2/Makefile
MODULE_big = pgxml
-
OBJS = xpath.o xslt_proc.o
-SHLIB_LINK += $(filter -lxslt, $(LIBS)) $(filter -lxml2, $(LIBS))
+EXTENSION = xml2
+DATA = xml2--1.0.sql xml2--unpackaged--1.0.sql
-DATA_built = pgxml.sql
-DATA = uninstall_pgxml.sql
REGRESS = xml2
+SHLIB_LINK += $(filter -lxslt, $(LIBS)) $(filter -lxml2, $(LIBS))
+
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
diff --git a/contrib/xml2/expected/xml2.out b/contrib/xml2/expected/xml2.out
index 74896b0802..3bf676fb40 100644
--- a/contrib/xml2/expected/xml2.out
+++ b/contrib/xml2/expected/xml2.out
@@ -1,10 +1,4 @@
---
--- first, define the functions. Turn off echoing so that expected file
--- does not depend on contents of pgxml.sql.
---
-SET client_min_messages = warning;
-\set ECHO none
-RESET client_min_messages;
+CREATE EXTENSION xml2;
select query_to_xml('select 1 as x',true,false,'');
query_to_xml
---------------------------------------------------------------
@@ -18,7 +12,7 @@ select query_to_xml('select 1 as x',true,false,'');
(1 row)
-select xslt_process( query_to_xml('select x from generate_series(1,5) as
+select xslt_process( query_to_xml('select x from generate_series(1,5) as
x',true,false,'')::text,
$$<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
@@ -145,3 +139,71 @@ values
Value</attribute></attributes>');
create index idx_xpath on t1 ( xpath_string
('/attributes/attribute[@name="attr_1"]/text()', xml_data::text));
+SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></employee>'::text, $$<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
+ <xsl:strip-space elements="*"/>
+ <xsl:param name="n1"/>
+ <xsl:param name="n2"/>
+ <xsl:param name="n3"/>
+ <xsl:param name="n4"/>
+ <xsl:param name="n5" select="'me'"/>
+ <xsl:template match="*">
+ <xsl:element name="samples">
+ <xsl:element name="sample">
+ <xsl:value-of select="$n1"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n2"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n3"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n4"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n5"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n6"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n7"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n8"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n9"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n10"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n11"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n12"/>
+ </xsl:element>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet>$$::text, 'n1="v1",n2="v2",n3="v3",n4="v4",n5="v5",n6="v6",n7="v7",n8="v8",n9="v9",n10="v10",n11="v11",n12="v12"'::text);
+ xslt_process
+------------------------
+ <samples> +
+ <sample>v1</sample> +
+ <sample>v2</sample> +
+ <sample>v3</sample> +
+ <sample>v4</sample> +
+ <sample>v5</sample> +
+ <sample>v6</sample> +
+ <sample>v7</sample> +
+ <sample>v8</sample> +
+ <sample>v9</sample> +
+ <sample>v10</sample>+
+ <sample>v11</sample>+
+ <sample>v12</sample>+
+ </samples> +
+
+(1 row)
+
diff --git a/contrib/xml2/expected/xml2_1.out b/contrib/xml2/expected/xml2_1.out
index 083fc3b2ca..fda626e08c 100644
--- a/contrib/xml2/expected/xml2_1.out
+++ b/contrib/xml2/expected/xml2_1.out
@@ -1,10 +1,4 @@
---
--- first, define the functions. Turn off echoing so that expected file
--- does not depend on contents of pgxml.sql.
---
-SET client_min_messages = warning;
-\set ECHO none
-RESET client_min_messages;
+CREATE EXTENSION xml2;
select query_to_xml('select 1 as x',true,false,'');
query_to_xml
---------------------------------------------------------------
@@ -18,7 +12,7 @@ select query_to_xml('select 1 as x',true,false,'');
(1 row)
-select xslt_process( query_to_xml('select x from generate_series(1,5) as
+select xslt_process( query_to_xml('select x from generate_series(1,5) as
x',true,false,'')::text,
$$<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
@@ -107,3 +101,53 @@ values
Value</attribute></attributes>');
create index idx_xpath on t1 ( xpath_string
('/attributes/attribute[@name="attr_1"]/text()', xml_data::text));
+SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></employee>'::text, $$<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
+ <xsl:strip-space elements="*"/>
+ <xsl:param name="n1"/>
+ <xsl:param name="n2"/>
+ <xsl:param name="n3"/>
+ <xsl:param name="n4"/>
+ <xsl:param name="n5" select="'me'"/>
+ <xsl:template match="*">
+ <xsl:element name="samples">
+ <xsl:element name="sample">
+ <xsl:value-of select="$n1"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n2"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n3"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n4"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n5"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n6"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n7"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n8"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n9"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n10"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n11"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n12"/>
+ </xsl:element>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet>$$::text, 'n1="v1",n2="v2",n3="v3",n4="v4",n5="v5",n6="v6",n7="v7",n8="v8",n9="v9",n10="v10",n11="v11",n12="v12"'::text);
+ERROR: xslt_process() is not available without libxslt
diff --git a/contrib/xml2/pgxml.sql.in b/contrib/xml2/pgxml.sql.in
deleted file mode 100644
index 98d8f81b57..0000000000
--- a/contrib/xml2/pgxml.sql.in
+++ /dev/null
@@ -1,77 +0,0 @@
-/* $PostgreSQL: pgsql/contrib/xml2/pgxml.sql.in,v 1.12 2010/03/01 18:07:59 tgl Exp $ */
-
--- Adjust this setting to control where the objects get created.
-SET search_path = public;
-
---SQL for XML parser
-
-CREATE OR REPLACE FUNCTION xml_is_well_formed(text) RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
--- deprecated old name for xml_is_well_formed
-CREATE OR REPLACE FUNCTION xml_valid(text) RETURNS bool
-AS 'MODULE_PATHNAME', 'xml_is_well_formed'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xml_encode_special_chars(text) RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xpath_string(text,text) RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xpath_nodeset(text,text,text,text) RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xpath_number(text,text) RETURNS float4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xpath_bool(text,text) RETURNS boolean
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
--- List function
-
-CREATE OR REPLACE FUNCTION xpath_list(text,text,text) RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xpath_list(text,text) RETURNS text
-AS 'SELECT xpath_list($1,$2,'','')'
-LANGUAGE SQL STRICT IMMUTABLE;
-
--- Wrapper functions for nodeset where no tags needed
-
-CREATE OR REPLACE FUNCTION xpath_nodeset(text,text)
-RETURNS text
-AS 'SELECT xpath_nodeset($1,$2,'''','''')'
-LANGUAGE SQL STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xpath_nodeset(text,text,text)
-RETURNS text
-AS 'SELECT xpath_nodeset($1,$2,'''',$3)'
-LANGUAGE SQL STRICT IMMUTABLE;
-
--- Table function
-
-CREATE OR REPLACE FUNCTION xpath_table(text,text,text,text,text)
-RETURNS setof record
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT STABLE;
-
--- XSLT functions
-
-CREATE OR REPLACE FUNCTION xslt_process(text,text,text)
-RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT VOLATILE;
-
--- the function checks for the correct argument count
-CREATE OR REPLACE FUNCTION xslt_process(text,text)
-RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
diff --git a/contrib/xml2/sql/xml2.sql b/contrib/xml2/sql/xml2.sql
index 73723b6be1..4a996af716 100644
--- a/contrib/xml2/sql/xml2.sql
+++ b/contrib/xml2/sql/xml2.sql
@@ -1,16 +1,8 @@
---
--- first, define the functions. Turn off echoing so that expected file
--- does not depend on contents of pgxml.sql.
---
-SET client_min_messages = warning;
-\set ECHO none
-\i pgxml.sql
-\set ECHO all
-RESET client_min_messages;
+CREATE EXTENSION xml2;
select query_to_xml('select 1 as x',true,false,'');
-select xslt_process( query_to_xml('select x from generate_series(1,5) as
+select xslt_process( query_to_xml('select x from generate_series(1,5) as
x',true,false,'')::text,
$$<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
@@ -80,3 +72,53 @@ Value</attribute></attributes>');
create index idx_xpath on t1 ( xpath_string
('/attributes/attribute[@name="attr_1"]/text()', xml_data::text));
+
+SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></employee>'::text, $$<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
+ <xsl:strip-space elements="*"/>
+ <xsl:param name="n1"/>
+ <xsl:param name="n2"/>
+ <xsl:param name="n3"/>
+ <xsl:param name="n4"/>
+ <xsl:param name="n5" select="'me'"/>
+ <xsl:template match="*">
+ <xsl:element name="samples">
+ <xsl:element name="sample">
+ <xsl:value-of select="$n1"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n2"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n3"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n4"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n5"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n6"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n7"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n8"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n9"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n10"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n11"/>
+ </xsl:element>
+ <xsl:element name="sample">
+ <xsl:value-of select="$n12"/>
+ </xsl:element>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet>$$::text, 'n1="v1",n2="v2",n3="v3",n4="v4",n5="v5",n6="v6",n7="v7",n8="v8",n9="v9",n10="v10",n11="v11",n12="v12"'::text);
diff --git a/contrib/xml2/uninstall_pgxml.sql b/contrib/xml2/uninstall_pgxml.sql
deleted file mode 100644
index 09441ef01f..0000000000
--- a/contrib/xml2/uninstall_pgxml.sql
+++ /dev/null
@@ -1,33 +0,0 @@
-/* $PostgreSQL: pgsql/contrib/xml2/uninstall_pgxml.sql,v 1.4 2007/11/13 04:24:29 momjian Exp $ */
-
--- Adjust this setting to control where the objects get dropped.
-SET search_path = public;
-
-DROP FUNCTION xslt_process(text,text);
-
-DROP FUNCTION xslt_process(text,text,text);
-
-DROP FUNCTION xpath_table(text,text,text,text,text);
-
-DROP FUNCTION xpath_nodeset(text,text,text);
-
-DROP FUNCTION xpath_nodeset(text,text);
-
-DROP FUNCTION xpath_list(text,text);
-
-DROP FUNCTION xpath_list(text,text,text);
-
-DROP FUNCTION xpath_bool(text,text);
-
-DROP FUNCTION xpath_number(text,text);
-
-DROP FUNCTION xpath_nodeset(text,text,text,text);
-
-DROP FUNCTION xpath_string(text,text);
-
-DROP FUNCTION xml_encode_special_chars(text);
-
--- deprecated old name for xml_is_well_formed
-DROP FUNCTION xml_valid(text);
-
-DROP FUNCTION xml_is_well_formed(text);
diff --git a/contrib/xml2/xml2--1.0.sql b/contrib/xml2/xml2--1.0.sql
new file mode 100644
index 0000000000..bc27dc89ca
--- /dev/null
+++ b/contrib/xml2/xml2--1.0.sql
@@ -0,0 +1,70 @@
+/* contrib/xml2/xml2--1.0.sql */
+
+--SQL for XML parser
+
+-- deprecated old name for xml_is_well_formed
+CREATE FUNCTION xml_valid(text) RETURNS bool
+AS 'xml_is_well_formed'
+LANGUAGE INTERNAL STRICT STABLE;
+
+CREATE FUNCTION xml_encode_special_chars(text) RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION xpath_string(text,text) RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION xpath_nodeset(text,text,text,text) RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION xpath_number(text,text) RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION xpath_bool(text,text) RETURNS boolean
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+-- List function
+
+CREATE FUNCTION xpath_list(text,text,text) RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION xpath_list(text,text) RETURNS text
+AS 'SELECT xpath_list($1,$2,'','')'
+LANGUAGE SQL STRICT IMMUTABLE;
+
+-- Wrapper functions for nodeset where no tags needed
+
+CREATE FUNCTION xpath_nodeset(text,text)
+RETURNS text
+AS 'SELECT xpath_nodeset($1,$2,'''','''')'
+LANGUAGE SQL STRICT IMMUTABLE;
+
+CREATE FUNCTION xpath_nodeset(text,text,text)
+RETURNS text
+AS 'SELECT xpath_nodeset($1,$2,'''',$3)'
+LANGUAGE SQL STRICT IMMUTABLE;
+
+-- Table function
+
+CREATE FUNCTION xpath_table(text,text,text,text,text)
+RETURNS setof record
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE;
+
+-- XSLT functions
+
+CREATE FUNCTION xslt_process(text,text,text)
+RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT VOLATILE;
+
+-- the function checks for the correct argument count
+CREATE FUNCTION xslt_process(text,text)
+RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
diff --git a/contrib/xml2/xml2--unpackaged--1.0.sql b/contrib/xml2/xml2--unpackaged--1.0.sql
new file mode 100644
index 0000000000..1aa894a619
--- /dev/null
+++ b/contrib/xml2/xml2--unpackaged--1.0.sql
@@ -0,0 +1,26 @@
+/* contrib/xml2/xml2--unpackaged--1.0.sql */
+
+ALTER EXTENSION xml2 ADD function xslt_process(text,text);
+ALTER EXTENSION xml2 ADD function xslt_process(text,text,text);
+ALTER EXTENSION xml2 ADD function xpath_table(text,text,text,text,text);
+ALTER EXTENSION xml2 ADD function xpath_nodeset(text,text,text);
+ALTER EXTENSION xml2 ADD function xpath_nodeset(text,text);
+ALTER EXTENSION xml2 ADD function xpath_list(text,text);
+ALTER EXTENSION xml2 ADD function xpath_list(text,text,text);
+ALTER EXTENSION xml2 ADD function xpath_bool(text,text);
+ALTER EXTENSION xml2 ADD function xpath_number(text,text);
+ALTER EXTENSION xml2 ADD function xpath_nodeset(text,text,text,text);
+ALTER EXTENSION xml2 ADD function xpath_string(text,text);
+ALTER EXTENSION xml2 ADD function xml_encode_special_chars(text);
+ALTER EXTENSION xml2 ADD function xml_valid(text);
+
+-- xml_valid is now an alias for core xml_is_well_formed()
+
+CREATE OR REPLACE FUNCTION xml_valid(text) RETURNS bool
+AS 'xml_is_well_formed'
+LANGUAGE INTERNAL STRICT STABLE;
+
+-- xml_is_well_formed is now in core, not needed in extension.
+-- be careful to drop extension's copy not core's.
+
+DROP FUNCTION @extschema@.xml_is_well_formed(text);
diff --git a/contrib/xml2/xml2.control b/contrib/xml2/xml2.control
new file mode 100644
index 0000000000..51de678d5f
--- /dev/null
+++ b/contrib/xml2/xml2.control
@@ -0,0 +1,6 @@
+# xml2 extension
+comment = 'XPath querying and XSLT'
+default_version = '1.0'
+module_pathname = '$libdir/pgxml'
+# non-relocatable because xml2--unpackaged--1.0.sql needs to use @extschema@
+relocatable = false
diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c
index dbf0b76f92..44c600e134 100644
--- a/contrib/xml2/xpath.c
+++ b/contrib/xml2/xpath.c
@@ -1,5 +1,5 @@
/*
- * $PostgreSQL: pgsql/contrib/xml2/xpath.c,v 1.30 2010/07/06 19:18:55 momjian Exp $
+ * contrib/xml2/xpath.c
*
* Parser interface for DOM-based parser (libxml) rather than
* stream-based SAX-type parser
@@ -40,6 +40,15 @@ Datum xpath_table(PG_FUNCTION_ARGS);
void pgxml_parser_init(void);
+/* workspace for pgxml_xpath() */
+
+typedef struct
+{
+ xmlDocPtr doctree;
+ xmlXPathContextPtr ctxt;
+ xmlXPathObjectPtr res;
+} xpath_workspace;
+
/* local declarations */
static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
@@ -51,7 +60,10 @@ static text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
static xmlChar *pgxml_texttoxmlchar(text *textstring);
-static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath);
+static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath,
+ xpath_workspace *workspace);
+
+static void cleanup_workspace(xpath_workspace *workspace);
/*
@@ -71,7 +83,14 @@ pgxml_parser_init(void)
}
-/* Returns true if document is well-formed */
+/*
+ * Returns true if document is well-formed
+ *
+ * Note: this has been superseded by a core function. We still have to
+ * have it in the contrib module so that existing SQL-level references
+ * to the function won't fail; but in normal usage with up-to-date SQL
+ * definitions for the contrib module, this won't be called.
+ */
PG_FUNCTION_INFO_V1(xml_is_well_formed);
@@ -214,25 +233,22 @@ PG_FUNCTION_INFO_V1(xpath_nodeset);
Datum
xpath_nodeset(PG_FUNCTION_ARGS)
{
- xmlChar *xpath,
- *toptag,
- *septag;
- int32 pathsize;
- text *xpathsupp,
- *xpres;
-
- /* PG_GETARG_TEXT_P(0) is document buffer */
- xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
+ text *document = PG_GETARG_TEXT_P(0);
+ text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
+ xmlChar *toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
+ xmlChar *septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3));
+ xmlChar *xpath;
+ text *xpres;
+ xmlXPathObjectPtr res;
+ xpath_workspace workspace;
- toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
- septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3));
+ xpath = pgxml_texttoxmlchar(xpathsupp);
- pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
+ res = pgxml_xpath(document, xpath, &workspace);
- xpath = pgxml_texttoxmlchar(xpathsupp);
+ xpres = pgxml_result_to_text(res, toptag, septag, NULL);
- xpres = pgxml_result_to_text(pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
- toptag, septag, NULL);
+ cleanup_workspace(&workspace);
pfree(xpath);
@@ -250,23 +266,21 @@ PG_FUNCTION_INFO_V1(xpath_list);
Datum
xpath_list(PG_FUNCTION_ARGS)
{
- xmlChar *xpath,
- *plainsep;
- int32 pathsize;
- text *xpathsupp,
- *xpres;
-
- /* PG_GETARG_TEXT_P(0) is document buffer */
- xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
+ text *document = PG_GETARG_TEXT_P(0);
+ text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
+ xmlChar *plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
+ xmlChar *xpath;
+ text *xpres;
+ xmlXPathObjectPtr res;
+ xpath_workspace workspace;
- plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
+ xpath = pgxml_texttoxmlchar(xpathsupp);
- pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
+ res = pgxml_xpath(document, xpath, &workspace);
- xpath = pgxml_texttoxmlchar(xpathsupp);
+ xpres = pgxml_result_to_text(res, NULL, NULL, plainsep);
- xpres = pgxml_result_to_text(pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
- NULL, NULL, plainsep);
+ cleanup_workspace(&workspace);
pfree(xpath);
@@ -281,13 +295,13 @@ PG_FUNCTION_INFO_V1(xpath_string);
Datum
xpath_string(PG_FUNCTION_ARGS)
{
+ text *document = PG_GETARG_TEXT_P(0);
+ text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
xmlChar *xpath;
int32 pathsize;
- text *xpathsupp,
- *xpres;
-
- /* PG_GETARG_TEXT_P(0) is document buffer */
- xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
+ text *xpres;
+ xmlXPathObjectPtr res;
+ xpath_workspace workspace;
pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
@@ -298,13 +312,16 @@ xpath_string(PG_FUNCTION_ARGS)
/* We could try casting to string using the libxml function? */
xpath = (xmlChar *) palloc(pathsize + 9);
- memcpy((char *) (xpath + 7), VARDATA(xpathsupp), pathsize);
strncpy((char *) xpath, "string(", 7);
+ memcpy((char *) (xpath + 7), VARDATA(xpathsupp), pathsize);
xpath[pathsize + 7] = ')';
xpath[pathsize + 8] = '\0';
- xpres = pgxml_result_to_text(pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
- NULL, NULL, NULL);
+ res = pgxml_xpath(document, xpath, &workspace);
+
+ xpres = pgxml_result_to_text(res, NULL, NULL, NULL);
+
+ cleanup_workspace(&workspace);
pfree(xpath);
@@ -319,21 +336,17 @@ PG_FUNCTION_INFO_V1(xpath_number);
Datum
xpath_number(PG_FUNCTION_ARGS)
{
+ text *document = PG_GETARG_TEXT_P(0);
+ text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
xmlChar *xpath;
- int32 pathsize;
- text *xpathsupp;
float4 fRes;
-
xmlXPathObjectPtr res;
-
- /* PG_GETARG_TEXT_P(0) is document buffer */
- xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
-
- pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
+ xpath_workspace workspace;
xpath = pgxml_texttoxmlchar(xpathsupp);
- res = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath);
+ res = pgxml_xpath(document, xpath, &workspace);
+
pfree(xpath);
if (res == NULL)
@@ -341,6 +354,8 @@ xpath_number(PG_FUNCTION_ARGS)
fRes = xmlXPathCastToNumber(res);
+ cleanup_workspace(&workspace);
+
if (xmlXPathIsNaN(fRes))
PG_RETURN_NULL();
@@ -353,21 +368,17 @@ PG_FUNCTION_INFO_V1(xpath_bool);
Datum
xpath_bool(PG_FUNCTION_ARGS)
{
+ text *document = PG_GETARG_TEXT_P(0);
+ text *xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
xmlChar *xpath;
- int32 pathsize;
- text *xpathsupp;
int bRes;
-
xmlXPathObjectPtr res;
-
- /* PG_GETARG_TEXT_P(0) is document buffer */
- xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
-
- pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
+ xpath_workspace workspace;
xpath = pgxml_texttoxmlchar(xpathsupp);
- res = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath);
+ res = pgxml_xpath(document, xpath, &workspace);
+
pfree(xpath);
if (res == NULL)
@@ -375,6 +386,8 @@ xpath_bool(PG_FUNCTION_ARGS)
bRes = xmlXPathCastToBoolean(res);
+ cleanup_workspace(&workspace);
+
PG_RETURN_BOOL(bRes);
}
@@ -383,49 +396,61 @@ xpath_bool(PG_FUNCTION_ARGS)
/* Core function to evaluate XPath query */
static xmlXPathObjectPtr
-pgxml_xpath(text *document, xmlChar *xpath)
+pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
{
- xmlDocPtr doctree;
- xmlXPathContextPtr ctxt;
+ int32 docsize = VARSIZE(document) - VARHDRSZ;
xmlXPathObjectPtr res;
xmlXPathCompExprPtr comppath;
- int32 docsize;
- docsize = VARSIZE(document) - VARHDRSZ;
+ workspace->doctree = NULL;
+ workspace->ctxt = NULL;
+ workspace->res = NULL;
pgxml_parser_init();
- doctree = xmlParseMemory((char *) VARDATA(document), docsize);
- if (doctree == NULL)
+ workspace->doctree = xmlParseMemory((char *) VARDATA(document), docsize);
+ if (workspace->doctree == NULL)
return NULL; /* not well-formed */
- ctxt = xmlXPathNewContext(doctree);
- ctxt->node = xmlDocGetRootElement(doctree);
+ workspace->ctxt = xmlXPathNewContext(workspace->doctree);
+ workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
/* compile the path */
comppath = xmlXPathCompile(xpath);
if (comppath == NULL)
{
- xmlFreeDoc(doctree);
+ cleanup_workspace(workspace);
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"XPath Syntax Error");
}
/* Now evaluate the path expression. */
- res = xmlXPathCompiledEval(comppath, ctxt);
+ res = xmlXPathCompiledEval(comppath, workspace->ctxt);
+ workspace->res = res;
+
xmlXPathFreeCompExpr(comppath);
if (res == NULL)
- {
- xmlXPathFreeContext(ctxt);
- xmlFreeDoc(doctree);
+ cleanup_workspace(workspace);
- return NULL;
- }
- /* xmlFreeDoc(doctree); */
return res;
}
+/* Clean up after processing the result of pgxml_xpath() */
+static void
+cleanup_workspace(xpath_workspace *workspace)
+{
+ if (workspace->res)
+ xmlXPathFreeObject(workspace->res);
+ workspace->res = NULL;
+ if (workspace->ctxt)
+ xmlXPathFreeContext(workspace->ctxt);
+ workspace->ctxt = NULL;
+ if (workspace->doctree)
+ xmlFreeDoc(workspace->doctree);
+ workspace->doctree = NULL;
+}
+
static text *
pgxml_result_to_text(xmlXPathObjectPtr res,
xmlChar *toptag,
diff --git a/contrib/xml2/xslt_proc.c b/contrib/xml2/xslt_proc.c
index 4c80732bb8..f8f7d7263f 100644
--- a/contrib/xml2/xslt_proc.c
+++ b/contrib/xml2/xslt_proc.c
@@ -1,5 +1,5 @@
/*
- * $PostgreSQL: pgsql/contrib/xml2/xslt_proc.c,v 1.21 2010/07/06 19:18:55 momjian Exp $
+ * contrib/xml2/xslt_proc.c
*
* XSLT processing functions (requiring libxslt)
*
@@ -41,9 +41,7 @@ Datum xslt_process(PG_FUNCTION_ARGS);
extern void pgxml_parser_init(void);
/* local defs */
-static void parse_params(const char **params, text *paramstr);
-
-#define MAXPARAMS 20 /* must be even, see parse_params() */
+static const char **parse_params(text *paramstr);
#endif /* USE_LIBXSLT */
@@ -57,7 +55,7 @@ xslt_process(PG_FUNCTION_ARGS)
text *doct = PG_GETARG_TEXT_P(0);
text *ssheet = PG_GETARG_TEXT_P(1);
text *paramstr;
- const char *params[MAXPARAMS + 1]; /* +1 for the terminator */
+ const char **params;
xsltStylesheetPtr stylesheet = NULL;
xmlDocPtr doctree;
xmlDocPtr restree;
@@ -69,11 +67,14 @@ xslt_process(PG_FUNCTION_ARGS)
if (fcinfo->nargs == 3)
{
paramstr = PG_GETARG_TEXT_P(2);
- parse_params(params, paramstr);
+ params = parse_params(paramstr);
}
else
+ {
/* No parameters */
+ params = (const char **) palloc(sizeof(char *));
params[0] = NULL;
+ }
/* Setup parser */
pgxml_parser_init();
@@ -139,22 +140,34 @@ xslt_process(PG_FUNCTION_ARGS)
#ifdef USE_LIBXSLT
-static void
-parse_params(const char **params, text *paramstr)
+static const char **
+parse_params(text *paramstr)
{
char *pos;
char *pstr;
- int i;
char *nvsep = "=";
char *itsep = ",";
+ const char **params;
+ int max_params;
+ int nparams;
pstr = text_to_cstring(paramstr);
+ max_params = 20; /* must be even! */
+ params = (const char **) palloc((max_params + 1) * sizeof(char *));
+ nparams = 0;
+
pos = pstr;
- for (i = 0; i < MAXPARAMS; i++)
+ while (*pos != '\0')
{
- params[i] = pos;
+ if (nparams >= max_params)
+ {
+ max_params *= 2;
+ params = (const char **) repalloc(params,
+ (max_params + 1) * sizeof(char *));
+ }
+ params[nparams++] = pos;
pos = strstr(pos, nvsep);
if (pos != NULL)
{
@@ -164,13 +177,12 @@ parse_params(const char **params, text *paramstr)
else
{
/* No equal sign, so ignore this "parameter" */
- /* We'll reset params[i] to NULL below the loop */
+ nparams--;
break;
}
- /* Value */
- i++;
- /* since MAXPARAMS is even, we still have i < MAXPARAMS */
- params[i] = pos;
+
+ /* since max_params is even, we still have nparams < max_params */
+ params[nparams++] = pos;
pos = strstr(pos, itsep);
if (pos != NULL)
{
@@ -178,13 +190,13 @@ parse_params(const char **params, text *paramstr)
pos++;
}
else
- {
- i++;
break;
- }
}
- params[i] = NULL;
+ /* Add the terminator marker; we left room for it in the palloc's */
+ params[nparams] = NULL;
+
+ return params;
}
#endif /* USE_LIBXSLT */