diff options
Diffstat (limited to 'contrib/xml/pgxml.c')
-rw-r--r-- | contrib/xml/pgxml.c | 352 |
1 files changed, 0 insertions, 352 deletions
diff --git a/contrib/xml/pgxml.c b/contrib/xml/pgxml.c deleted file mode 100644 index 4d8c3b96bcf..00000000000 --- a/contrib/xml/pgxml.c +++ /dev/null @@ -1,352 +0,0 @@ -/******************************************************** - * Interface code to parse an XML document using expat - ********************************************************/ - -#include "postgres.h" -#include "fmgr.h" - -#include "expat.h" -#include "pgxml.h" - -/* Memory management - we make expat use standard pg MM */ - -XML_Memory_Handling_Suite mhs; - -/* passthrough functions (palloc is a macro) */ - -static void * -pgxml_palloc(size_t size) -{ - return palloc(size); -} - -static void * -pgxml_repalloc(void *ptr, size_t size) -{ - return repalloc(ptr, size); -} - -static void -pgxml_pfree(void *ptr) -{ - return pfree(ptr); -} - -static void -pgxml_mhs_init() -{ - mhs.malloc_fcn = pgxml_palloc; - mhs.realloc_fcn = pgxml_repalloc; - mhs.free_fcn = pgxml_pfree; -} - -static void -pgxml_handler_init() -{ - /* - * This code should set up the relevant handlers from user-supplied - * settings. Quite how these settings are made is another matter :) - */ -} - -/* Returns true if document is well-formed */ - -PG_FUNCTION_INFO_V1(pgxml_parse); - -Datum -pgxml_parse(PG_FUNCTION_ARGS) -{ - /* called as pgxml_parse(document) */ - XML_Parser p; - text *t = PG_GETARG_TEXT_P(0); /* document buffer */ - int32 docsize = VARSIZE(t) - VARHDRSZ; - - pgxml_mhs_init(); - - pgxml_handler_init(); - - p = XML_ParserCreate_MM(NULL, &mhs, NULL); - if (!p) - { - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), - errmsg("could not create expat parser"))); - PG_RETURN_NULL(); /* seems appropriate if we couldn't parse */ - } - - if (!XML_Parse(p, (char *) VARDATA(t), docsize, 1)) - { - /* - * elog(WARNING, "Parse error at line %d:%s", - * XML_GetCurrentLineNumber(p), - * XML_ErrorString(XML_GetErrorCode(p))); - */ - XML_ParserFree(p); - PG_RETURN_BOOL(false); - } - - XML_ParserFree(p); - PG_RETURN_BOOL(true); -} - -/* XPath handling functions */ - -/* XPath support here is for a very skeletal kind of XPath! - It was easy to program though... */ - -/* This first is the core function that builds a result set. The - actual functions called by the user manipulate that result set - in various ways. -*/ - -static XPath_Results * -build_xpath_results(text *doc, text *pathstr) -{ - XPath_Results *xpr; - char *res; - pgxml_udata *udata; - XML_Parser p; - int32 docsize; - - xpr = (XPath_Results *) palloc((sizeof(XPath_Results))); - memset((void *) xpr, 0, sizeof(XPath_Results)); - xpr->rescount = 0; - - docsize = VARSIZE(doc) - VARHDRSZ; - - /* res isn't going to be the real return type, it is just a buffer */ - - res = (char *) palloc(docsize); - memset((void *) res, 0, docsize); - - xpr->resbuf = res; - - udata = (pgxml_udata *) palloc((sizeof(pgxml_udata))); - memset((void *) udata, 0, sizeof(pgxml_udata)); - - udata->currentpath[0] = '\0'; - udata->textgrab = 0; - - udata->path = (char *) palloc(VARSIZE(pathstr)); - memcpy(udata->path, VARDATA(pathstr), VARSIZE(pathstr) - VARHDRSZ); - - udata->path[VARSIZE(pathstr) - VARHDRSZ] = '\0'; - - udata->resptr = res; - udata->reslen = 0; - - udata->xpres = xpr; - - /* Now fire up the parser */ - pgxml_mhs_init(); - - p = XML_ParserCreate_MM(NULL, &mhs, NULL); - if (!p) - { - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), - errmsg("could not create expat parser"))); - pfree(xpr); - pfree(udata->path); - pfree(udata); - pfree(res); - return NULL; - } - XML_SetUserData(p, (void *) udata); - - /* Set the handlers */ - - XML_SetElementHandler(p, pgxml_starthandler, pgxml_endhandler); - XML_SetCharacterDataHandler(p, pgxml_charhandler); - - if (!XML_Parse(p, (char *) VARDATA(doc), docsize, 1)) - { - /* - * elog(WARNING, "Parse error at line %d:%s", - * XML_GetCurrentLineNumber(p), - * XML_ErrorString(XML_GetErrorCode(p))); - */ - XML_ParserFree(p); - pfree(xpr); - pfree(udata->path); - pfree(udata); - - return NULL; - } - - pfree(udata->path); - pfree(udata); - XML_ParserFree(p); - return xpr; -} - - -PG_FUNCTION_INFO_V1(pgxml_xpath); - -Datum -pgxml_xpath(PG_FUNCTION_ARGS) -{ - /* called as pgxml_xpath(document,pathstr, index) for the moment */ - - XPath_Results *xpresults; - text *restext; - - text *t = PG_GETARG_TEXT_P(0); /* document buffer */ - text *t2 = PG_GETARG_TEXT_P(1); - int32 ind = PG_GETARG_INT32(2) - 1; - - xpresults = build_xpath_results(t, t2); - - /* - * This needs to be changed depending on the mechanism for returning - * our set of results. - */ - - if (xpresults == NULL) /* parse error (not WF or parser failure) */ - PG_RETURN_NULL(); - - if (ind >= (xpresults->rescount)) - PG_RETURN_NULL(); - - restext = (text *) palloc(xpresults->reslens[ind] + VARHDRSZ); - memcpy(VARDATA(restext), xpresults->results[ind], xpresults->reslens[ind]); - - VARATT_SIZEP(restext) = xpresults->reslens[ind] + VARHDRSZ; - - pfree(xpresults->resbuf); - pfree(xpresults); - - PG_RETURN_TEXT_P(restext); -} - - -static void -pgxml_pathcompare(void *userData) -{ - char *matchpos; - - matchpos = strstr(UD->currentpath, UD->path); - - if (matchpos == NULL) - { /* Should we have more logic here ? */ - if (UD->textgrab) - { - UD->textgrab = 0; - pgxml_finalisegrabbedtext(userData); - } - return; - } - - /* - * OK, we have a match of some sort. Now we need to check that our - * match is anchored to the *end* of the string AND that it is - * immediately preceded by a '/' - */ - - /* - * This test wouldn't work if strlen (UD->path) overran the length of - * the currentpath, but that's not possible because we got a match! - */ - - if ((matchpos + strlen(UD->path))[0] == '\0') - { - if ((UD->path)[0] == '/') - { - if (matchpos == UD->currentpath) - UD->textgrab = 1; - } - else - { - if ((matchpos - 1)[0] == '/') - UD->textgrab = 1; - } - } -} - -static void -pgxml_starthandler(void *userData, const XML_Char * name, - const XML_Char ** atts) -{ - - char sepstr[] = "/"; - - if ((strlen(name) + strlen(UD->currentpath)) > MAXPATHLENGTH - 2) - elog(WARNING, "path too long"); - else - { - strncat(UD->currentpath, sepstr, 1); - strcat(UD->currentpath, name); - } - if (UD->textgrab) - { - /* - * Depending on user preference, should we "reconstitute" the - * element into the result text? - */ - } - else - pgxml_pathcompare(userData); -} - -static void -pgxml_endhandler(void *userData, const XML_Char * name) -{ - /* - * Start by removing the current element off the end of the - * currentpath - */ - - char *sepptr; - - sepptr = strrchr(UD->currentpath, '/'); - if (sepptr == NULL) - { - /* internal error */ - elog(ERROR, "did not find '/'"); - sepptr = UD->currentpath; - } - if (strcmp(name, sepptr + 1) != 0) - { - elog(WARNING, "wanted [%s], got [%s]", sepptr, name); - /* unmatched entry, so do nothing */ - } - else - { - sepptr[0] = '\0'; /* Chop that element off the end */ - } - - if (UD->textgrab) - pgxml_pathcompare(userData); - -} - -static void -pgxml_charhandler(void *userData, const XML_Char * s, int len) -{ - if (UD->textgrab) - { - if (len > 0) - { - memcpy(UD->resptr, s, len); - UD->resptr += len; - UD->reslen += len; - } - } -} - -/* Should I be using PG list types here? */ - -static void -pgxml_finalisegrabbedtext(void *userData) -{ - /* In res/reslen, we have a single result. */ - UD->xpres->results[UD->xpres->rescount] = UD->resptr - UD->reslen; - UD->xpres->reslens[UD->xpres->rescount] = UD->reslen; - UD->reslen = 0; - UD->xpres->rescount++; - - /* - * This effectively concatenates all the results together but we do - * know where one ends and the next begins - */ -} |