Fix contrib/xml2 so regression test still works when it's built without libxslt.
authorTom Lane <[email protected]>
Mon, 1 Mar 2010 18:08:41 +0000 (18:08 +0000)
committerTom Lane <[email protected]>
Mon, 1 Mar 2010 18:08:41 +0000 (18:08 +0000)
This involves modifying the module to have a stable ABI, that is, the
xslt_process() function still exists even without libxslt.  It throws a
runtime error if called, but doesn't prevent executing the CREATE FUNCTION
call.  This is a good thing anyway to simplify cross-version upgrades.

contrib/xml2/Makefile
contrib/xml2/expected/xml2_1.out [new file with mode: 0644]
contrib/xml2/pgxml.sql.in
contrib/xml2/xslt_proc.c

index 13b9cb447ec25cd6cd39ab335257246b35ec36f0..41414b23bb9ebc8dd31ddb12552e62c513bdf610 100644 (file)
@@ -1,19 +1,27 @@
 # This makefile will build the new XML and XSLT routines.
 
+# This module will not work without libxml2, but it will work without libxslt.
+# To build without libxslt, run "gmake USE_LIBXSLT=0", or comment out the
+# following line:
+USE_LIBXSLT = 1
+
 MODULE_big = pgxml
 
-# Remove xslt_proc.o from the following line if you don't have libxslt
 OBJS = xpath.o xslt_proc.o
 
-# Remove -lxslt from the following line if you don't have libxslt.
+PG_CPPFLAGS := $(shell xml2-config --cflags)
+
+ifeq ($(USE_LIBXSLT),1)
+PG_CPPFLAGS += -DUSE_LIBXSLT
 SHLIB_LINK = -lxslt -lxml2
+else
+SHLIB_LINK = -lxml2
+endif
 
 DATA_built = pgxml.sql
 REGRESS = xml2
 DOCS = README.xml2
 
-PG_CPPFLAGS := $(shell xml2-config --cflags)
-
 ifdef USE_PGXS
 PGXS = $(shell pg_config --pgxs)
 include $(PGXS)
@@ -23,4 +31,3 @@ top_builddir = ../..
 include $(top_builddir)/src/Makefile.global
 include $(top_srcdir)/contrib/contrib-global.mk
 endif
