PostgreSQL Source Code git master
xpath.c
Go to the documentation of this file.
1/*
2 * contrib/xml2/xpath.c
3 *
4 * Parser interface for DOM-based parser (libxml) rather than
5 * stream-based SAX-type parser
6 */
7#include "postgres.h"
8
10#include "executor/spi.h"
11#include "fmgr.h"
12#include "funcapi.h"
13#include "lib/stringinfo.h"
14#include "utils/builtins.h"
15#include "utils/xml.h"
16
17/* libxml includes */
18
19#include <libxml/xpath.h>
20#include <libxml/tree.h>
21#include <libxml/xmlmemory.h>
22#include <libxml/xmlerror.h>
23#include <libxml/parserInternals.h>
24
26 .name = "xml2",
27 .version = PG_VERSION
28);
29
30/* exported for use by xslt_proc.c */
31
33
34/* workspace for pgxml_xpath() */
35
36typedef struct
37{
38 xmlDocPtr doctree;
39 xmlXPathContextPtr ctxt;
40 xmlXPathObjectPtr res;
42
43/* local declarations */
44
45static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
46 xmlChar *toptagname, xmlChar *septagname,
47 xmlChar *plainsep);
48
49static text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
50 xmlChar *septag, xmlChar *plainsep);
51
52static xmlChar *pgxml_texttoxmlchar(text *textstring);
53
54static xpath_workspace *pgxml_xpath(text *document, xmlChar *xpath,
55 PgXmlErrorContext *xmlerrcxt);
56
57static void cleanup_workspace(xpath_workspace *workspace);
58
59
60/*
61 * Initialize for xml parsing.
62 *
63 * As with the underlying pg_xml_init function, calls to this MUST be followed
64 * by a PG_TRY block that guarantees that pg_xml_done is called.
65 */
68{
69 PgXmlErrorContext *xmlerrcxt;
70
71 /* Set up error handling (we share the core's error handler) */
72 xmlerrcxt = pg_xml_init(strictness);
73
74 /* Note: we're assuming an elog cannot be thrown by the following calls */
75
76 /* Initialize libxml */
77 xmlInitParser();
78
79 return xmlerrcxt;
80}
81
82
83/* Encodes special characters (<, >, &, " and \r) as XML entities */
84
86
89{
90 text *tin = PG_GETARG_TEXT_PP(0);
91 text *volatile tout = NULL;
92 xmlChar *volatile tt = NULL;
93 PgXmlErrorContext *xmlerrcxt;
94
96
97 PG_TRY();
98 {
99 xmlChar *ts;
100
101 ts = pgxml_texttoxmlchar(tin);
102
103 tt = xmlEncodeSpecialChars(NULL, ts);
104 if (tt == NULL || pg_xml_error_occurred(xmlerrcxt))
105 xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
106 "could not allocate xmlChar");
107 pfree(ts);
108
109 tout = cstring_to_text((char *) tt);
110 }
111 PG_CATCH();
112 {
113 if (tt != NULL)
114 xmlFree(tt);
115
116 pg_xml_done(xmlerrcxt, true);
117
118 PG_RE_THROW();
119 }
120 PG_END_TRY();
121
122 if (tt != NULL)
123 xmlFree(tt);
124
125 pg_xml_done(xmlerrcxt, false);
126
127 PG_RETURN_TEXT_P(tout);
128}
129
130/*
131 * Function translates a nodeset into a text representation
132 *
133 * iterates over each node in the set and calls xmlNodeDump to write it to
134 * an xmlBuffer -from which an xmlChar * string is returned.
135 *
136 * each representation is surrounded by <tagname> ... </tagname>
137 *
138 * plainsep is an ordinary (not tag) separator - if used, then nodes are
139 * cast to string as output method
140 */
141static xmlChar *
142pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
143 xmlChar *toptagname,
144 xmlChar *septagname,
145 xmlChar *plainsep)
146{
147 volatile xmlBufferPtr buf = NULL;
148 xmlChar *volatile result = NULL;
149 PgXmlErrorContext *xmlerrcxt;
150
151 /* spin up some error handling */
153
154 PG_TRY();
155 {
156 buf = xmlBufferCreate();
157
158 if (buf == NULL || pg_xml_error_occurred(xmlerrcxt))
159 xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
160 "could not allocate xmlBuffer");
161
162 if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
163 {
164 xmlBufferWriteChar(buf, "<");
165 xmlBufferWriteCHAR(buf, toptagname);
166 xmlBufferWriteChar(buf, ">");
167 }
168 if (nodeset != NULL)
169 {
170 for (int i = 0; i < nodeset->nodeNr; i++)
171 {
172 if (plainsep != NULL)
173 {
174 xmlBufferWriteCHAR(buf,
175 xmlXPathCastNodeToString(nodeset->nodeTab[i]));
176
177 /* If this isn't the last entry, write the plain sep. */
178 if (i < (nodeset->nodeNr) - 1)
179 xmlBufferWriteChar(buf, (char *) plainsep);
180 }
181 else
182 {
183 if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
184 {
185 xmlBufferWriteChar(buf, "<");
186 xmlBufferWriteCHAR(buf, septagname);
187 xmlBufferWriteChar(buf, ">");
188 }
189 xmlNodeDump(buf,
190 nodeset->nodeTab[i]->doc,
191 nodeset->nodeTab[i],
192 1, 0);
193
194 if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
195 {
196 xmlBufferWriteChar(buf, "</");
197 xmlBufferWriteCHAR(buf, septagname);
198 xmlBufferWriteChar(buf, ">");
199 }
200 }
201 }
202 }
203
204 if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
205 {
206 xmlBufferWriteChar(buf, "</");
207 xmlBufferWriteCHAR(buf, toptagname);
208 xmlBufferWriteChar(buf, ">");
209 }
210
211 result = xmlStrdup(xmlBufferContent(buf));
212 if (result == NULL || pg_xml_error_occurred(xmlerrcxt))
213 xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
214 "could not allocate result");
215 }
216 PG_CATCH();
217 {
218 if (buf)
219 xmlBufferFree(buf);
220
221 pg_xml_done(xmlerrcxt, true);
222
223 PG_RE_THROW();
224 }
225 PG_END_TRY();
226
227 xmlBufferFree(buf);
228 pg_xml_done(xmlerrcxt, false);
229
230 return result;
231}
232
233
234/* Translate a PostgreSQL "varlena" -i.e. a variable length parameter
235 * into the libxml2 representation
236 */
237static xmlChar *
239{
240 return (xmlChar *) text_to_cstring(textstring);
241}
242
243/* Publicly visible XPath functions */
244
245/*
246 * This is a "raw" xpath function. Check that it returns child elements
247 * properly
248 */
250
251Datum
253{
254 text *document = PG_GETARG_TEXT_PP(0);
255 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
256 xmlChar *toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_PP(2));
257 xmlChar *septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_PP(3));
258 xmlChar *xpath;
259 text *volatile xpres = NULL;
260 xpath_workspace *volatile workspace = NULL;
261 PgXmlErrorContext *xmlerrcxt;
262
263 xpath = pgxml_texttoxmlchar(xpathsupp);
265
266 PG_TRY();
267 {
268 workspace = pgxml_xpath(document, xpath, xmlerrcxt);
269 xpres = pgxml_result_to_text(workspace->res, toptag, septag, NULL);
270 }
271 PG_CATCH();
272 {
273 if (workspace)
274 cleanup_workspace(workspace);
275
276 pg_xml_done(xmlerrcxt, true);
277 PG_RE_THROW();
278 }
279 PG_END_TRY();
280
281 cleanup_workspace(workspace);
282 pg_xml_done(xmlerrcxt, false);
283
284 pfree(xpath);
285
286 if (xpres == NULL)
288 PG_RETURN_TEXT_P(xpres);
289}
290
291/*
292 * The following function is almost identical, but returns the elements in
293 * a list.
294 */
296
297Datum
299{
300 text *document = PG_GETARG_TEXT_PP(0);
301 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
302 xmlChar *plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_PP(2));
303 xmlChar *xpath;
304 text *volatile xpres = NULL;
305 xpath_workspace *volatile workspace = NULL;
306 PgXmlErrorContext *xmlerrcxt;
307
308 xpath = pgxml_texttoxmlchar(xpathsupp);
310
311 PG_TRY();
312 {
313 workspace = pgxml_xpath(document, xpath, xmlerrcxt);
314 xpres = pgxml_result_to_text(workspace->res, NULL, NULL, plainsep);
315 }
316 PG_CATCH();
317 {
318 if (workspace)
319 cleanup_workspace(workspace);
320
321 pg_xml_done(xmlerrcxt, true);
322 PG_RE_THROW();
323 }
324 PG_END_TRY();
325
326 cleanup_workspace(workspace);
327 pg_xml_done(xmlerrcxt, false);
328
329 pfree(xpath);
330
331 if (xpres == NULL)
333 PG_RETURN_TEXT_P(xpres);
334}
335
336
338
339Datum
341{
342 text *document = PG_GETARG_TEXT_PP(0);
343 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
344 xmlChar *xpath;
345 int32 pathsize;
346 text *volatile xpres = NULL;
347 xpath_workspace *volatile workspace = NULL;
348 PgXmlErrorContext *xmlerrcxt;
349
350 pathsize = VARSIZE_ANY_EXHDR(xpathsupp);
351
352 /*
353 * We encapsulate the supplied path with "string()" = 8 chars + 1 for NUL
354 * at end
355 */
356 /* We could try casting to string using the libxml function? */
357
358 xpath = (xmlChar *) palloc(pathsize + 9);
359 memcpy(xpath, "string(", 7);
360 memcpy(xpath + 7, VARDATA_ANY(xpathsupp), pathsize);
361 xpath[pathsize + 7] = ')';
362 xpath[pathsize + 8] = '\0';
363
365
366 PG_TRY();
367 {
368 workspace = pgxml_xpath(document, xpath, xmlerrcxt);
369 xpres = pgxml_result_to_text(workspace->res, NULL, NULL, NULL);
370 }
371 PG_CATCH();
372 {
373 if (workspace)
374 cleanup_workspace(workspace);
375
376 pg_xml_done(xmlerrcxt, true);
377 PG_RE_THROW();
378 }
379 PG_END_TRY();
380
381 cleanup_workspace(workspace);
382 pg_xml_done(xmlerrcxt, false);
383
384 pfree(xpath);
385
386 if (xpres == NULL)
388 PG_RETURN_TEXT_P(xpres);
389}
390
391
393
394Datum
396{
397 text *document = PG_GETARG_TEXT_PP(0);
398 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
399 xmlChar *xpath;
400 volatile float4 fRes = 0.0;
401 volatile bool isNull = false;
402 xpath_workspace *volatile workspace = NULL;
403 PgXmlErrorContext *xmlerrcxt;
404
405 xpath = pgxml_texttoxmlchar(xpathsupp);
407
408 PG_TRY();
409 {
410 workspace = pgxml_xpath(document, xpath, xmlerrcxt);
411 pfree(xpath);
412
413 if (workspace->res == NULL)
414 isNull = true;
415 else
416 fRes = xmlXPathCastToNumber(workspace->res);
417 }
418 PG_CATCH();
419 {
420 if (workspace)
421 cleanup_workspace(workspace);
422
423 pg_xml_done(xmlerrcxt, true);
424 PG_RE_THROW();
425 }
426 PG_END_TRY();
427
428 cleanup_workspace(workspace);
429 pg_xml_done(xmlerrcxt, false);
430
431 if (isNull || xmlXPathIsNaN(fRes))
433
434 PG_RETURN_FLOAT4(fRes);
435}
436
437
439
440Datum
442{
443 text *document = PG_GETARG_TEXT_PP(0);
444 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
445 xmlChar *xpath;
446 volatile int bRes = 0;
447 xpath_workspace *volatile workspace = NULL;
448 PgXmlErrorContext *xmlerrcxt;
449
450 xpath = pgxml_texttoxmlchar(xpathsupp);
452
453 PG_TRY();
454 {
455 workspace = pgxml_xpath(document, xpath, xmlerrcxt);
456 pfree(xpath);
457
458 if (workspace->res == NULL)
459 bRes = 0;
460 else
461 bRes = xmlXPathCastToBoolean(workspace->res);
462 }
463 PG_CATCH();
464 {
465 if (workspace)
466 cleanup_workspace(workspace);
467
468 pg_xml_done(xmlerrcxt, true);
469 PG_RE_THROW();
470 }
471 PG_END_TRY();
472
473 cleanup_workspace(workspace);
474 pg_xml_done(xmlerrcxt, false);
475
476 PG_RETURN_BOOL(bRes);
477}
478
479
480
481/* Core function to evaluate XPath query */
482
483static xpath_workspace *
484pgxml_xpath(text *document, xmlChar *xpath, PgXmlErrorContext *xmlerrcxt)
485{
486 int32 docsize = VARSIZE_ANY_EXHDR(document);
487 xmlXPathCompExprPtr comppath;
489
490 workspace->doctree = NULL;
491 workspace->ctxt = NULL;
492 workspace->res = NULL;
493
494 workspace->doctree = xmlReadMemory((char *) VARDATA_ANY(document),
495 docsize, NULL, NULL,
496 XML_PARSE_NOENT);
497 if (workspace->doctree != NULL)
498 {
499 workspace->ctxt = xmlXPathNewContext(workspace->doctree);
500 workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
501
502 /* compile the path */
503 comppath = xmlXPathCtxtCompile(workspace->ctxt, xpath);
504 if (comppath == NULL || pg_xml_error_occurred(xmlerrcxt))
505 xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
506 "XPath Syntax Error");
507
508 /* Now evaluate the path expression. */
509 workspace->res = xmlXPathCompiledEval(comppath, workspace->ctxt);
510
511 xmlXPathFreeCompExpr(comppath);
512 }
513
514 return workspace;
515}
516
517/* Clean up after processing the result of pgxml_xpath() */
518static void
520{
521 if (workspace->res)
522 xmlXPathFreeObject(workspace->res);
523 workspace->res = NULL;
524 if (workspace->ctxt)
525 xmlXPathFreeContext(workspace->ctxt);
526 workspace->ctxt = NULL;
527 if (workspace->doctree)
528 xmlFreeDoc(workspace->doctree);
529 workspace->doctree = NULL;
530}
531
532static text *
533pgxml_result_to_text(xmlXPathObjectPtr res,
534 xmlChar *toptag,
535 xmlChar *septag,
536 xmlChar *plainsep)
537{
538 xmlChar *volatile xpresstr = NULL;
539 text *volatile xpres = NULL;
540 PgXmlErrorContext *xmlerrcxt;
541
542 if (res == NULL)
543 return NULL;
544
545 /* spin some error handling */
547
548 PG_TRY();
549 {
550 switch (res->type)
551 {
552 case XPATH_NODESET:
553 xpresstr = pgxmlNodeSetToText(res->nodesetval,
554 toptag,
555 septag, plainsep);
556 break;
557
558 case XPATH_STRING:
559 xpresstr = xmlStrdup(res->stringval);
560 if (xpresstr == NULL || pg_xml_error_occurred(xmlerrcxt))
561 xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
562 "could not allocate result");
563 break;
564
565 default:
566 elog(NOTICE, "unsupported XQuery result: %d", res->type);
567 xpresstr = xmlStrdup((const xmlChar *) "<unsupported/>");
568 if (xpresstr == NULL || pg_xml_error_occurred(xmlerrcxt))
569 xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
570 "could not allocate result");
571 }
572
573 /* Now convert this result back to text */
574 xpres = cstring_to_text((char *) xpresstr);
575 }
576 PG_CATCH();
577 {
578 if (xpresstr != NULL)
579 xmlFree(xpresstr);
580
581 pg_xml_done(xmlerrcxt, true);
582
583 PG_RE_THROW();
584 }
585 PG_END_TRY();
586
587 /* Free various storage */
588 xmlFree(xpresstr);
589
590 pg_xml_done(xmlerrcxt, false);
591
592 return xpres;
593}
594
595/*
596 * xpath_table is a table function. It needs some tidying (as do the
597 * other functions here!
598 */
600
601Datum
603{
604 /* Function parameters */
605 char *pkeyfield = text_to_cstring(PG_GETARG_TEXT_PP(0));
606 char *xmlfield = text_to_cstring(PG_GETARG_TEXT_PP(1));
608 char *xpathset = text_to_cstring(PG_GETARG_TEXT_PP(3));
609 char *condition = text_to_cstring(PG_GETARG_TEXT_PP(4));
610
611 /* SPI (input tuple) support */
612 SPITupleTable *tuptable;
613 HeapTuple spi_tuple;
614 TupleDesc spi_tupdesc;
615
616
617 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
618 AttInMetadata *attinmeta;
619
620 char **values;
621 xmlChar **xpaths;
622 char *pos;
623 const char *pathsep = "|";
624
625 int numpaths;
626 int ret;
627 uint64 proc;
628 int j;
629 int rownr; /* For issuing multiple rows from one original
630 * document */
631 bool had_values; /* To determine end of nodeset results */
632 StringInfoData query_buf;
633 PgXmlErrorContext *xmlerrcxt;
634 volatile xmlDocPtr doctree = NULL;
635
637
638 /* must have at least one output column (for the pkey) */
639 if (rsinfo->setDesc->natts < 1)
641 (errcode(ERRCODE_SYNTAX_ERROR),
642 errmsg("xpath_table must have at least one output column")));
643
644 /*
645 * At the moment we assume that the returned attributes make sense for the
646 * XPath specified (i.e. we trust the caller). It's not fatal if they get
647 * it wrong - the input function for the column type will raise an error
648 * if the path result can't be converted into the correct binary
649 * representation.
650 */
651
652 attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc);
653
654 values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *));
655 xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *));
656
657 /*
658 * Split XPaths. xpathset is a writable CString.
659 *
660 * Note that we stop splitting once we've done all needed for tupdesc
661 */
662 numpaths = 0;
663 pos = xpathset;
664 while (numpaths < (rsinfo->setDesc->natts - 1))
665 {
666 xpaths[numpaths++] = (xmlChar *) pos;
667 pos = strstr(pos, pathsep);
668 if (pos != NULL)
669 {
670 *pos = '\0';
671 pos++;
672 }
673 else
674 break;
675 }
676
677 /* Now build query */
678 initStringInfo(&query_buf);
679
680 /* Build initial sql statement */
681 appendStringInfo(&query_buf, "SELECT %s, %s FROM %s WHERE %s",
682 pkeyfield,
683 xmlfield,
684 relname,
685 condition);
686
687 SPI_connect();
688
689 if ((ret = SPI_exec(query_buf.data, 0)) != SPI_OK_SELECT)
690 elog(ERROR, "xpath_table: SPI execution failed for query %s",
691 query_buf.data);
692
693 proc = SPI_processed;
694 tuptable = SPI_tuptable;
695 spi_tupdesc = tuptable->tupdesc;
696
697 /*
698 * Check that SPI returned correct result. If you put a comma into one of
699 * the function parameters, this will catch it when the SPI query returns
700 * e.g. 3 columns.
701 */
702 if (spi_tupdesc->natts != 2)
703 {
704 ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
705 errmsg("expression returning multiple columns is not valid in parameter list"),
706 errdetail("Expected two columns in SPI result, got %d.", spi_tupdesc->natts)));
707 }
708
709 /*
710 * Setup the parser. This should happen after we are done evaluating the
711 * query, in case it calls functions that set up libxml differently.
712 */
714
715 PG_TRY();
716 {
717 /* For each row i.e. document returned from SPI */
718 uint64 i;
719
720 for (i = 0; i < proc; i++)
721 {
722 char *pkey;
723 char *xmldoc;
724 xmlXPathContextPtr ctxt;
725 xmlXPathObjectPtr res;
726 xmlChar *resstr;
727 xmlXPathCompExprPtr comppath;
728 HeapTuple ret_tuple;
729
730 /* Extract the row data as C Strings */
731 spi_tuple = tuptable->vals[i];
732 pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
733 xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2);
734
735 /*
736 * Clear the values array, so that not-well-formed documents
737 * return NULL in all columns. Note that this also means that
738 * spare columns will be NULL.
739 */
740 for (j = 0; j < rsinfo->setDesc->natts; j++)
741 values[j] = NULL;
742
743 /* Insert primary key */
744 values[0] = pkey;
745
746 /* Parse the document */
747 if (xmldoc)
748 doctree = xmlReadMemory(xmldoc, strlen(xmldoc),
749 NULL, NULL,
750 XML_PARSE_NOENT);
751 else /* treat NULL as not well-formed */
752 doctree = NULL;
753
754 if (doctree == NULL)
755 {
756 /* not well-formed, so output all-NULL tuple */
757 ret_tuple = BuildTupleFromCStrings(attinmeta, values);
758 tuplestore_puttuple(rsinfo->setResult, ret_tuple);
759 heap_freetuple(ret_tuple);
760 }
761 else
762 {
763 /* New loop here - we have to deal with nodeset results */
764 rownr = 0;
765
766 do
767 {
768 /* Now evaluate the set of xpaths. */
769 had_values = false;
770 for (j = 0; j < numpaths; j++)
771 {
772 ctxt = xmlXPathNewContext(doctree);
773 if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt))
774 xml_ereport(xmlerrcxt,
775 ERROR, ERRCODE_OUT_OF_MEMORY,
776 "could not allocate XPath context");
777
778 ctxt->node = xmlDocGetRootElement(doctree);
779
780 /* compile the path */
781 comppath = xmlXPathCtxtCompile(ctxt, xpaths[j]);
782 if (comppath == NULL || pg_xml_error_occurred(xmlerrcxt))
783 xml_ereport(xmlerrcxt, ERROR,
784 ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
785 "XPath Syntax Error");
786
787 /* Now evaluate the path expression. */
788 res = xmlXPathCompiledEval(comppath, ctxt);
789 xmlXPathFreeCompExpr(comppath);
790
791 if (res != NULL)
792 {
793 switch (res->type)
794 {
795 case XPATH_NODESET:
796 /* We see if this nodeset has enough nodes */
797 if (res->nodesetval != NULL &&
798 rownr < res->nodesetval->nodeNr)
799 {
800 resstr = xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]);
801 if (resstr == NULL || pg_xml_error_occurred(xmlerrcxt))
802 xml_ereport(xmlerrcxt,
803 ERROR, ERRCODE_OUT_OF_MEMORY,
804 "could not allocate result");
805 had_values = true;
806 }
807 else
808 resstr = NULL;
809
810 break;
811
812 case XPATH_STRING:
813 resstr = xmlStrdup(res->stringval);
814 if (resstr == NULL || pg_xml_error_occurred(xmlerrcxt))
815 xml_ereport(xmlerrcxt,
816 ERROR, ERRCODE_OUT_OF_MEMORY,
817 "could not allocate result");
818 break;
819
820 default:
821 elog(NOTICE, "unsupported XQuery result: %d", res->type);
822 resstr = xmlStrdup((const xmlChar *) "<unsupported/>");
823 if (resstr == NULL || pg_xml_error_occurred(xmlerrcxt))
824 xml_ereport(xmlerrcxt,
825 ERROR, ERRCODE_OUT_OF_MEMORY,
826 "could not allocate result");
827 }
828
829 /*
830 * Insert this into the appropriate column in the
831 * result tuple.
832 */
833 values[j + 1] = (char *) resstr;
834 }
835 xmlXPathFreeContext(ctxt);
836 }
837
838 /* Now add the tuple to the output, if there is one. */
839 if (had_values)
840 {
841 ret_tuple = BuildTupleFromCStrings(attinmeta, values);
842 tuplestore_puttuple(rsinfo->setResult, ret_tuple);
843 heap_freetuple(ret_tuple);
844 }
845
846 rownr++;
847 } while (had_values);
848 }
849
850 if (doctree != NULL)
851 xmlFreeDoc(doctree);
852 doctree = NULL;
853
854 if (pkey)
855 pfree(pkey);
856 if (xmldoc)
857 pfree(xmldoc);
858 }
859 }
860 PG_CATCH();
861 {
862 if (doctree != NULL)
863 xmlFreeDoc(doctree);
864
865 pg_xml_done(xmlerrcxt, true);
866
867 PG_RE_THROW();
868 }
869 PG_END_TRY();
870
871 if (doctree != NULL)
872 xmlFreeDoc(doctree);
873
874 pg_xml_done(xmlerrcxt, false);
875
876 SPI_finish();
877
878 /*
879 * SFRM_Materialize mode expects us to return a NULL Datum. The actual
880 * tuples are in our tuplestore and passed back through rsinfo->setResult.
881 * rsinfo->setDesc is set to the tuple description that we actually used
882 * to build our tuples with, so the caller can verify we did what it was
883 * expecting.
884 */
885 return (Datum) 0;
886}
static Datum values[MAXATTR]
Definition: bootstrap.c:153
int32_t int32
Definition: c.h:548
uint64_t uint64
Definition: c.h:553
float float4
Definition: c.h:648
int errdetail(const char *fmt,...)
Definition: elog.c:1216
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define PG_RE_THROW()
Definition: elog.h:405
#define PG_TRY(...)
Definition: elog.h:372
#define PG_END_TRY(...)
Definition: elog.h:397
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:382
#define elog(elevel,...)
Definition: elog.h:226
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:150
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2324
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2275
#define palloc0_object(type)
Definition: fe_memutils.h:75
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_RETURN_FLOAT4(x)
Definition: fmgr.h:366
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
#define MAT_SRF_USE_EXPECTED_DESC
Definition: funcapi.h:296
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
int j
Definition: isn.c:78
int i
Definition: isn.c:77
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc(Size size)
Definition: mcxt.c:1365
NameData relname
Definition: pg_class.h:38
static char buf[DEFAULT_XLOG_SEG_SIZE]
Definition: pg_test_fsync.c:71
uint64_t Datum
Definition: postgres.h:70
uint64 SPI_processed
Definition: spi.c:44
SPITupleTable * SPI_tuptable
Definition: spi.c:45
int SPI_connect(void)
Definition: spi.c:94
int SPI_finish(void)
Definition: spi.c:182
int SPI_exec(const char *src, long tcount)
Definition: spi.c:630
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition: spi.c:1220
#define SPI_OK_SELECT
Definition: spi.h:86
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
TupleDesc setDesc
Definition: execnodes.h:364
Tuplestorestate * setResult
Definition: execnodes.h:363
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26
Definition: c.h:706
xmlXPathContextPtr ctxt
Definition: xpath.c:39
xmlDocPtr doctree
Definition: xpath.c:38
xmlXPathObjectPtr res
Definition: xpath.c:40
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:764
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition: varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition: varatt.h:486
text * cstring_to_text(const char *s)
Definition: varlena.c:181
char * text_to_cstring(const text *t)
Definition: varlena.c:214
const char * name
Datum xpath(PG_FUNCTION_ARGS)
Definition: xml.c:4566
struct PgXmlErrorContext PgXmlErrorContext
Definition: xml.h:48
PgXmlErrorContext * pg_xml_init(PgXmlStrictness strictness)
void xml_ereport(PgXmlErrorContext *errcxt, int level, int sqlcode, const char *msg)
bool pg_xml_error_occurred(PgXmlErrorContext *errcxt)
void pg_xml_done(PgXmlErrorContext *errcxt, bool isError)
PgXmlStrictness
Definition: xml.h:40
@ PG_XML_STRICTNESS_LEGACY
Definition: xml.h:41
@ PG_XML_STRICTNESS_ALL
Definition: xml.h:44
static text * pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag, xmlChar *septag, xmlChar *plainsep)
Definition: xpath.c:533
Datum xpath_bool(PG_FUNCTION_ARGS)
Definition: xpath.c:441
Datum xpath_number(PG_FUNCTION_ARGS)
Definition: xpath.c:395
Datum xpath_table(PG_FUNCTION_ARGS)
Definition: xpath.c:602
static xmlChar * pgxml_texttoxmlchar(text *textstring)
Definition: xpath.c:238
PgXmlErrorContext * pgxml_parser_init(PgXmlStrictness strictness)
Definition: xpath.c:67
Datum xpath_string(PG_FUNCTION_ARGS)
Definition: xpath.c:340
static void cleanup_workspace(xpath_workspace *workspace)
Definition: xpath.c:519
Datum xml_encode_special_chars(PG_FUNCTION_ARGS)
Definition: xpath.c:88
Datum xpath_list(PG_FUNCTION_ARGS)
Definition: xpath.c:298
static xmlChar * pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlChar *toptagname, xmlChar *septagname, xmlChar *plainsep)
Definition: xpath.c:142
static xpath_workspace * pgxml_xpath(text *document, xmlChar *xpath, PgXmlErrorContext *xmlerrcxt)
Definition: xpath.c:484
PG_MODULE_MAGIC_EXT(.name="xml2",.version=PG_VERSION)
Datum xpath_nodeset(PG_FUNCTION_ARGS)
Definition: xpath.c:252
PG_FUNCTION_INFO_V1(xml_encode_special_chars)