diff options
author | Bruce Momjian | 2004-03-05 03:57:58 +0000 |
---|---|---|
committer | Bruce Momjian | 2004-03-05 03:57:58 +0000 |
commit | 31f4b59a464808ab0fec0ffb2eaa723321ea1af7 (patch) | |
tree | 004f71d1eb77899fa9e16ac8047189dcde6576e5 /contrib/xml/xpath.c | |
parent | adca025c9ec4b3050411eb74a5b4f9c20a4ce2b5 (diff) |
Move new version of contrib/ xml into xml2, keep old version in /xml.
Diffstat (limited to 'contrib/xml/xpath.c')
-rw-r--r-- | contrib/xml/xpath.c | 893 |
1 files changed, 0 insertions, 893 deletions
diff --git a/contrib/xml/xpath.c b/contrib/xml/xpath.c deleted file mode 100644 index b4fc8287986..00000000000 --- a/contrib/xml/xpath.c +++ /dev/null @@ -1,893 +0,0 @@ -/* Parser interface for DOM-based parser (libxml) rather than - stream-based SAX-type parser */ - -#include "postgres.h" -#include "fmgr.h" -#include "executor/spi.h" -#include "funcapi.h" -#include "miscadmin.h" -#include "lib/stringinfo.h" - -/* libxml includes */ - -#include <libxml/xpath.h> -#include <libxml/tree.h> -#include <libxml/xmlmemory.h> -#include <libxml/xmlerror.h> -#include <libxml/parserInternals.h> - -/* declarations */ - -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, ...); - -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); - -xmlChar *pgxml_texttoxmlchar(text *textstring); - -static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar* xpath); - - -Datum pgxml_parse(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); - -/* Global variables */ -char *errbuf; /* per line error buffer */ -char *pgxml_errorMsg = NULL; /* overall error message */ - -/* Convenience macros */ - -#define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp))) -#define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp))) - -#define ERRBUF_SIZE 200 - -/* memory handling passthrough functions (e.g. palloc, pstrdup are - currently macros, and the others might become so...) */ - -static void * -pgxml_palloc(size_t size) -{ -/* elog(DEBUG1,"Alloc %d in CMC %x",size,CurrentMemoryContext); */ - return palloc(size); -} - -static void * -pgxml_repalloc(void *ptr, size_t size) -{ -/* elog(DEBUG1,"ReAlloc in CMC %x",CurrentMemoryContext);*/ - return repalloc(ptr, size); -} - -static void -pgxml_pfree(void *ptr) -{ -/* elog(DEBUG1,"Free in CMC %x",CurrentMemoryContext); */ - return pfree(ptr); -} - -static char * -pgxml_pstrdup(const char *string) -{ - return pstrdup(string); -} - -/* The error handling function. This formats an error message and sets - * a flag - an ereport will be issued prior to return - */ - -static void -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); -} - -/* This function reports the current message at the level specified */ -void elog_error(int level, char *explain, int force) -{ - if (force || (pgxml_errorMsg != NULL)) - { - 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 -pgxml_parser_init() -{ - /* - * This code could also set parser settings from user-supplied info. - * Quite how these settings are made is another matter :) - */ - - xmlMemSetup(pgxml_pfree, pgxml_palloc, pgxml_repalloc, pgxml_pstrdup); - xmlInitParser(); - - xmlSetGenericErrorFunc(NULL, pgxml_errorHandler); - - xmlSubstituteEntitiesDefault(1); - xmlLoadExtDtdDefaultValue = 1; - - pgxml_errorMsg = NULL; - - errbuf = palloc(200); - memset(errbuf,0,200); - -} - - -/* Returns true if document is well-formed */ - -PG_FUNCTION_INFO_V1(pgxml_parse); - -Datum -pgxml_parse(PG_FUNCTION_ARGS) -{ - /* called as pgxml_parse(document) */ - xmlDocPtr doctree; - text *t = PG_GETARG_TEXT_P(0); /* document buffer */ - int32 docsize = VARSIZE(t) - VARHDRSZ; - - pgxml_parser_init(); - - doctree = xmlParseMemory((char *) VARDATA(t), docsize); - if (doctree == NULL) - { - xmlCleanupParser(); - PG_RETURN_BOOL(false); /* i.e. not well-formed */ - } - xmlCleanupParser(); - xmlFreeDoc(doctree); - PG_RETURN_BOOL(true); -} - - -static xmlChar -* -pgxmlNodeSetToText(xmlNodeSetPtr nodeset, - xmlChar * toptagname, - xmlChar * septagname, - xmlChar * plainsep) -{ - /* Function translates a nodeset into a text representation */ - - /* - * iterates over each node in the set and calls xmlNodeDump to write - * it to an xmlBuffer -from which an xmlChar * string is returned. - */ - - /* 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 */ - - - xmlBufferPtr buf; - xmlChar *result; - int i; - - buf = xmlBufferCreate(); - - if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0)) - { - xmlBufferWriteChar(buf, "<"); - xmlBufferWriteCHAR(buf, toptagname); - xmlBufferWriteChar(buf, ">"); - } - if (nodeset != NULL) - { - 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)) - { - 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, ">"); - } - } - } - } - - if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0)) - { - xmlBufferWriteChar(buf, "</"); - xmlBufferWriteCHAR(buf, toptagname); - xmlBufferWriteChar(buf, ">"); - } - result = xmlStrdup(buf->content); - xmlBufferFree(buf); - return result; -} - - -/* Translate a PostgreSQL "varlena" -i.e. a variable length parameter - * into the libxml2 representation - */ - -xmlChar * -pgxml_texttoxmlchar(text *textstring) -{ - xmlChar *res; - int32 txsize; - - txsize = VARSIZE(textstring) - VARHDRSZ; - res = (xmlChar *) palloc(txsize + 1); - memcpy((char *) res, VARDATA(textstring), txsize); - res[txsize] = '\0'; - return res; -} - -/* Public visible XPath functions */ - -/* This is a "raw" xpath function. Check that it returns child elements - * properly - */ - -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 */ - - toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2)); - septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3)); - - pathsize = VARSIZE(xpathsupp) - VARHDRSZ; - - xpath = pgxml_texttoxmlchar(xpathsupp); - - xpres = pgxml_result_to_text( - 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(); - } - PG_RETURN_TEXT_P(xpres); -} - -// 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; - - /* PG_GETARG_TEXT_P(0) is document buffer */ - xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */ - - plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2)); - - pathsize = VARSIZE(xpathsupp) - VARHDRSZ; - - xpath = pgxml_texttoxmlchar(xpathsupp); - - xpres = pgxml_result_to_text( - 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(); - } - PG_RETURN_TEXT_P(xpres); -} - - -PG_FUNCTION_INFO_V1(xpath_string); - -Datum -xpath_string(PG_FUNCTION_ARGS) -{ - 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 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'; - - xpres = pgxml_result_to_text( - pgxml_xpath(PG_GETARG_TEXT_P(0),xpath), - NULL,NULL,NULL); - - xmlCleanupParser(); - pfree((void *) xpath); - - if (xpres == NULL) - { - PG_RETURN_NULL(); - } - PG_RETURN_TEXT_P(xpres); -} - - -PG_FUNCTION_INFO_V1(xpath_number); - -Datum -xpath_number(PG_FUNCTION_ARGS) -{ - 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 = pgxml_texttoxmlchar(xpathsupp); - - res = pgxml_xpath(PG_GETARG_TEXT_P(0),xpath); - pfree((void *) xpath); - - if (res == NULL) - { - xmlCleanupParser(); - PG_RETURN_NULL(); - } - - fRes = xmlXPathCastToNumber(res); - xmlCleanupParser(); - if (xmlXPathIsNaN(fRes)) - { - PG_RETURN_NULL(); - } - - PG_RETURN_FLOAT4(fRes); - -} - - -PG_FUNCTION_INFO_V1(xpath_bool); - -Datum -xpath_bool(PG_FUNCTION_ARGS) -{ - 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 = pgxml_texttoxmlchar(xpathsupp); - - res = pgxml_xpath(PG_GETARG_TEXT_P(0),xpath); - pfree((void *) xpath); - - if (res == NULL) - { - xmlCleanupParser(); - PG_RETURN_BOOL(false); - } - - bRes = xmlXPathCastToBoolean(res); - xmlCleanupParser(); - PG_RETURN_BOOL(bRes); - -} - - - -/* Core function to evaluate XPath query */ - -xmlXPathObjectPtr - pgxml_xpath(text *document, xmlChar *xpath) - { - - xmlDocPtr doctree; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - - xmlXPathCompExprPtr comppath; - - int32 docsize; - - - docsize = VARSIZE(document) - VARHDRSZ; - - pgxml_parser_init(); - - doctree = xmlParseMemory((char *) VARDATA(document), docsize); - if (doctree == NULL) - { /* not well-formed */ - return NULL; - } - - ctxt = xmlXPathNewContext(doctree); - ctxt->node = xmlDocGetRootElement(doctree); - - - /* compile the path */ - comppath = xmlXPathCompile(xpath); - if (comppath == NULL) - { - xmlCleanupParser(); - xmlFreeDoc(doctree); - elog_error(ERROR,"XPath Syntax Error",1); - - return NULL; - } - - /* Now evaluate the path expression. */ - res = xmlXPathCompiledEval(comppath, ctxt); - xmlXPathFreeCompExpr(comppath); - - if (res == NULL) - { - xmlXPathFreeContext(ctxt); - // xmlCleanupParser(); - xmlFreeDoc(doctree); - - return NULL; - } - /* xmlFreeDoc(doctree); */ - return res; - } - -text -*pgxml_result_to_text(xmlXPathObjectPtr res, - xmlChar *toptag, - xmlChar *septag, - xmlChar *plainsep) -{ - xmlChar *xpresstr; - int32 ressize; - text *xpres; - - if (res == NULL) - { - return NULL; - } - switch (res->type) - { - case XPATH_NODESET: - xpresstr = pgxmlNodeSetToText(res->nodesetval, - toptag, - septag, plainsep); - break; - - case XPATH_STRING: - xpresstr = xmlStrdup(res->stringval); - break; - - default: - elog(NOTICE, "Unsupported XQuery result: %d", res->type); - xpresstr = xmlStrdup("<unsupported/>"); - } - - - /* Now convert this result back to text */ - ressize = strlen(xpresstr); - xpres = (text *) palloc(ressize + VARHDRSZ); - memcpy(VARDATA(xpres), xpresstr, ressize); - VARATT_SIZEP(xpres) = ressize + VARHDRSZ; - - /* Free various storage */ - xmlCleanupParser(); - /* xmlFreeDoc(doctree); -- will die at end of tuple anyway */ - - xmlFree(xpresstr); - - elog_error(ERROR,"XPath error",0); - - - return xpres; -} - -/* xpath_table is a table function. It needs some tidying (as do the - * other functions here! - */ - -PG_FUNCTION_INFO_V1(xpath_table); - -Datum xpath_table(PG_FUNCTION_ARGS) -{ -/* SPI (input tuple) support */ - 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; - -/* 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 - * this function call (per_query_ctx is used) */ - - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - -/* Create the tuplestore - SortMem is the max in-memory size before it is - * shipped to a disk heap file. Just like ... SortMem! - */ - - tupstore = tuplestore_begin_heap(true, false, SortMem); - - MemoryContextSwitchTo(oldcontext); - - /* 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. - */ - - 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 - */ - - /* 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 *)); - - xpaths = (xmlChar **) palloc(ret_tupdesc->natts * sizeof(xmlChar *)); - - /* Split XPaths. xpathset is a writable CString. */ - - /* Note that we stop splitting once we've done all needed for tupdesc */ - - 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(); - - /* 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_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; - -/* Switch out of SPI context */ - 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. - */ - - 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(); -/* 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; - -} |