-
diff --git a/contrib/xml2/expected/xml2_1.out b/contrib/xml2/expected/xml2_1.out
new file mode 100644 (file)
index 0000000..e6dcee1
--- /dev/null
@@ -0,0 +1,107 @@
+--
+-- 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;
+select xslt_process( 
+'<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+<row>
+  <x>1</x>
+</row>
+
+<row>
+  <x>2</x>
+</row>
+
+<row>
+  <x>3</x>
+</row>
+
+<row>
+  <x>4</x>
+</row>
+
+<row>
+  <x>5</x>
+</row>
+
+</table>'::text,
+$$<xsl:stylesheet version="1.0"
+               xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="xml" indent="yes" />
+<xsl:template match="*">
+  <xsl:copy>
+     <xsl:copy-of select="@*" />
+     <xsl:apply-templates />
+  </xsl:copy>
+</xsl:template>
+<xsl:template match="comment()|processing-instruction()">
+  <xsl:copy />
+</xsl:template>
+</xsl:stylesheet>
+$$::text);
+ERROR:  xslt_process() is not available without libxslt
+CREATE TABLE xpath_test (id integer NOT NULL, t text);
+INSERT INTO xpath_test VALUES (1, '<doc><int>1</int></doc>');
+SELECT * FROM xpath_table('id', 't', 'xpath_test', '/doc/int', 'true')
+as t(id int4);
+ id 
+----
+(0 rows)
+
+SELECT * FROM xpath_table('id', 't', 'xpath_test', '/doc/int', 'true')
+as t(id int4, doc int4);
+ id | doc 
+----+-----
+  1 |   1
+(1 row)
+
+create table articles (article_id integer, article_xml text, date_entered date);
+insert into articles (article_id, article_xml, date_entered)
+values (2, '<article><author>test</author><pages>37</pages></article>', now());
+SELECT * FROM
+xpath_table('article_id',
+            'article_xml',
+            'articles',
+            '/article/author|/article/pages|/article/title',
+            'date_entered > ''2003-01-01'' ')
+AS t(article_id integer, author text, page_count integer, title text);
+ article_id | author | page_count | title 
+------------+--------+------------+-------
+          2 | test   |         37 | 
+(1 row)
+
+-- this used to fail when invoked a second time
+select xslt_process('<aaa/>',$$<xsl:stylesheet version="1.0"
+xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:template match="@*|node()">
+      <xsl:copy>
+         <xsl:apply-templates select="@*|node()"/>
+      </xsl:copy>
+   </xsl:template>
+</xsl:stylesheet>$$);
+ERROR:  xslt_process() is not available without libxslt
+select xslt_process('<aaa/>',$$<xsl:stylesheet version="1.0"
+xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:template match="@*|node()">
+      <xsl:copy>
+         <xsl:apply-templates select="@*|node()"/>
+      </xsl:copy>
+   </xsl:template>
+</xsl:stylesheet>$$);
+ERROR:  xslt_process() is not available without libxslt
+create table t1 (id integer, xml_data text);
+insert into t1 (id, xml_data)
+values
+(1, '<attributes><attribute name="attr_1">Some
+Value</attribute></attributes>');
+select xpath_string('/attributes/attribute[@name="attr_1"]/text()', xml_data)
+from t1;
+ xpath_string 
+--------------
+(1 row)
+
index f9d8bd0e31a716f3c2c8e9705e04293c3f541695..2afbf7df00910d4e34e0ba80624887cc3066550f 100644 (file)
@@ -24,19 +24,14 @@ CREATE OR REPLACE FUNCTION xpath_list(text,text,text) RETURNS text
        AS 'MODULE_PATHNAME'
        LANGUAGE 'c' WITH (isStrict);
 
-
 CREATE OR REPLACE FUNCTION xpath_list(text,text) RETURNS text 
 AS 'SELECT xpath_list($1,$2,'','')' language 'SQL' WITH (isStrict);
 
-
-
 -- 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' WITH (isStrict);
 
-
 CREATE OR REPLACE FUNCTION xpath_nodeset(text,text,text) RETURNS text AS
 'SELECT xpath_nodeset($1,$2,'''',$3)' language 'SQL' WITH (isStrict);
 
@@ -47,14 +42,10 @@ CREATE OR REPLACE FUNCTION xpath_table(text,text,text,text,text) RETURNS setof r
        LANGUAGE 'c' WITH (isStrict);
 
 -- XSLT functions
--- Delete from here to the end of the file if you are not compiling with
--- XSLT support.
-
 
 CREATE OR REPLACE FUNCTION xslt_process(text,text,text) RETURNS text 
        AS 'MODULE_PATHNAME' LANGUAGE 'c' WITH (isStrict);
 
 -- the function checks for the correct argument count
-
 CREATE OR REPLACE FUNCTION xslt_process(text,text) RETURNS text 
        AS 'MODULE_PATHNAME' LANGUAGE 'c' WITH (isStrict);
index bf7ef89042fde611ffa0bf47225ee7517b2ba25f..86433a3e482e350ffe4bf48d1a8491b91d6b78d6 100644 (file)
@@ -7,6 +7,8 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 
+#ifdef USE_LIBXSLT
+
 /* libxml includes */
 
 #include <libxml/xpath.h>
 #include <libxslt/transform.h>
 #include <libxslt/xsltutils.h>
 
+#endif /* USE_LIBXSLT */
+
 
 /* externally accessible functions */
 
 Datum          xslt_process(PG_FUNCTION_ARGS);
 
+#ifdef USE_LIBXSLT
+
 /* declarations to come from xpath.c */
 extern void elog_error(const char *explain, bool force);
 extern void pgxml_parser_init(void);
@@ -36,13 +42,15 @@ static void parse_params(const char **params, text *paramstr);
 
 #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
 
+#endif /* USE_LIBXSLT */
+
 
 PG_FUNCTION_INFO_V1(xslt_process);
 
 Datum
 xslt_process(PG_FUNCTION_ARGS)
 {
-
+#ifdef USE_LIBXSLT
 
        const char *params[MAXPARAMS + 1];      /* +1 for the terminator */
        xsltStylesheetPtr stylesheet = NULL;
@@ -58,7 +66,6 @@ xslt_process(PG_FUNCTION_ARGS)
        text       *paramstr;
        text       *tres;
 
-
        if (fcinfo->nargs == 3)
        {
                paramstr = PG_GETARG_TEXT_P(2);
@@ -128,8 +135,18 @@ xslt_process(PG_FUNCTION_ARGS)
        VARATT_SIZEP(tres) = reslen + VARHDRSZ;
 
        PG_RETURN_TEXT_P(tres);
+
+#else /* !USE_LIBXSLT */
+
+       ereport(ERROR,
+                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                        errmsg("xslt_process() is not available without libxslt")));
+       PG_RETURN_NULL();
+
+#endif /* USE_LIBXSLT */
 }
 
+#ifdef USE_LIBXSLT
 
 static void
 parse_params(const char **params, text *paramstr)
@@ -178,3 +195,5 @@ parse_params(const char **params, text *paramstr)
 
        params[i] = NULL;
 }
+
+#endif /* USE_LIBXSLT */