aboutsummaryrefslogtreecommitdiff
path: root/contrib/xml2/xpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/xml2/xpath.c')
-rw-r--r--contrib/xml2/xpath.c854
1 files changed, 435 insertions, 419 deletions
diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c
index 84792ca2484..67ae99fbfbb 100644
--- a/contrib/xml2/xpath.c
+++ b/contrib/xml2/xpath.c
@@ -22,34 +22,34 @@ static void *pgxml_palloc(size_t size);
static void *pgxml_repalloc(void *ptr, size_t size);
static void pgxml_pfree(void *ptr);
static char *pgxml_pstrdup(const char *string);
-static void pgxml_errorHandler (void * ctxt, const char *msg, ...);
+static void pgxml_errorHandler(void *ctxt, const char *msg,...);
-void elog_error(int level, char *explain, int force);
-void pgxml_parser_init(void);
+void elog_error(int level, char *explain, int force);
+void pgxml_parser_init(void);
static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
xmlChar * toptagname, xmlChar * septagname,
xmlChar * plainsep);
-text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
- xmlChar *septag, xmlChar *plainsep);
+text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar * toptag,
+ xmlChar * septag, xmlChar * plainsep);
-xmlChar *pgxml_texttoxmlchar(text *textstring);
+xmlChar *pgxml_texttoxmlchar(text *textstring);
-static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar* xpath);
+static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar * xpath);
Datum xml_valid(PG_FUNCTION_ARGS);
-Datum xpath_nodeset(PG_FUNCTION_ARGS);
+Datum xpath_nodeset(PG_FUNCTION_ARGS);
Datum xpath_string(PG_FUNCTION_ARGS);
Datum xpath_number(PG_FUNCTION_ARGS);
-Datum xpath_bool(PG_FUNCTION_ARGS);
-Datum xpath_list(PG_FUNCTION_ARGS);
-Datum xpath_table(PG_FUNCTION_ARGS);
+Datum xpath_bool(PG_FUNCTION_ARGS);
+Datum xpath_list(PG_FUNCTION_ARGS);
+Datum xpath_table(PG_FUNCTION_ARGS);
/* Global variables */
-char *errbuf; /* per line error buffer */
-char *pgxml_errorMsg = NULL; /* overall error message */
+char *errbuf; /* per line error buffer */
+char *pgxml_errorMsg = NULL; /* overall error message */
/* Convenience macros */
@@ -93,47 +93,47 @@ pgxml_pstrdup(const char *string)
*/
static void
-pgxml_errorHandler (void * ctxt, const char *msg, ...)
+pgxml_errorHandler(void *ctxt, const char *msg,...)
{
- va_list args;
-
- va_start(args, msg);
- vsnprintf(errbuf, ERRBUF_SIZE, msg, args);
- va_end(args);
- /* Now copy the argument across */
- if (pgxml_errorMsg == NULL)
- {
- pgxml_errorMsg = pstrdup(errbuf);
- }
-else
- {
- int32 xsize = strlen(pgxml_errorMsg);
- pgxml_errorMsg = repalloc(pgxml_errorMsg,
- (size_t) (xsize + strlen(errbuf) + 1));
- strncpy(&pgxml_errorMsg[xsize-1],errbuf,strlen(errbuf));
- pgxml_errorMsg[xsize+strlen(errbuf)-1]='\0';
-
- }
- memset(errbuf,0,ERRBUF_SIZE);
+ va_list args;
+
+ va_start(args, msg);
+ vsnprintf(errbuf, ERRBUF_SIZE, msg, args);
+ va_end(args);
+ /* Now copy the argument across */
+ if (pgxml_errorMsg == NULL)
+ pgxml_errorMsg = pstrdup(errbuf);
+ else
+ {
+ int32 xsize = strlen(pgxml_errorMsg);
+
+ pgxml_errorMsg = repalloc(pgxml_errorMsg,
+ (size_t) (xsize + strlen(errbuf) + 1));
+ strncpy(&pgxml_errorMsg[xsize - 1], errbuf, strlen(errbuf));
+ pgxml_errorMsg[xsize + strlen(errbuf) - 1] = '\0';
+
+ }
+ memset(errbuf, 0, ERRBUF_SIZE);
}
/* This function reports the current message at the level specified */
-void elog_error(int level, char *explain, int force)
+void
+elog_error(int level, char *explain, int force)
{
- if (force || (pgxml_errorMsg != NULL))
- {
- if (pgxml_errorMsg == NULL)
+ if (force || (pgxml_errorMsg != NULL))
{
- ereport(level,(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
- errmsg(explain)));
- }
- else
- {
- ereport(level,(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
- errmsg("%s:%s",explain,pgxml_errorMsg)));
- pfree(pgxml_errorMsg);
+ if (pgxml_errorMsg == NULL)
+ {
+ ereport(level, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+ errmsg(explain)));
+ }
+ else
+ {
+ ereport(level, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+ errmsg("%s:%s", explain, pgxml_errorMsg)));
+ pfree(pgxml_errorMsg);
+ }
}
- }
}
void
@@ -155,7 +155,7 @@ pgxml_parser_init()
pgxml_errorMsg = NULL;
errbuf = palloc(200);
- memset(errbuf,0,200);
+ memset(errbuf, 0, 200);
}
@@ -191,7 +191,7 @@ static xmlChar
pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
xmlChar * toptagname,
xmlChar * septagname,
- xmlChar * plainsep)
+ xmlChar * plainsep)
{
/* Function translates a nodeset into a text representation */
@@ -201,9 +201,12 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
*/
/* each representation is surrounded by <tagname> ... </tagname> */
- /* plainsep is an ordinary (not tag) seperator - if used, then
- * nodes are cast to string as output method */
-
+
+ /*
+ * plainsep is an ordinary (not tag) seperator - if used, then nodes
+ * are cast to string as output method
+ */
+
xmlBufferPtr buf;
xmlChar *result;
@@ -222,35 +225,37 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
for (i = 0; i < nodeset->nodeNr; i++)
{
- if (plainsep != NULL) {
- xmlBufferWriteCHAR(buf,
- xmlXPathCastNodeToString(nodeset->nodeTab[i]));
-
- /* If this isn't the last entry, write the plain sep. */
- if (i < (nodeset->nodeNr)-1) {
- xmlBufferWriteChar(buf, plainsep);
- }
- } else {
-
-
- if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
+ if (plainsep != NULL)
{
- xmlBufferWriteChar(buf, "<");
- xmlBufferWriteCHAR(buf, septagname);
- xmlBufferWriteChar(buf, ">");
- }
- xmlNodeDump(buf,
- nodeset->nodeTab[i]->doc,
- nodeset->nodeTab[i],
- 1, 0);
+ xmlBufferWriteCHAR(buf,
+ xmlXPathCastNodeToString(nodeset->nodeTab[i]));
- if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
+ /* If this isn't the last entry, write the plain sep. */
+ if (i < (nodeset->nodeNr) - 1)
+ xmlBufferWriteChar(buf, plainsep);
+ }
+ else
{
- xmlBufferWriteChar(buf, "</");
- xmlBufferWriteCHAR(buf, septagname);
- xmlBufferWriteChar(buf, ">");
+
+
+ if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
+ {
+ xmlBufferWriteChar(buf, "<");
+ xmlBufferWriteCHAR(buf, septagname);
+ xmlBufferWriteChar(buf, ">");
+ }
+ xmlNodeDump(buf,
+ nodeset->nodeTab[i]->doc,
+ nodeset->nodeTab[i],
+ 1, 0);
+
+ if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
+ {
+ xmlBufferWriteChar(buf, "</");
+ xmlBufferWriteCHAR(buf, septagname);
+ xmlBufferWriteChar(buf, ">");
+ }
}
- }
}
}
@@ -294,11 +299,13 @@ PG_FUNCTION_INFO_V1(xpath_nodeset);
Datum
xpath_nodeset(PG_FUNCTION_ARGS)
{
- xmlChar *xpath, *toptag, *septag;
- int32 pathsize;
- text
- *xpathsupp,
- *xpres;
+ 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 */
@@ -311,32 +318,31 @@ xpath_nodeset(PG_FUNCTION_ARGS)
xpath = pgxml_texttoxmlchar(xpathsupp);
xpres = pgxml_result_to_text(
- pgxml_xpath(PG_GETARG_TEXT_P(0),xpath),
- toptag,septag,NULL);
+ pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
+ toptag, septag, NULL);
/* xmlCleanupParser(); done by result_to_text routine */
pfree((void *) xpath);
- if (xpres == NULL)
- {
- PG_RETURN_NULL();
- }
+ if (xpres == NULL)
+ PG_RETURN_NULL();
PG_RETURN_TEXT_P(xpres);
}
-// The following function is almost identical, but returns the elements in
-// a list.
+/* The following function is almost identical, but returns the elements in */
+/* a list. */
PG_FUNCTION_INFO_V1(xpath_list);
Datum
xpath_list(PG_FUNCTION_ARGS)
{
- xmlChar *xpath, *plainsep;
- int32 pathsize;
- text
- *xpathsupp,
- *xpres;
+ xmlChar *xpath,
+ *plainsep;
+ int32 pathsize;
+ text
+ *xpathsupp,
+ *xpres;
/* PG_GETARG_TEXT_P(0) is document buffer */
xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
@@ -348,16 +354,14 @@ xpath_list(PG_FUNCTION_ARGS)
xpath = pgxml_texttoxmlchar(xpathsupp);
xpres = pgxml_result_to_text(
- pgxml_xpath(PG_GETARG_TEXT_P(0),xpath),
- NULL,NULL,plainsep);
+ pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
+ NULL, NULL, plainsep);
/* xmlCleanupParser(); done by result_to_text routine */
pfree((void *) xpath);
- if (xpres == NULL)
- {
- PG_RETURN_NULL();
- }
+ if (xpres == NULL)
+ PG_RETURN_NULL();
PG_RETURN_TEXT_P(xpres);
}
@@ -367,38 +371,38 @@ PG_FUNCTION_INFO_V1(xpath_string);
Datum
xpath_string(PG_FUNCTION_ARGS)
{
- xmlChar *xpath;
- int32 pathsize;
- text
- *xpathsupp,
- *xpres;
+ xmlChar *xpath;
+ int32 pathsize;
+ text
+ *xpathsupp,
+ *xpres;
/* PG_GETARG_TEXT_P(0) is document buffer */
xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */
pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
- /* We encapsulate the supplied path with "string()"
- * = 8 chars + 1 for NUL at end */
+ /*
+ * We encapsulate the supplied path with "string()" = 8 chars + 1 for
+ * NUL at end
+ */
/* 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);
- xpath[pathsize+7] = ')';
- xpath[pathsize+8] = '\0';
+ xpath = (xmlChar *) palloc(pathsize + 9);
+ memcpy((char *) (xpath + 7), VARDATA(xpathsupp), pathsize);
+ strncpy((char *) xpath, "string(", 7);
+ xpath[pathsize + 7] = ')';
+ xpath[pathsize + 8] = '\0';
xpres = pgxml_result_to_text(
- pgxml_xpath(PG_GETARG_TEXT_P(0),xpath),
- NULL,NULL,NULL);
+ pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
+ NULL, NULL, NULL);
xmlCleanupParser();
pfree((void *) xpath);
- if (xpres == NULL)
- {
- PG_RETURN_NULL();
- }
+ if (xpres == NULL)
+ PG_RETURN_NULL();
PG_RETURN_TEXT_P(xpres);
}
@@ -408,12 +412,12 @@ PG_FUNCTION_INFO_V1(xpath_number);
Datum
xpath_number(PG_FUNCTION_ARGS)
{
- xmlChar *xpath;
- int32 pathsize;
- text
- *xpathsupp;
-
- float4 fRes;
+ xmlChar *xpath;
+ int32 pathsize;
+ text
+ *xpathsupp;
+
+ float4 fRes;
xmlXPathObjectPtr res;
@@ -424,21 +428,19 @@ xpath_number(PG_FUNCTION_ARGS)
xpath = pgxml_texttoxmlchar(xpathsupp);
- res = pgxml_xpath(PG_GETARG_TEXT_P(0),xpath);
+ res = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath);
pfree((void *) xpath);
if (res == NULL)
- {
- xmlCleanupParser();
- PG_RETURN_NULL();
- }
+ {
+ xmlCleanupParser();
+ PG_RETURN_NULL();
+ }
fRes = xmlXPathCastToNumber(res);
xmlCleanupParser();
if (xmlXPathIsNaN(fRes))
- {
- PG_RETURN_NULL();
- }
+ PG_RETURN_NULL();
PG_RETURN_FLOAT4(fRes);
@@ -450,12 +452,12 @@ PG_FUNCTION_INFO_V1(xpath_bool);
Datum
xpath_bool(PG_FUNCTION_ARGS)
{
- xmlChar *xpath;
- int32 pathsize;
- text
- *xpathsupp;
-
- int bRes;
+ xmlChar *xpath;
+ int32 pathsize;
+ text
+ *xpathsupp;
+
+ int bRes;
xmlXPathObjectPtr res;
@@ -466,14 +468,14 @@ xpath_bool(PG_FUNCTION_ARGS)
xpath = pgxml_texttoxmlchar(xpathsupp);
- res = pgxml_xpath(PG_GETARG_TEXT_P(0),xpath);
+ res = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath);
pfree((void *) xpath);
if (res == NULL)
- {
- xmlCleanupParser();
- PG_RETURN_BOOL(false);
- }
+ {
+ xmlCleanupParser();
+ PG_RETURN_BOOL(false);
+ }
bRes = xmlXPathCastToBoolean(res);
xmlCleanupParser();
@@ -486,8 +488,8 @@ xpath_bool(PG_FUNCTION_ARGS)
/* Core function to evaluate XPath query */
xmlXPathObjectPtr
- pgxml_xpath(text *document, xmlChar *xpath)
- {
+pgxml_xpath(text *document, xmlChar * xpath)
+{
xmlDocPtr doctree;
xmlXPathContextPtr ctxt;
@@ -497,14 +499,14 @@ xmlXPathObjectPtr
int32 docsize;
-
+
docsize = VARSIZE(document) - VARHDRSZ;
pgxml_parser_init();
doctree = xmlParseMemory((char *) VARDATA(document), docsize);
if (doctree == NULL)
- { /* not well-formed */
+ { /* not well-formed */
return NULL;
}
@@ -518,9 +520,9 @@ xmlXPathObjectPtr
{
xmlCleanupParser();
xmlFreeDoc(doctree);
- elog_error(ERROR,"XPath Syntax Error",1);
+ elog_error(ERROR, "XPath Syntax Error", 1);
- return NULL;
+ return NULL;
}
/* Now evaluate the path expression. */
@@ -529,36 +531,35 @@ xmlXPathObjectPtr
if (res == NULL)
{
- xmlXPathFreeContext(ctxt);
- // xmlCleanupParser();
+ xmlXPathFreeContext(ctxt);
+ /* xmlCleanupParser(); */
xmlFreeDoc(doctree);
return NULL;
}
/* xmlFreeDoc(doctree); */
return res;
- }
+}
-text
-*pgxml_result_to_text(xmlXPathObjectPtr res,
- xmlChar *toptag,
- xmlChar *septag,
- xmlChar *plainsep)
+text
+ *
+pgxml_result_to_text(xmlXPathObjectPtr res,
+ xmlChar * toptag,
+ xmlChar * septag,
+ xmlChar * plainsep)
{
- xmlChar *xpresstr;
- int32 ressize;
- text *xpres;
-
- if (res == NULL)
- {
- return NULL;
- }
+ xmlChar *xpresstr;
+ int32 ressize;
+ text *xpres;
+
+ if (res == NULL)
+ return NULL;
switch (res->type)
{
case XPATH_NODESET:
xpresstr = pgxmlNodeSetToText(res->nodesetval,
- toptag,
- septag, plainsep);
+ toptag,
+ septag, plainsep);
break;
case XPATH_STRING:
@@ -583,7 +584,7 @@ text
xmlFree(xpresstr);
- elog_error(ERROR,"XPath error",0);
+ elog_error(ERROR, "XPath error", 0);
return xpres;
@@ -595,299 +596,314 @@ text
PG_FUNCTION_INFO_V1(xpath_table);
-Datum xpath_table(PG_FUNCTION_ARGS)
+Datum
+xpath_table(PG_FUNCTION_ARGS)
{
/* SPI (input tuple) support */
- SPITupleTable *tuptable;
- HeapTuple spi_tuple;
- TupleDesc spi_tupdesc;
+ SPITupleTable *tuptable;
+ HeapTuple spi_tuple;
+ TupleDesc spi_tupdesc;
/* Output tuple (tuplestore) support */
- Tuplestorestate *tupstore = NULL;
- TupleDesc ret_tupdesc;
- HeapTuple ret_tuple;
-
- ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
- AttInMetadata *attinmeta;
- MemoryContext per_query_ctx;
- MemoryContext oldcontext;
-
-/* Function parameters */
- char *pkeyfield = GET_STR(PG_GETARG_TEXT_P(0));
- char *xmlfield = GET_STR(PG_GETARG_TEXT_P(1));
- char *relname = GET_STR(PG_GETARG_TEXT_P(2));
- char *xpathset = GET_STR(PG_GETARG_TEXT_P(3));
- char *condition = GET_STR(PG_GETARG_TEXT_P(4));
-
- char **values;
- xmlChar **xpaths;
- xmlChar *pos;
- xmlChar *pathsep= "|";
-
- int numpaths;
- int ret;
- int proc;
- int i;
- int j;
- int rownr; /* For issuing multiple rows from one original document */
- int had_values; /* To determine end of nodeset results */
-
- StringInfo querysql;
+ Tuplestorestate *tupstore = NULL;
+ TupleDesc ret_tupdesc;
+ HeapTuple ret_tuple;
+
+ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ AttInMetadata *attinmeta;
+ MemoryContext per_query_ctx;
+ MemoryContext oldcontext;
+
+/* Function parameters */
+ char *pkeyfield = GET_STR(PG_GETARG_TEXT_P(0));
+ char *xmlfield = GET_STR(PG_GETARG_TEXT_P(1));
+ char *relname = GET_STR(PG_GETARG_TEXT_P(2));
+ char *xpathset = GET_STR(PG_GETARG_TEXT_P(3));
+ char *condition = GET_STR(PG_GETARG_TEXT_P(4));
+
+ char **values;
+ xmlChar **xpaths;
+ xmlChar *pos;
+ xmlChar *pathsep = "|";
+
+ int numpaths;
+ int ret;
+ int proc;
+ int i;
+ int j;
+ int rownr; /* For issuing multiple rows from one
+ * original document */
+ int had_values; /* To determine end of nodeset results */
+
+ StringInfo querysql;
/* We only have a valid tuple description in table function mode */
- if (rsinfo->expectedDesc == NULL) {
- ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("xpath_table must be called as a table function")));
- }
-
-/* The tuplestore must exist in a higher context than
+ if (rsinfo->expectedDesc == NULL)
+ {
+ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("xpath_table must be called as a table function")));
+ }
+
+/* The tuplestore must exist in a higher context than
* this function call (per_query_ctx is used) */
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
+ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+ oldcontext = MemoryContextSwitchTo(per_query_ctx);
/* Create the tuplestore - work_mem is the max in-memory size before a
* file is created on disk to hold it.
*/
- tupstore = tuplestore_begin_heap(true, false, work_mem);
+ tupstore = tuplestore_begin_heap(true, false, work_mem);
- MemoryContextSwitchTo(oldcontext);
+ MemoryContextSwitchTo(oldcontext);
- /* get the requested return tuple description */
- ret_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ /* get the requested return tuple description */
+ ret_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
- /* At the moment we assume that the returned attributes make sense
- * for the XPath specififed (i.e. we trust the caller).
- * It's not fatal if they get it wrong - the input function for the
- * column type will raise an error if the path result can't be converted
- * into the correct binary representation.
- */
+ /*
+ * At the moment we assume that the returned attributes make sense for
+ * the XPath specififed (i.e. we trust the caller). It's not fatal if
+ * they get it wrong - the input function for the column type will
+ * raise an error if the path result can't be converted into the
+ * correct binary representation.
+ */
- attinmeta = TupleDescGetAttInMetadata(ret_tupdesc);
+ attinmeta = TupleDescGetAttInMetadata(ret_tupdesc);
- /* We want to materialise because it means that we don't have to
- * carry libxml2 parser state between invocations of this function
- */
+ /*
+ * We want to materialise because it means that we don't have to carry
+ * libxml2 parser state between invocations of this function
+ */
- /* check to see if caller supports us returning a tuplestore */
- if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
- ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("xpath_table requires Materialize mode, but it is not "
- "allowed in this context")));
+ /* check to see if caller supports us returning a tuplestore */
+ if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("xpath_table requires Materialize mode, but it is not "
+ "allowed in this context")));
- // Set return mode and allocate value space.
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setDesc = ret_tupdesc;
-
- values = (char **) palloc(ret_tupdesc->natts * sizeof(char *));
+ /* Set return mode and allocate value space. */
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setDesc = ret_tupdesc;
- xpaths = (xmlChar **) palloc(ret_tupdesc->natts * sizeof(xmlChar *));
+ values = (char **) palloc(ret_tupdesc->natts * sizeof(char *));
- /* Split XPaths. xpathset is a writable CString. */
+ xpaths = (xmlChar **) palloc(ret_tupdesc->natts * sizeof(xmlChar *));
- /* Note that we stop splitting once we've done all needed for tupdesc */
+ /* Split XPaths. xpathset is a writable CString. */
- numpaths=0;
- pos = xpathset;
- do {
- xpaths[numpaths] = pos;
- pos = strstr(pos,pathsep);
- if (pos != NULL) {
- *pos = '\0';
- pos++;
- }
- numpaths++;
- } while ((pos != NULL) && (numpaths < (ret_tupdesc->natts - 1) ));
+ /* Note that we stop splitting once we've done all needed for tupdesc */
- /* Now build query */
+ numpaths = 0;
+ pos = xpathset;
+ do
+ {
+ xpaths[numpaths] = pos;
+ pos = strstr(pos, pathsep);
+ if (pos != NULL)
+ {
+ *pos = '\0';
+ pos++;
+ }
+ numpaths++;
+ } while ((pos != NULL) && (numpaths < (ret_tupdesc->natts - 1)));
+
+ /* Now build query */
- querysql = makeStringInfo();
+ querysql = makeStringInfo();
- /* Build initial sql statement */
- appendStringInfo(querysql, "SELECT %s, %s FROM %s WHERE %s",
- pkeyfield,
- xmlfield,
- relname,
- condition
- );
+ /* Build initial sql statement */
+ appendStringInfo(querysql, "SELECT %s, %s FROM %s WHERE %s",
+ pkeyfield,
+ xmlfield,
+ relname,
+ condition
+ );
- if ((ret = SPI_connect()) < 0) {
- elog(ERROR, "xpath_table: SPI_connect returned %d", ret);
- }
+ if ((ret = SPI_connect()) < 0)
+ elog(ERROR, "xpath_table: SPI_connect returned %d", ret);
- if ((ret = SPI_exec(querysql->data,0)) != SPI_OK_SELECT) {
- elog(ERROR,"xpath_table: SPI execution failed for query %s",querysql->data);
- }
+ if ((ret = SPI_exec(querysql->data, 0)) != SPI_OK_SELECT)
+ elog(ERROR, "xpath_table: SPI execution failed for query %s", querysql->data);
- proc= SPI_processed;
- /* elog(DEBUG1,"xpath_table: SPI returned %d rows",proc); */
- tuptable = SPI_tuptable;
- spi_tupdesc = tuptable->tupdesc;
+ proc = SPI_processed;
+ /* elog(DEBUG1,"xpath_table: SPI returned %d rows",proc); */
+ tuptable = SPI_tuptable;
+ spi_tupdesc = tuptable->tupdesc;
/* Switch out of SPI context */
- MemoryContextSwitchTo(oldcontext);
+ MemoryContextSwitchTo(oldcontext);
/* Check that SPI returned correct result. If you put a comma into one of
* the function parameters, this will catch it when the SPI query returns
- * e.g. 3 columns.
+ * e.g. 3 columns.
*/
- if (spi_tupdesc->natts != 2) {
- ereport(ERROR,(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("Expression returning multiple columns is not valid in parameter list"),
- errdetail("Expected two columns in SPI result, got %d",spi_tupdesc->natts)));
- }
+ if (spi_tupdesc->natts != 2)
+ {
+ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Expression returning multiple columns is not valid in parameter list"),
+ errdetail("Expected two columns in SPI result, got %d", spi_tupdesc->natts)));
+ }
/* Setup the parser. Beware that this must happen in the same context as the
* cleanup - which means that any error from here on must do cleanup to
* ensure that the entity table doesn't get freed by being out of context.
*/
- pgxml_parser_init();
-
- /* For each row i.e. document returned from SPI */
- for (i=0; i < proc; i++) {
- char *pkey;
- char *xmldoc;
-
- xmlDocPtr doctree;
- xmlXPathContextPtr ctxt;
- xmlXPathObjectPtr res;
- xmlChar *resstr;
-
-
- xmlXPathCompExprPtr comppath;
-
- /* Extract the row data as C Strings */
-
- spi_tuple = tuptable->vals[i];
- pkey = SPI_getvalue(spi_tuple, spi_tupdesc,1);
- xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc,2);
-
-
- /* Clear the values array, so that not-well-formed documents
- * return NULL in all columns.
- */
-
- /* Note that this also means that spare columns will be NULL. */
- for (j=0; j < ret_tupdesc->natts; j++) {
- values[j]= NULL;
- }
-
- /* Insert primary key */
- values[0]=pkey;
-
- /* Parse the document */
- doctree = xmlParseMemory(xmldoc, strlen(xmldoc));
-
- if (doctree == NULL)
- { /* not well-formed, so output all-NULL tuple */
-
- ret_tuple = BuildTupleFromCStrings(attinmeta, values);
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
- tuplestore_puttuple(tupstore, ret_tuple);
- MemoryContextSwitchTo(oldcontext);
- heap_freetuple(ret_tuple);
- }
- else
- {
- /* New loop here - we have to deal with nodeset results */
- rownr=0;
-
- do {
- /* Now evaluate the set of xpaths. */
- had_values=0;
- for (j=0; j < numpaths; j++) {
-
- ctxt = xmlXPathNewContext(doctree);
- ctxt->node = xmlDocGetRootElement(doctree);
- xmlSetGenericErrorFunc(ctxt, pgxml_errorHandler);
-
- /* compile the path */
- comppath = xmlXPathCompile(xpaths[j]);
- if (comppath == NULL)
- {
- xmlCleanupParser();
- xmlFreeDoc(doctree);
-
- elog_error(ERROR,"XPath Syntax Error",1);
-
- PG_RETURN_NULL(); /* Keep compiler happy */
- }
-
- /* Now evaluate the path expression. */
- res = xmlXPathCompiledEval(comppath, ctxt);
- xmlXPathFreeCompExpr(comppath);
-
- if (res != NULL)
- {
- switch (res->type)
- {
- case XPATH_NODESET:
- /* We see if this nodeset has enough nodes */
- if ((res->nodesetval != NULL) && (rownr < res->nodesetval->nodeNr)) {
- resstr =
- xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]);
- had_values=1;
- } else {
- resstr = NULL;
- }
-
- break;
-
- case XPATH_STRING:
- resstr = xmlStrdup(res->stringval);
- break;
-
- default:
- elog(NOTICE, "Unsupported XQuery result: %d", res->type);
- resstr = xmlStrdup("<unsupported/>");
- }
-
-
- // Insert this into the appropriate column in the result tuple.
- values[j+1] = resstr;
- }
- xmlXPathFreeContext(ctxt);
- }
- // Now add the tuple to the output, if there is one.
- if (had_values) {
- ret_tuple = BuildTupleFromCStrings(attinmeta, values);
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
- tuplestore_puttuple(tupstore, ret_tuple);
- MemoryContextSwitchTo(oldcontext);
- heap_freetuple(ret_tuple);
- }
-
- rownr++;
-
- } while (had_values);
-
- }
-
- xmlFreeDoc(doctree);
-
- pfree(pkey);
- pfree(xmldoc);
- }
-
- xmlCleanupParser();
+ pgxml_parser_init();
+
+ /* For each row i.e. document returned from SPI */
+ for (i = 0; i < proc; i++)
+ {
+ char *pkey;
+ char *xmldoc;
+
+ xmlDocPtr doctree;
+ xmlXPathContextPtr ctxt;
+ xmlXPathObjectPtr res;
+ xmlChar *resstr;
+
+
+ xmlXPathCompExprPtr comppath;
+
+ /* Extract the row data as C Strings */
+
+ spi_tuple = tuptable->vals[i];
+ pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
+ xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2);
+
+
+ /*
+ * Clear the values array, so that not-well-formed documents
+ * return NULL in all columns.
+ */
+
+ /* Note that this also means that spare columns will be NULL. */
+ for (j = 0; j < ret_tupdesc->natts; j++)
+ values[j] = NULL;
+
+ /* Insert primary key */
+ values[0] = pkey;
+
+ /* Parse the document */
+ doctree = xmlParseMemory(xmldoc, strlen(xmldoc));
+
+ if (doctree == NULL)
+ { /* not well-formed, so output all-NULL
+ * tuple */
+
+ ret_tuple = BuildTupleFromCStrings(attinmeta, values);
+ oldcontext = MemoryContextSwitchTo(per_query_ctx);
+ tuplestore_puttuple(tupstore, ret_tuple);
+ MemoryContextSwitchTo(oldcontext);
+ heap_freetuple(ret_tuple);
+ }
+ else
+ {
+ /* New loop here - we have to deal with nodeset results */
+ rownr = 0;
+
+ do
+ {
+ /* Now evaluate the set of xpaths. */
+ had_values = 0;
+ for (j = 0; j < numpaths; j++)
+ {
+
+ ctxt = xmlXPathNewContext(doctree);
+ ctxt->node = xmlDocGetRootElement(doctree);
+ xmlSetGenericErrorFunc(ctxt, pgxml_errorHandler);
+
+ /* compile the path */
+ comppath = xmlXPathCompile(xpaths[j]);
+ if (comppath == NULL)
+ {
+ xmlCleanupParser();
+ xmlFreeDoc(doctree);
+
+ elog_error(ERROR, "XPath Syntax Error", 1);
+
+ PG_RETURN_NULL(); /* Keep compiler happy */
+ }
+
+ /* Now evaluate the path expression. */
+ res = xmlXPathCompiledEval(comppath, ctxt);
+ xmlXPathFreeCompExpr(comppath);
+
+ if (res != NULL)
+ {
+ switch (res->type)
+ {
+ case XPATH_NODESET:
+ /* We see if this nodeset has enough nodes */
+ if ((res->nodesetval != NULL) && (rownr < res->nodesetval->nodeNr))
+ {
+ resstr =
+ xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]);
+ had_values = 1;
+ }
+ else
+ resstr = NULL;
+
+ break;
+
+ case XPATH_STRING:
+ resstr = xmlStrdup(res->stringval);
+ break;
+
+ default:
+ elog(NOTICE, "Unsupported XQuery result: %d", res->type);
+ resstr = xmlStrdup("<unsupported/>");
+ }
+
+
+ /*
+ * Insert this into the appropriate column in the
+ * result tuple.
+ */
+ values[j + 1] = resstr;
+ }
+ xmlXPathFreeContext(ctxt);
+ }
+ /* Now add the tuple to the output, if there is one. */
+ if (had_values)
+ {
+ ret_tuple = BuildTupleFromCStrings(attinmeta, values);
+ oldcontext = MemoryContextSwitchTo(per_query_ctx);
+ tuplestore_puttuple(tupstore, ret_tuple);
+ MemoryContextSwitchTo(oldcontext);
+ heap_freetuple(ret_tuple);
+ }
+
+ rownr++;
+
+ } while (had_values);
+
+ }
+
+ xmlFreeDoc(doctree);
+
+ pfree(pkey);
+ pfree(xmldoc);
+ }
+
+ xmlCleanupParser();
/* Needed to flag completeness in 7.3.1. 7.4 defines it as a no-op. */
- tuplestore_donestoring(tupstore);
-
- SPI_finish();
-
- rsinfo->setResult=tupstore;
-
- /*
- * SFRM_Materialize mode expects us to return a NULL Datum. The actual
- * tuples are in our tuplestore and passed back through
- * rsinfo->setResult. rsinfo->setDesc is set to the tuple description
- * that we actually used to build our tuples with, so the caller can
- * verify we did what it was expecting.
- */
- return (Datum) 0;
-
+ tuplestore_donestoring(tupstore);
+
+ SPI_finish();
+
+ rsinfo->setResult = tupstore;
+
+ /*
+ * SFRM_Materialize mode expects us to return a NULL Datum. The actual
+ * tuples are in our tuplestore and passed back through
+ * rsinfo->setResult. rsinfo->setDesc is set to the tuple description
+ * that we actually used to build our tuples with, so the caller can
+ * verify we did what it was expecting.
+ */
+ return (Datum) 0;
+
}