summaryrefslogtreecommitdiff
path: root/contrib/xml2/xpath.c
diff options
context:
space:
mode:
authorMichael P2011-07-05 03:16:11 +0000
committerMichael P2011-07-06 03:40:35 +0000
commit0bbfc1e6338b5d98d6cb83fa75f2c38f527d4d4b (patch)
tree46fa412a31d08ea6e53d488ae7bc231df0b273da /contrib/xml2/xpath.c
parent091b0e828cf0fd5bbd1f9ae58ab96fc983e55d77 (diff)
parenta4bebdd92624e018108c2610fc3f2c1584b6c687 (diff)
Merge commit 'a4bebdd92624e018108c2610fc3f2c1584b6c687' into master
This is the commit merge of Postgres-XC with the intersection of PostgreSQL REL9_1_STABLE and master branches. Conflicts: COPYRIGHT contrib/pgbench/pgbench.c src/Makefile src/backend/access/transam/recovery.conf.sample src/backend/access/transam/varsup.c src/backend/access/transam/xlog.c src/backend/catalog/Makefile src/backend/catalog/dependency.c src/backend/catalog/system_views.sql src/backend/commands/copy.c src/backend/commands/explain.c src/backend/commands/sequence.c src/backend/commands/tablecmds.c src/backend/commands/vacuum.c src/backend/executor/nodeAgg.c src/backend/nodes/copyfuncs.c src/backend/nodes/equalfuncs.c src/backend/nodes/outfuncs.c src/backend/nodes/readfuncs.c src/backend/optimizer/path/allpaths.c src/backend/optimizer/plan/createplan.c src/backend/optimizer/plan/setrefs.c src/backend/parser/gram.y src/backend/parser/parse_utilcmd.c src/backend/postmaster/postmaster.c src/backend/rewrite/rewriteHandler.c src/backend/storage/lmgr/proc.c src/backend/tcop/postgres.c src/backend/utils/adt/ruleutils.c src/backend/utils/init/postinit.c src/backend/utils/misc/guc.c src/backend/utils/misc/postgresql.conf.sample src/backend/utils/sort/tuplesort.c src/bin/initdb/initdb.c src/bin/pg_ctl/pg_ctl.c src/bin/pg_dump/pg_dump.c src/include/access/xlog.h src/include/catalog/catversion.h src/include/catalog/indexing.h src/include/catalog/pg_aggregate.h src/include/catalog/pg_proc.h src/include/commands/copy.h src/include/nodes/parsenodes.h src/include/nodes/primnodes.h src/include/optimizer/pathnode.h src/include/parser/kwlist.h src/include/storage/procarray.h src/test/regress/expected/.gitignore src/test/regress/expected/aggregates.out src/test/regress/expected/alter_table.out src/test/regress/expected/bit.out src/test/regress/expected/box.out src/test/regress/expected/delete.out src/test/regress/expected/float4.out src/test/regress/expected/float8.out src/test/regress/expected/int2.out src/test/regress/expected/int8.out src/test/regress/expected/interval.out src/test/regress/expected/numeric.out src/test/regress/expected/point.out src/test/regress/expected/polygon.out src/test/regress/expected/sequence.out src/test/regress/expected/timestamp.out src/test/regress/expected/timestamptz.out src/test/regress/expected/transactions.out src/test/regress/expected/window.out src/test/regress/input/misc.source src/test/regress/output/create_misc_1.source src/test/regress/output/misc.source src/test/regress/sql/aggregates.sql src/test/regress/sql/alter_table.sql src/test/regress/sql/bit.sql src/test/regress/sql/box.sql src/test/regress/sql/delete.sql src/test/regress/sql/domain.sql src/test/regress/sql/float4.sql src/test/regress/sql/float8.sql src/test/regress/sql/int2.sql src/test/regress/sql/int8.sql src/test/regress/sql/interval.sql src/test/regress/sql/lseg.sql src/test/regress/sql/numeric.sql src/test/regress/sql/path.sql src/test/regress/sql/point.sql src/test/regress/sql/polygon.sql src/test/regress/sql/portals.sql src/test/regress/sql/sequence.sql src/test/regress/sql/timestamp.sql src/test/regress/sql/timestamptz.sql src/test/regress/sql/transactions.sql src/test/regress/sql/window.sql src/test/regress/sql/with.sql
Diffstat (limited to 'contrib/xml2/xpath.c')
-rw-r--r--contrib/xml2/xpath.c173
1 files changed, 99 insertions, 74 deletions
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,