00001
00002
00003
00004
00005
00006
00007 #include "postgres.h"
00008
00009 #include "access/htup_details.h"
00010 #include "executor/spi.h"
00011 #include "fmgr.h"
00012 #include "funcapi.h"
00013 #include "lib/stringinfo.h"
00014 #include "miscadmin.h"
00015 #include "utils/builtins.h"
00016 #include "utils/xml.h"
00017
00018
00019
00020 #include <libxml/xpath.h>
00021 #include <libxml/tree.h>
00022 #include <libxml/xmlmemory.h>
00023 #include <libxml/xmlerror.h>
00024 #include <libxml/parserInternals.h>
00025
00026
00027 PG_MODULE_MAGIC;
00028
00029
00030
00031 Datum xml_is_well_formed(PG_FUNCTION_ARGS);
00032 Datum xml_encode_special_chars(PG_FUNCTION_ARGS);
00033 Datum xpath_nodeset(PG_FUNCTION_ARGS);
00034 Datum xpath_string(PG_FUNCTION_ARGS);
00035 Datum xpath_number(PG_FUNCTION_ARGS);
00036 Datum xpath_bool(PG_FUNCTION_ARGS);
00037 Datum xpath_list(PG_FUNCTION_ARGS);
00038 Datum xpath_table(PG_FUNCTION_ARGS);
00039
00040
00041
00042 PgXmlErrorContext *pgxml_parser_init(PgXmlStrictness strictness);
00043
00044
00045
00046 typedef struct
00047 {
00048 xmlDocPtr doctree;
00049 xmlXPathContextPtr ctxt;
00050 xmlXPathObjectPtr res;
00051 } xpath_workspace;
00052
00053
00054
00055 static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
00056 xmlChar *toptagname, xmlChar *septagname,
00057 xmlChar *plainsep);
00058
00059 static text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
00060 xmlChar *septag, xmlChar *plainsep);
00061
00062 static xmlChar *pgxml_texttoxmlchar(text *textstring);
00063
00064 static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath,
00065 xpath_workspace *workspace);
00066
00067 static void cleanup_workspace(xpath_workspace *workspace);
00068
00069
00070
00071
00072
00073
00074
00075
00076 PgXmlErrorContext *
00077 pgxml_parser_init(PgXmlStrictness strictness)
00078 {
00079 PgXmlErrorContext *xmlerrcxt;
00080
00081
00082 xmlerrcxt = pg_xml_init(strictness);
00083
00084
00085
00086
00087 xmlInitParser();
00088
00089 xmlSubstituteEntitiesDefault(1);
00090 xmlLoadExtDtdDefaultValue = 1;
00091
00092 return xmlerrcxt;
00093 }
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 PG_FUNCTION_INFO_V1(xml_is_well_formed);
00106
00107 Datum
00108 xml_is_well_formed(PG_FUNCTION_ARGS)
00109 {
00110 text *t = PG_GETARG_TEXT_P(0);
00111 bool result = false;
00112 int32 docsize = VARSIZE(t) - VARHDRSZ;
00113 xmlDocPtr doctree;
00114 PgXmlErrorContext *xmlerrcxt;
00115
00116 xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY);
00117
00118 PG_TRY();
00119 {
00120 doctree = xmlParseMemory((char *) VARDATA(t), docsize);
00121
00122 result = (doctree != NULL);
00123
00124 if (doctree != NULL)
00125 xmlFreeDoc(doctree);
00126 }
00127 PG_CATCH();
00128 {
00129 pg_xml_done(xmlerrcxt, true);
00130
00131 PG_RE_THROW();
00132 }
00133 PG_END_TRY();
00134
00135 pg_xml_done(xmlerrcxt, false);
00136
00137 PG_RETURN_BOOL(result);
00138 }
00139
00140
00141
00142
00143 PG_FUNCTION_INFO_V1(xml_encode_special_chars);
00144
00145 Datum
00146 xml_encode_special_chars(PG_FUNCTION_ARGS)
00147 {
00148 text *tin = PG_GETARG_TEXT_P(0);
00149 text *tout;
00150 xmlChar *ts,
00151 *tt;
00152
00153 ts = pgxml_texttoxmlchar(tin);
00154
00155 tt = xmlEncodeSpecialChars(NULL, ts);
00156
00157 pfree(ts);
00158
00159 tout = cstring_to_text((char *) tt);
00160
00161 xmlFree(tt);
00162
00163 PG_RETURN_TEXT_P(tout);
00164 }
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 static xmlChar *
00178 pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
00179 xmlChar *toptagname,
00180 xmlChar *septagname,
00181 xmlChar *plainsep)
00182 {
00183 xmlBufferPtr buf;
00184 xmlChar *result;
00185 int i;
00186
00187 buf = xmlBufferCreate();
00188
00189 if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
00190 {
00191 xmlBufferWriteChar(buf, "<");
00192 xmlBufferWriteCHAR(buf, toptagname);
00193 xmlBufferWriteChar(buf, ">");
00194 }
00195 if (nodeset != NULL)
00196 {
00197 for (i = 0; i < nodeset->nodeNr; i++)
00198 {
00199 if (plainsep != NULL)
00200 {
00201 xmlBufferWriteCHAR(buf,
00202 xmlXPathCastNodeToString(nodeset->nodeTab[i]));
00203
00204
00205 if (i < (nodeset->nodeNr) - 1)
00206 xmlBufferWriteChar(buf, (char *) plainsep);
00207 }
00208 else
00209 {
00210 if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
00211 {
00212 xmlBufferWriteChar(buf, "<");
00213 xmlBufferWriteCHAR(buf, septagname);
00214 xmlBufferWriteChar(buf, ">");
00215 }
00216 xmlNodeDump(buf,
00217 nodeset->nodeTab[i]->doc,
00218 nodeset->nodeTab[i],
00219 1, 0);
00220
00221 if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
00222 {
00223 xmlBufferWriteChar(buf, "</");
00224 xmlBufferWriteCHAR(buf, septagname);
00225 xmlBufferWriteChar(buf, ">");
00226 }
00227 }
00228 }
00229 }
00230
00231 if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
00232 {
00233 xmlBufferWriteChar(buf, "</");
00234 xmlBufferWriteCHAR(buf, toptagname);
00235 xmlBufferWriteChar(buf, ">");
00236 }
00237 result = xmlStrdup(buf->content);
00238 xmlBufferFree(buf);
00239 return result;
00240 }
00241
00242
00243
00244
00245
00246 static xmlChar *
00247 pgxml_texttoxmlchar(text *textstring)
00248 {
00249 return (xmlChar *) text_to_cstring(textstring);
00250 }
00251
00252
00253
00254
00255
00256
00257
00258 PG_FUNCTION_INFO_V1(xpath_nodeset);
00259
00260 Datum
00261 xpath_nodeset(PG_FUNCTION_ARGS)
00262 {
00263 text *document = PG_GETARG_TEXT_P(0);
00264 text *xpathsupp = PG_GETARG_TEXT_P(1);
00265 xmlChar *toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
00266 xmlChar *septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3));
00267 xmlChar *xpath;
00268 text *xpres;
00269 xmlXPathObjectPtr res;
00270 xpath_workspace workspace;
00271
00272 xpath = pgxml_texttoxmlchar(xpathsupp);
00273
00274 res = pgxml_xpath(document, xpath, &workspace);
00275
00276 xpres = pgxml_result_to_text(res, toptag, septag, NULL);
00277
00278 cleanup_workspace(&workspace);
00279
00280 pfree(xpath);
00281
00282 if (xpres == NULL)
00283 PG_RETURN_NULL();
00284 PG_RETURN_TEXT_P(xpres);
00285 }
00286
00287
00288
00289
00290
00291 PG_FUNCTION_INFO_V1(xpath_list);
00292
00293 Datum
00294 xpath_list(PG_FUNCTION_ARGS)
00295 {
00296 text *document = PG_GETARG_TEXT_P(0);
00297 text *xpathsupp = PG_GETARG_TEXT_P(1);
00298 xmlChar *plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
00299 xmlChar *xpath;
00300 text *xpres;
00301 xmlXPathObjectPtr res;
00302 xpath_workspace workspace;
00303
00304 xpath = pgxml_texttoxmlchar(xpathsupp);
00305
00306 res = pgxml_xpath(document, xpath, &workspace);
00307
00308 xpres = pgxml_result_to_text(res, NULL, NULL, plainsep);
00309
00310 cleanup_workspace(&workspace);
00311
00312 pfree(xpath);
00313
00314 if (xpres == NULL)
00315 PG_RETURN_NULL();
00316 PG_RETURN_TEXT_P(xpres);
00317 }
00318
00319
00320 PG_FUNCTION_INFO_V1(xpath_string);
00321
00322 Datum
00323 xpath_string(PG_FUNCTION_ARGS)
00324 {
00325 text *document = PG_GETARG_TEXT_P(0);
00326 text *xpathsupp = PG_GETARG_TEXT_P(1);
00327 xmlChar *xpath;
00328 int32 pathsize;
00329 text *xpres;
00330 xmlXPathObjectPtr res;
00331 xpath_workspace workspace;
00332
00333 pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
00334
00335
00336
00337
00338
00339
00340
00341 xpath = (xmlChar *) palloc(pathsize + 9);
00342 strncpy((char *) xpath, "string(", 7);
00343 memcpy((char *) (xpath + 7), VARDATA(xpathsupp), pathsize);
00344 xpath[pathsize + 7] = ')';
00345 xpath[pathsize + 8] = '\0';
00346
00347 res = pgxml_xpath(document, xpath, &workspace);
00348
00349 xpres = pgxml_result_to_text(res, NULL, NULL, NULL);
00350
00351 cleanup_workspace(&workspace);
00352
00353 pfree(xpath);
00354
00355 if (xpres == NULL)
00356 PG_RETURN_NULL();
00357 PG_RETURN_TEXT_P(xpres);
00358 }
00359
00360
00361 PG_FUNCTION_INFO_V1(xpath_number);
00362
00363 Datum
00364 xpath_number(PG_FUNCTION_ARGS)
00365 {
00366 text *document = PG_GETARG_TEXT_P(0);
00367 text *xpathsupp = PG_GETARG_TEXT_P(1);
00368 xmlChar *xpath;
00369 float4 fRes;
00370 xmlXPathObjectPtr res;
00371 xpath_workspace workspace;
00372
00373 xpath = pgxml_texttoxmlchar(xpathsupp);
00374
00375 res = pgxml_xpath(document, xpath, &workspace);
00376
00377 pfree(xpath);
00378
00379 if (res == NULL)
00380 PG_RETURN_NULL();
00381
00382 fRes = xmlXPathCastToNumber(res);
00383
00384 cleanup_workspace(&workspace);
00385
00386 if (xmlXPathIsNaN(fRes))
00387 PG_RETURN_NULL();
00388
00389 PG_RETURN_FLOAT4(fRes);
00390 }
00391
00392
00393 PG_FUNCTION_INFO_V1(xpath_bool);
00394
00395 Datum
00396 xpath_bool(PG_FUNCTION_ARGS)
00397 {
00398 text *document = PG_GETARG_TEXT_P(0);
00399 text *xpathsupp = PG_GETARG_TEXT_P(1);
00400 xmlChar *xpath;
00401 int bRes;
00402 xmlXPathObjectPtr res;
00403 xpath_workspace workspace;
00404
00405 xpath = pgxml_texttoxmlchar(xpathsupp);
00406
00407 res = pgxml_xpath(document, xpath, &workspace);
00408
00409 pfree(xpath);
00410
00411 if (res == NULL)
00412 PG_RETURN_BOOL(false);
00413
00414 bRes = xmlXPathCastToBoolean(res);
00415
00416 cleanup_workspace(&workspace);
00417
00418 PG_RETURN_BOOL(bRes);
00419 }
00420
00421
00422
00423
00424
00425 static xmlXPathObjectPtr
00426 pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
00427 {
00428 int32 docsize = VARSIZE(document) - VARHDRSZ;
00429 PgXmlErrorContext *xmlerrcxt;
00430 xmlXPathCompExprPtr comppath;
00431
00432 workspace->doctree = NULL;
00433 workspace->ctxt = NULL;
00434 workspace->res = NULL;
00435
00436 xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY);
00437
00438 PG_TRY();
00439 {
00440 workspace->doctree = xmlParseMemory((char *) VARDATA(document),
00441 docsize);
00442 if (workspace->doctree != NULL)
00443 {
00444 workspace->ctxt = xmlXPathNewContext(workspace->doctree);
00445 workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
00446
00447
00448 comppath = xmlXPathCompile(xpath);
00449 if (comppath == NULL)
00450 xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
00451 "XPath Syntax Error");
00452
00453
00454 workspace->res = xmlXPathCompiledEval(comppath, workspace->ctxt);
00455
00456 xmlXPathFreeCompExpr(comppath);
00457 }
00458 }
00459 PG_CATCH();
00460 {
00461 cleanup_workspace(workspace);
00462
00463 pg_xml_done(xmlerrcxt, true);
00464
00465 PG_RE_THROW();
00466 }
00467 PG_END_TRY();
00468
00469 if (workspace->res == NULL)
00470 cleanup_workspace(workspace);
00471
00472 pg_xml_done(xmlerrcxt, false);
00473
00474 return workspace->res;
00475 }
00476
00477
00478 static void
00479 cleanup_workspace(xpath_workspace *workspace)
00480 {
00481 if (workspace->res)
00482 xmlXPathFreeObject(workspace->res);
00483 workspace->res = NULL;
00484 if (workspace->ctxt)
00485 xmlXPathFreeContext(workspace->ctxt);
00486 workspace->ctxt = NULL;
00487 if (workspace->doctree)
00488 xmlFreeDoc(workspace->doctree);
00489 workspace->doctree = NULL;
00490 }
00491
00492 static text *
00493 pgxml_result_to_text(xmlXPathObjectPtr res,
00494 xmlChar *toptag,
00495 xmlChar *septag,
00496 xmlChar *plainsep)
00497 {
00498 xmlChar *xpresstr;
00499 text *xpres;
00500
00501 if (res == NULL)
00502 return NULL;
00503
00504 switch (res->type)
00505 {
00506 case XPATH_NODESET:
00507 xpresstr = pgxmlNodeSetToText(res->nodesetval,
00508 toptag,
00509 septag, plainsep);
00510 break;
00511
00512 case XPATH_STRING:
00513 xpresstr = xmlStrdup(res->stringval);
00514 break;
00515
00516 default:
00517 elog(NOTICE, "unsupported XQuery result: %d", res->type);
00518 xpresstr = xmlStrdup((const xmlChar *) "<unsupported/>");
00519 }
00520
00521
00522 xpres = cstring_to_text((char *) xpresstr);
00523
00524
00525 xmlFree(xpresstr);
00526
00527 return xpres;
00528 }
00529
00530
00531
00532
00533
00534 PG_FUNCTION_INFO_V1(xpath_table);
00535
00536 Datum
00537 xpath_table(PG_FUNCTION_ARGS)
00538 {
00539
00540 char *pkeyfield = text_to_cstring(PG_GETARG_TEXT_PP(0));
00541 char *xmlfield = text_to_cstring(PG_GETARG_TEXT_PP(1));
00542 char *relname = text_to_cstring(PG_GETARG_TEXT_PP(2));
00543 char *xpathset = text_to_cstring(PG_GETARG_TEXT_PP(3));
00544 char *condition = text_to_cstring(PG_GETARG_TEXT_PP(4));
00545
00546
00547 SPITupleTable *tuptable;
00548 HeapTuple spi_tuple;
00549 TupleDesc spi_tupdesc;
00550
00551
00552 Tuplestorestate *tupstore = NULL;
00553 TupleDesc ret_tupdesc;
00554 HeapTuple ret_tuple;
00555
00556 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
00557 AttInMetadata *attinmeta;
00558 MemoryContext per_query_ctx;
00559 MemoryContext oldcontext;
00560
00561 char **values;
00562 xmlChar **xpaths;
00563 char *pos;
00564 const char *pathsep = "|";
00565
00566 int numpaths;
00567 int ret;
00568 int proc;
00569 int i;
00570 int j;
00571 int rownr;
00572
00573 bool had_values;
00574 StringInfoData query_buf;
00575 PgXmlErrorContext *xmlerrcxt;
00576 volatile xmlDocPtr doctree = NULL;
00577
00578
00579 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
00580 ereport(ERROR,
00581 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00582 errmsg("set-valued function called in context that cannot accept a set")));
00583 if (rsinfo->expectedDesc == NULL)
00584 ereport(ERROR,
00585 (errcode(ERRCODE_SYNTAX_ERROR),
00586 errmsg("xpath_table must be called as a table function")));
00587
00588
00589
00590
00591
00592 if (!(rsinfo->allowedModes & SFRM_Materialize))
00593 ereport(ERROR,
00594 (errcode(ERRCODE_SYNTAX_ERROR),
00595 errmsg("xpath_table requires Materialize mode, but it is not "
00596 "allowed in this context")));
00597
00598
00599
00600
00601
00602 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
00603 oldcontext = MemoryContextSwitchTo(per_query_ctx);
00604
00605
00606
00607
00608
00609 tupstore =
00610 tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
00611 false, work_mem);
00612
00613 MemoryContextSwitchTo(oldcontext);
00614
00615
00616 ret_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
00617
00618
00619 if (ret_tupdesc->natts < 1)
00620 ereport(ERROR,
00621 (errcode(ERRCODE_SYNTAX_ERROR),
00622 errmsg("xpath_table must have at least one output column")));
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632 attinmeta = TupleDescGetAttInMetadata(ret_tupdesc);
00633
00634
00635 rsinfo->returnMode = SFRM_Materialize;
00636 rsinfo->setDesc = ret_tupdesc;
00637
00638 values = (char **) palloc(ret_tupdesc->natts * sizeof(char *));
00639 xpaths = (xmlChar **) palloc(ret_tupdesc->natts * sizeof(xmlChar *));
00640
00641
00642
00643
00644
00645
00646 numpaths = 0;
00647 pos = xpathset;
00648 while (numpaths < (ret_tupdesc->natts - 1))
00649 {
00650 xpaths[numpaths++] = (xmlChar *) pos;
00651 pos = strstr(pos, pathsep);
00652 if (pos != NULL)
00653 {
00654 *pos = '\0';
00655 pos++;
00656 }
00657 else
00658 break;
00659 }
00660
00661
00662 initStringInfo(&query_buf);
00663
00664
00665 appendStringInfo(&query_buf, "SELECT %s, %s FROM %s WHERE %s",
00666 pkeyfield,
00667 xmlfield,
00668 relname,
00669 condition);
00670
00671 if ((ret = SPI_connect()) < 0)
00672 elog(ERROR, "xpath_table: SPI_connect returned %d", ret);
00673
00674 if ((ret = SPI_exec(query_buf.data, 0)) != SPI_OK_SELECT)
00675 elog(ERROR, "xpath_table: SPI execution failed for query %s",
00676 query_buf.data);
00677
00678 proc = SPI_processed;
00679
00680 tuptable = SPI_tuptable;
00681 spi_tupdesc = tuptable->tupdesc;
00682
00683
00684 MemoryContextSwitchTo(oldcontext);
00685
00686
00687
00688
00689
00690
00691 if (spi_tupdesc->natts != 2)
00692 {
00693 ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00694 errmsg("expression returning multiple columns is not valid in parameter list"),
00695 errdetail("Expected two columns in SPI result, got %d.", spi_tupdesc->natts)));
00696 }
00697
00698
00699
00700
00701
00702 xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY);
00703
00704 PG_TRY();
00705 {
00706
00707 for (i = 0; i < proc; i++)
00708 {
00709 char *pkey;
00710 char *xmldoc;
00711 xmlXPathContextPtr ctxt;
00712 xmlXPathObjectPtr res;
00713 xmlChar *resstr;
00714 xmlXPathCompExprPtr comppath;
00715
00716
00717 spi_tuple = tuptable->vals[i];
00718 pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
00719 xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2);
00720
00721
00722
00723
00724
00725
00726 for (j = 0; j < ret_tupdesc->natts; j++)
00727 values[j] = NULL;
00728
00729
00730 values[0] = pkey;
00731
00732
00733 if (xmldoc)
00734 doctree = xmlParseMemory(xmldoc, strlen(xmldoc));
00735 else
00736 doctree = NULL;
00737
00738 if (doctree == NULL)
00739 {
00740
00741 ret_tuple = BuildTupleFromCStrings(attinmeta, values);
00742 tuplestore_puttuple(tupstore, ret_tuple);
00743 heap_freetuple(ret_tuple);
00744 }
00745 else
00746 {
00747
00748 rownr = 0;
00749
00750 do
00751 {
00752
00753 had_values = false;
00754 for (j = 0; j < numpaths; j++)
00755 {
00756 ctxt = xmlXPathNewContext(doctree);
00757 ctxt->node = xmlDocGetRootElement(doctree);
00758
00759
00760 comppath = xmlXPathCompile(xpaths[j]);
00761 if (comppath == NULL)
00762 xml_ereport(xmlerrcxt, ERROR,
00763 ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
00764 "XPath Syntax Error");
00765
00766
00767 res = xmlXPathCompiledEval(comppath, ctxt);
00768 xmlXPathFreeCompExpr(comppath);
00769
00770 if (res != NULL)
00771 {
00772 switch (res->type)
00773 {
00774 case XPATH_NODESET:
00775
00776 if (res->nodesetval != NULL &&
00777 rownr < res->nodesetval->nodeNr)
00778 {
00779 resstr = xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]);
00780 had_values = true;
00781 }
00782 else
00783 resstr = NULL;
00784
00785 break;
00786
00787 case XPATH_STRING:
00788 resstr = xmlStrdup(res->stringval);
00789 break;
00790
00791 default:
00792 elog(NOTICE, "unsupported XQuery result: %d", res->type);
00793 resstr = xmlStrdup((const xmlChar *) "<unsupported/>");
00794 }
00795
00796
00797
00798
00799
00800 values[j + 1] = (char *) resstr;
00801 }
00802 xmlXPathFreeContext(ctxt);
00803 }
00804
00805
00806 if (had_values)
00807 {
00808 ret_tuple = BuildTupleFromCStrings(attinmeta, values);
00809 tuplestore_puttuple(tupstore, ret_tuple);
00810 heap_freetuple(ret_tuple);
00811 }
00812
00813 rownr++;
00814 } while (had_values);
00815 }
00816
00817 if (doctree != NULL)
00818 xmlFreeDoc(doctree);
00819 doctree = NULL;
00820
00821 if (pkey)
00822 pfree(pkey);
00823 if (xmldoc)
00824 pfree(xmldoc);
00825 }
00826 }
00827 PG_CATCH();
00828 {
00829 if (doctree != NULL)
00830 xmlFreeDoc(doctree);
00831
00832 pg_xml_done(xmlerrcxt, true);
00833
00834 PG_RE_THROW();
00835 }
00836 PG_END_TRY();
00837
00838 if (doctree != NULL)
00839 xmlFreeDoc(doctree);
00840
00841 pg_xml_done(xmlerrcxt, false);
00842
00843 tuplestore_donestoring(tupstore);
00844
00845 SPI_finish();
00846
00847 rsinfo->setResult = tupstore;
00848
00849
00850
00851
00852
00853
00854
00855
00856 return (Datum) 0;
00857 }