PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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/tuplestore.h"
16#include "utils/xml.h"
17
18/* libxml includes */
19
20#include <libxml/xpath.h>
21#include <libxml/tree.h>
22#include <libxml/xmlmemory.h>
23#include <libxml/xmlerror.h>
24#include <libxml/parserInternals.h>
25
27 .name = "xml2",
28 .version = PG_VERSION
29);
30
31/* exported for use by xslt_proc.c */
32
34
35/* workspace for pgxml_xpath() */
36
43
44/* local declarations */
45
49
52
54
57
58static void cleanup_workspace(xpath_workspace *workspace);
59
60
61/*
62 * Initialize for xml parsing.
63 *
64 * As with the underlying pg_xml_init function, calls to this MUST be followed
65 * by a PG_TRY block that guarantees that pg_xml_done is called.
66 */
69{
71
72 /* Set up error handling (we share the core's error handler) */
74
75 /* Note: we're assuming an elog cannot be thrown by the following calls */
76
77 /* Initialize libxml */
79
80 return xmlerrcxt;
81}
82
83
84/* Encodes special characters (<, >, &, " and \r) as XML entities */
85
87
90{
92 text *volatile tout = NULL;
93 xmlChar *volatile tt = NULL;
95
97
98 PG_TRY();
99 {
100 xmlChar *ts;
101
103
107 "could not allocate xmlChar");
108 pfree(ts);
109
110 tout = cstring_to_text((char *) tt);
111 }
112 PG_CATCH();
113 {
114 if (tt != NULL)
115 xmlFree(tt);
116
117 pg_xml_done(xmlerrcxt, true);
118
119 PG_RE_THROW();
120 }
121 PG_END_TRY();
122
123 if (tt != NULL)
124 xmlFree(tt);
125
126 pg_xml_done(xmlerrcxt, false);
127
129}
130
131/*
132 * Function translates a nodeset into a text representation
133 *
134 * iterates over each node in the set and calls xmlNodeDump to write it to
135 * an xmlBuffer -from which an xmlChar * string is returned.
136 *
137 * each representation is surrounded by <tagname> ... </tagname>
138 *
139 * plainsep is an ordinary (not tag) separator - if used, then nodes are
140 * cast to string as output method
141 */
142static xmlChar *
147{
148 volatile xmlBufferPtr buf = NULL;
149 xmlChar *volatile result = NULL;
150 xmlChar *volatile str = NULL;
152
153 /* spin up some error handling */
155
156 PG_TRY();
157 {
159
162 "could not allocate xmlBuffer");
163
164 if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
165 {
169 }
170 if (nodeset != NULL)
171 {
172 for (int i = 0; i < nodeset->nodeNr; i++)
173 {
174 if (plainsep != NULL)
175 {
179 "could not allocate node text");
180
182 xmlFree(str);
183 str = NULL;
184
185 /* If this isn't the last entry, write the plain sep. */
186 if (i < (nodeset->nodeNr) - 1)
188 }
189 else
190 {
191 xmlNodePtr node = nodeset->nodeTab[i];
192
193 if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
194 {
198 }
199
200 /*
201 * XML_NAMESPACE_DECL nodes are xmlNs structs, that cannot
202 * be processed by xmlNodeDump().
203 */
204 if (node->type == XML_NAMESPACE_DECL)
205 {
209 "could not allocate node text");
211 xmlFree(str);
212 str = NULL;
213 }
214 else
215 xmlNodeDump(buf, node->doc, node, 1, 0);
216
217 if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
218 {
219 xmlBufferWriteChar(buf, "</");
222 }
223 }
224 }
225 }
226
227 if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
228 {
229 xmlBufferWriteChar(buf, "</");
232 }
233
237 "could not allocate result");
238 }
239 PG_CATCH();
240 {
241 if (result)
243 if (str)
244 xmlFree(str);
245 if (buf)
247
248 pg_xml_done(xmlerrcxt, true);
249
250 PG_RE_THROW();
251 }
252 PG_END_TRY();
253
255 pg_xml_done(xmlerrcxt, false);
256
257 return result;
258}
259
260
261/*
262 * Translate a PostgreSQL "varlena" -i.e. a variable length parameter
263 * into the libxml2 representation
264 */
265static xmlChar *
270
271/* Publicly visible XPath functions */
272
273/*
274 * This is a "raw" xpath function. Check that it returns child elements
275 * properly
276 */
278
279Datum
281{
283 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
286 xmlChar *xpath;
287 text *volatile xpres = NULL;
288 xpath_workspace *volatile workspace = NULL;
290
293
294 PG_TRY();
295 {
296 workspace = pgxml_xpath(document, xpath, xmlerrcxt);
298 }
299 PG_CATCH();
300 {
301 if (workspace)
302 cleanup_workspace(workspace);
303
304 pg_xml_done(xmlerrcxt, true);
305 PG_RE_THROW();
306 }
307 PG_END_TRY();
308
309 cleanup_workspace(workspace);
310 pg_xml_done(xmlerrcxt, false);
311
312 pfree(xpath);
313
314 if (xpres == NULL)
317}
318
319/*
320 * The following function is almost identical, but returns the elements in
321 * a list.
322 */
324
325Datum
327{
329 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
331 xmlChar *xpath;
332 text *volatile xpres = NULL;
333 xpath_workspace *volatile workspace = NULL;
335
338
339 PG_TRY();
340 {
341 workspace = pgxml_xpath(document, xpath, xmlerrcxt);
343 }
344 PG_CATCH();
345 {
346 if (workspace)
347 cleanup_workspace(workspace);
348
349 pg_xml_done(xmlerrcxt, true);
350 PG_RE_THROW();
351 }
352 PG_END_TRY();
353
354 cleanup_workspace(workspace);
355 pg_xml_done(xmlerrcxt, false);
356
357 pfree(xpath);
358
359 if (xpres == NULL)
362}
363
364
366
367Datum
369{
371 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
372 xmlChar *xpath;
374 text *volatile xpres = NULL;
375 xpath_workspace *volatile workspace = NULL;
377
379
380 /*
381 * We encapsulate the supplied path with "string()" = 8 chars + 1 for NUL
382 * at end
383 */
384 /* We could try casting to string using the libxml function? */
385
386 xpath = (xmlChar *) palloc(pathsize + 9);
387 memcpy(xpath, "string(", 7);
389 xpath[pathsize + 7] = ')';
390 xpath[pathsize + 8] = '\0';
391
393
394 PG_TRY();
395 {
396 workspace = pgxml_xpath(document, xpath, xmlerrcxt);
397 xpres = pgxml_result_to_text(workspace->res, NULL, NULL, NULL);
398 }
399 PG_CATCH();
400 {
401 if (workspace)
402 cleanup_workspace(workspace);
403
404 pg_xml_done(xmlerrcxt, true);
405 PG_RE_THROW();
406 }
407 PG_END_TRY();
408
409 cleanup_workspace(workspace);
410 pg_xml_done(xmlerrcxt, false);
411
412 pfree(xpath);
413
414 if (xpres == NULL)
417}
418
419
421
422Datum
424{
426 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
427 xmlChar *xpath;
428 volatile float4 fRes = 0.0;
429 volatile bool isNull = false;
430 xpath_workspace *volatile workspace = NULL;
432
435
436 PG_TRY();
437 {
438 workspace = pgxml_xpath(document, xpath, xmlerrcxt);
439 pfree(xpath);
440
441 if (workspace->res == NULL)
442 isNull = true;
443 else
444 fRes = xmlXPathCastToNumber(workspace->res);
445 }
446 PG_CATCH();
447 {
448 if (workspace)
449 cleanup_workspace(workspace);
450
451 pg_xml_done(xmlerrcxt, true);
452 PG_RE_THROW();
453 }
454 PG_END_TRY();
455
456 cleanup_workspace(workspace);
457 pg_xml_done(xmlerrcxt, false);
458
459 if (isNull || xmlXPathIsNaN(fRes))
461
463}
464
465
467
468Datum
470{
472 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
473 xmlChar *xpath;
474 volatile int bRes = 0;
475 xpath_workspace *volatile workspace = NULL;
477
480
481 PG_TRY();
482 {
483 workspace = pgxml_xpath(document, xpath, xmlerrcxt);
484 pfree(xpath);
485
486 if (workspace->res == NULL)
487 bRes = 0;
488 else
489 bRes = xmlXPathCastToBoolean(workspace->res);
490 }
491 PG_CATCH();
492 {
493 if (workspace)
494 cleanup_workspace(workspace);
495
496 pg_xml_done(xmlerrcxt, true);
497 PG_RE_THROW();
498 }
499 PG_END_TRY();
500
501 cleanup_workspace(workspace);
502 pg_xml_done(xmlerrcxt, false);
503
505}
506
507
508
509/* Core function to evaluate XPath query */
510
511static xpath_workspace *
513{
517
518 workspace->doctree = NULL;
519 workspace->ctxt = NULL;
520 workspace->res = NULL;
521
522 PG_TRY();
523 {
524 workspace->doctree = xmlReadMemory((char *) VARDATA_ANY(document),
525 docsize, NULL, NULL,
527 if (workspace->doctree != NULL)
528 {
529 workspace->ctxt = xmlXPathNewContext(workspace->doctree);
530 if (workspace->ctxt == NULL)
532 "could not allocate XPath context");
533
534 workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
535
536 /* compile the path */
537 comppath = xmlXPathCtxtCompile(workspace->ctxt, xpath);
540 "XPath Syntax Error");
541
542 /* Now evaluate the path expression. */
543 workspace->res = xmlXPathCompiledEval(comppath, workspace->ctxt);
544
546 comppath = NULL;
547 }
548 }
549 PG_CATCH();
550 {
551 if (comppath != NULL)
553 cleanup_workspace(workspace);
554
555 PG_RE_THROW();
556 }
557 PG_END_TRY();
558
559 return workspace;
560}
561
562/* Clean up after processing the result of pgxml_xpath() */
563static void
565{
566 if (workspace->res)
567 xmlXPathFreeObject(workspace->res);
568 workspace->res = NULL;
569 if (workspace->ctxt)
570 xmlXPathFreeContext(workspace->ctxt);
571 workspace->ctxt = NULL;
572 if (workspace->doctree)
573 xmlFreeDoc(workspace->doctree);
574 workspace->doctree = NULL;
575}
576
577static text *
582{
583 xmlChar *volatile xpresstr = NULL;
584 text *volatile xpres = NULL;
586
587 if (res == NULL)
588 return NULL;
589
590 /* spin some error handling */
592
593 PG_TRY();
594 {
595 switch (res->type)
596 {
597 case XPATH_NODESET:
598 xpresstr = pgxmlNodeSetToText(res->nodesetval,
599 toptag,
601 break;
602
603 case XPATH_STRING:
604 xpresstr = xmlStrdup(res->stringval);
607 "could not allocate result");
608 break;
609
610 default:
611 elog(NOTICE, "unsupported XQuery result: %d", res->type);
612 xpresstr = xmlStrdup((const xmlChar *) "<unsupported/>");
615 "could not allocate result");
616 }
617
618 /* Now convert this result back to text */
619 xpres = cstring_to_text((char *) xpresstr);
620 }
621 PG_CATCH();
622 {
623 if (xpresstr != NULL)
625
626 pg_xml_done(xmlerrcxt, true);
627
628 PG_RE_THROW();
629 }
630 PG_END_TRY();
631
632 /* Free various storage */
634
635 pg_xml_done(xmlerrcxt, false);
636
637 return xpres;
638}
639
640/*
641 * xpath_table is a table function. It needs some tidying (as do the
642 * other functions here!
643 */
645
646Datum
648{
649 /* Function parameters */
654 char *condition = text_to_cstring(PG_GETARG_TEXT_PP(4));
655
656 /* SPI (input tuple) support */
657 SPITupleTable *tuptable;
660
661
662 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
663 AttInMetadata *attinmeta;
664
665 char **values;
666 xmlChar **xpaths;
667 char *pos;
668 const char *pathsep = "|";
669
670 int numpaths;
671 int ret;
672 uint64 proc;
673 int j;
674 int rownr; /* For issuing multiple rows from one original
675 * document */
676 bool had_values; /* To determine end of nodeset results */
679 volatile xmlDocPtr doctree = NULL;
680 xmlXPathContextPtr volatile ctxt = NULL;
681 xmlXPathObjectPtr volatile res = NULL;
683 xmlChar *volatile resstr = NULL;
684
686
687 /* must have at least one output column (for the pkey) */
688 if (rsinfo->setDesc->natts < 1)
691 errmsg("xpath_table must have at least one output column")));
692
693 /*
694 * At the moment we assume that the returned attributes make sense for the
695 * XPath specified (i.e. we trust the caller). It's not fatal if they get
696 * it wrong - the input function for the column type will raise an error
697 * if the path result can't be converted into the correct binary
698 * representation.
699 */
700
701 attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc);
702
703 values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *));
704 xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *));
705
706 /*
707 * Split XPaths. xpathset is a writable CString.
708 *
709 * Note that we stop splitting once we've done all needed for tupdesc
710 */
711 numpaths = 0;
712 pos = xpathset;
713 while (numpaths < (rsinfo->setDesc->natts - 1))
714 {
715 xpaths[numpaths++] = (xmlChar *) pos;
716 pos = strstr(pos, pathsep);
717 if (pos != NULL)
718 {
719 *pos = '\0';
720 pos++;
721 }
722 else
723 break;
724 }
725
726 /* Now build query */
728
729 /* Build initial sql statement */
730 appendStringInfo(&query_buf, "SELECT %s, %s FROM %s WHERE %s",
731 pkeyfield,
732 xmlfield,
733 relname,
734 condition);
735
736 SPI_connect();
737
738 if ((ret = SPI_exec(query_buf.data, 0)) != SPI_OK_SELECT)
739 elog(ERROR, "xpath_table: SPI execution failed for query %s",
740 query_buf.data);
741
742 proc = SPI_processed;
743 tuptable = SPI_tuptable;
744 spi_tupdesc = tuptable->tupdesc;
745
746 /*
747 * Check that SPI returned correct result. If you put a comma into one of
748 * the function parameters, this will catch it when the SPI query returns
749 * e.g. 3 columns.
750 */
751 if (spi_tupdesc->natts != 2)
752 {
754 errmsg("expression returning multiple columns is not valid in parameter list"),
755 errdetail("Expected two columns in SPI result, got %d.", spi_tupdesc->natts)));
756 }
757
758 /*
759 * Setup the parser. This should happen after we are done evaluating the
760 * query, in case it calls functions that set up libxml differently.
761 */
763
764 PG_TRY();
765 {
766 /* For each row i.e. document returned from SPI */
767 uint64 i;
768
769 for (i = 0; i < proc; i++)
770 {
771 char *pkey;
772 char *xmldoc;
774
775 /* Extract the row data as C Strings */
776 spi_tuple = tuptable->vals[i];
779
780 /*
781 * Clear the values array, so that not-well-formed documents
782 * return NULL in all columns. Note that this also means that
783 * spare columns will be NULL.
784 */
785 for (j = 0; j < rsinfo->setDesc->natts; j++)
786 values[j] = NULL;
787
788 /* Insert primary key */
789 values[0] = pkey;
790
791 /* Parse the document */
792 if (xmldoc)
793 doctree = xmlReadMemory(xmldoc, strlen(xmldoc),
794 NULL, NULL,
796 else /* treat NULL as not well-formed */
797 doctree = NULL;
798
799 if (doctree == NULL)
800 {
801 /* not well-formed, so output all-NULL tuple */
805 }
806 else
807 {
808 /* New loop here - we have to deal with nodeset results */
809 rownr = 0;
810
811 do
812 {
813 /* Now evaluate the set of xpaths. */
814 had_values = false;
815 for (j = 0; j < numpaths; j++)
816 {
817 ctxt = NULL;
818 res = NULL;
819 comppath = NULL;
820 resstr = NULL;
821
822 ctxt = xmlXPathNewContext(doctree);
823 if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt))
826 "could not allocate XPath context");
827
828 ctxt->node = xmlDocGetRootElement(doctree);
829
830 /* compile the path */
835 "XPath Syntax Error");
836
837 /* Now evaluate the path expression. */
838 res = xmlXPathCompiledEval(comppath, ctxt);
840 comppath = NULL;
841
842 if (res != NULL)
843 {
844 switch (res->type)
845 {
846 case XPATH_NODESET:
847 /* We see if this nodeset has enough nodes */
848 if (res->nodesetval != NULL &&
850 {
851 resstr = xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]);
855 "could not allocate result");
856 had_values = true;
857 }
858 else
859 resstr = NULL;
860
861 break;
862
863 case XPATH_STRING:
864 resstr = xmlStrdup(res->stringval);
868 "could not allocate result");
869 break;
870
871 default:
872 elog(NOTICE, "unsupported XQuery result: %d", res->type);
873 resstr = xmlStrdup((const xmlChar *) "<unsupported/>");
877 "could not allocate result");
878 }
879
880 /*
881 * Insert this into the appropriate column in the
882 * result tuple.
883 */
884 values[j + 1] = (char *) resstr;
885 resstr = NULL;
886 }
887
888 if (res != NULL)
889 {
891 res = NULL;
892 }
894 ctxt = NULL;
895 }
896
897 /* Now add the tuple to the output, if there is one. */
898 if (had_values)
899 {
903 }
904
905 /* BuildTupleFromCStrings() has copied the values. */
906 for (j = 1; j < rsinfo->setDesc->natts; j++)
907 {
908 if (values[j] != NULL)
909 {
910 xmlFree((xmlChar *) values[j]);
911 values[j] = NULL;
912 }
913 }
914
915 rownr++;
916 } while (had_values);
917 }
918
919 if (doctree != NULL)
920 xmlFreeDoc(doctree);
921 doctree = NULL;
922
923 if (pkey)
924 pfree(pkey);
925 if (xmldoc)
926 pfree(xmldoc);
927 }
928 }
929 PG_CATCH();
930 {
931 if (resstr != NULL)
933 for (j = 1; j < rsinfo->setDesc->natts; j++)
934 {
935 if (values[j] != NULL)
936 xmlFree((xmlChar *) values[j]);
937 }
938 if (res != NULL)
940 if (comppath != NULL)
942 if (ctxt != NULL)
944 if (doctree != NULL)
945 xmlFreeDoc(doctree);
946
947 pg_xml_done(xmlerrcxt, true);
948
949 PG_RE_THROW();
950 }
951 PG_END_TRY();
952
953 if (doctree != NULL)
954 xmlFreeDoc(doctree);
955
956 pg_xml_done(xmlerrcxt, false);
957
958 SPI_finish();
959
960 /*
961 * SFRM_Materialize mode expects us to return a NULL Datum. The actual
962 * tuples are in our tuplestore and passed back through rsinfo->setResult.
963 * rsinfo->setDesc is set to the tuple description that we actually used
964 * to build our tuples with, so the caller can verify we did what it was
965 * expecting.
966 */
967 return (Datum) 0;
968}
static Datum values[MAXATTR]
Definition bootstrap.c:190
int32_t int32
Definition c.h:620
uint64_t uint64
Definition c.h:625
float float4
Definition c.h:713
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
int errcode(int sqlerrcode)
Definition elog.c:875
#define PG_RE_THROW()
Definition elog.h:407
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define PG_TRY(...)
Definition elog.h:374
#define PG_END_TRY(...)
Definition elog.h:399
#define ERROR
Definition elog.h:40
#define PG_CATCH(...)
Definition elog.h:384
#define elog(elevel,...)
Definition elog.h:228
#define NOTICE
Definition elog.h:36
#define ereport(elevel,...)
Definition elog.h:152
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
#define palloc0_object(type)
Definition fe_memutils.h:90
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define PG_MODULE_MAGIC_EXT(...)
Definition fmgr.h:540
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define PG_RETURN_TEXT_P(x)
Definition fmgr.h:374
#define PG_RETURN_FLOAT4(x)
Definition fmgr.h:368
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
void InitMaterializedSRF(FunctionCallInfo fcinfo, uint32 flags)
Definition funcapi.c:76
#define MAT_SRF_USE_EXPECTED_DESC
Definition funcapi.h:296
const char * str
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
int j
Definition isn.c:78
int i
Definition isn.c:77
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
void * palloc(Size size)
Definition mcxt.c:1390
static char * errmsg
NameData relname
Definition pg_class.h:40
static char buf[DEFAULT_XLOG_SEG_SIZE]
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
uint64 SPI_processed
Definition spi.c:45
SPITupleTable * SPI_tuptable
Definition spi.c:46
int SPI_connect(void)
Definition spi.c:95
int SPI_finish(void)
Definition spi.c:183
int SPI_exec(const char *src, long tcount)
Definition spi.c:631
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition spi.c:1221
#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 tupdesc
Definition spi.h:25
HeapTuple * vals
Definition spi.h:26
Definition c.h:776
xmlXPathContextPtr ctxt
Definition xpath.c:40
xmlDocPtr doctree
Definition xpath.c:39
xmlXPathObjectPtr res
Definition xpath.c:41
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition tuplestore.c:765
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:184
char * text_to_cstring(const text *t)
Definition varlena.c:217
const char * name
Datum xpath(PG_FUNCTION_ARGS)
Definition xml.c:4572
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:578
Datum xpath_bool(PG_FUNCTION_ARGS)
Definition xpath.c:469
Datum xpath_number(PG_FUNCTION_ARGS)
Definition xpath.c:423
Datum xpath_table(PG_FUNCTION_ARGS)
Definition xpath.c:647
static xmlChar * pgxml_texttoxmlchar(text *textstring)
Definition xpath.c:266
PgXmlErrorContext * pgxml_parser_init(PgXmlStrictness strictness)
Definition xpath.c:68
Datum xpath_string(PG_FUNCTION_ARGS)
Definition xpath.c:368
static void cleanup_workspace(xpath_workspace *workspace)
Definition xpath.c:564
Datum xml_encode_special_chars(PG_FUNCTION_ARGS)
Definition xpath.c:89
Datum xpath_list(PG_FUNCTION_ARGS)
Definition xpath.c:326
static xmlChar * pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlChar *toptagname, xmlChar *septagname, xmlChar *plainsep)
Definition xpath.c:143
static xpath_workspace * pgxml_xpath(text *document, xmlChar *xpath, PgXmlErrorContext *xmlerrcxt)
Definition xpath.c:512
Datum xpath_nodeset(PG_FUNCTION_ARGS)
Definition xpath.c:280