PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
xpath.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "executor/spi.h"
#include "fmgr.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "utils/builtins.h"
#include "utils/xml.h"
#include <libxml/xpath.h>
#include <libxml/tree.h>
#include <libxml/xmlmemory.h>
#include <libxml/xmlerror.h>
#include <libxml/parserInternals.h>
Include dependency graph for xpath.c:

Go to the source code of this file.

Data Structures

struct  xpath_workspace
 

Functions

 PG_MODULE_MAGIC_EXT (.name="xml2",.version=PG_VERSION)
 
PgXmlErrorContextpgxml_parser_init (PgXmlStrictness strictness)
 
static xmlChar * pgxmlNodeSetToText (xmlNodeSetPtr nodeset, xmlChar *toptagname, xmlChar *septagname, xmlChar *plainsep)
 
static textpgxml_result_to_text (xmlXPathObjectPtr res, xmlChar *toptag, xmlChar *septag, xmlChar *plainsep)
 
static xmlChar * pgxml_texttoxmlchar (text *textstring)
 
static xmlXPathObjectPtr pgxml_xpath (text *document, xmlChar *xpath, xpath_workspace *workspace)
 
static void cleanup_workspace (xpath_workspace *workspace)
 
 PG_FUNCTION_INFO_V1 (xml_encode_special_chars)
 
Datum xml_encode_special_chars (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (xpath_nodeset)
 
Datum xpath_nodeset (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (xpath_list)
 
Datum xpath_list (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (xpath_string)
 
Datum xpath_string (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (xpath_number)
 
Datum xpath_number (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (xpath_bool)
 
Datum xpath_bool (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (xpath_table)
 
Datum xpath_table (PG_FUNCTION_ARGS)
 

Function Documentation

◆ cleanup_workspace()

static void cleanup_workspace ( xpath_workspace workspace)
static

Definition at line 422 of file xpath.c.

423{
424 if (workspace->res)
425 xmlXPathFreeObject(workspace->res);
426 workspace->res = NULL;
427 if (workspace->ctxt)
428 xmlXPathFreeContext(workspace->ctxt);
429 workspace->ctxt = NULL;
430 if (workspace->doctree)
431 xmlFreeDoc(workspace->doctree);
432 workspace->doctree = NULL;
433}
xmlXPathContextPtr ctxt
Definition: xpath.c:39
xmlDocPtr doctree
Definition: xpath.c:38
xmlXPathObjectPtr res
Definition: xpath.c:40

References xpath_workspace::ctxt, xpath_workspace::doctree, and xpath_workspace::res.

Referenced by pgxml_xpath(), xpath_bool(), xpath_list(), xpath_nodeset(), xpath_number(), and xpath_string().

◆ PG_FUNCTION_INFO_V1() [1/7]

PG_FUNCTION_INFO_V1 ( xml_encode_special_chars  )

◆ PG_FUNCTION_INFO_V1() [2/7]

PG_FUNCTION_INFO_V1 ( xpath_bool  )

◆ PG_FUNCTION_INFO_V1() [3/7]

PG_FUNCTION_INFO_V1 ( xpath_list  )

◆ PG_FUNCTION_INFO_V1() [4/7]

PG_FUNCTION_INFO_V1 ( xpath_nodeset  )

◆ PG_FUNCTION_INFO_V1() [5/7]

PG_FUNCTION_INFO_V1 ( xpath_number  )

◆ PG_FUNCTION_INFO_V1() [6/7]

PG_FUNCTION_INFO_V1 ( xpath_string  )

◆ PG_FUNCTION_INFO_V1() [7/7]

PG_FUNCTION_INFO_V1 ( xpath_table  )

◆ PG_MODULE_MAGIC_EXT()

PG_MODULE_MAGIC_EXT ( name = "xml2",
version = PG_VERSION 
)

◆ pgxml_parser_init()

PgXmlErrorContext * pgxml_parser_init ( PgXmlStrictness  strictness)

Definition at line 67 of file xpath.c.

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}
struct PgXmlErrorContext PgXmlErrorContext
Definition: xml.h:48
PgXmlErrorContext * pg_xml_init(PgXmlStrictness strictness)

References pg_xml_init().

Referenced by pgxml_xpath(), xpath_table(), and xslt_process().

◆ pgxml_result_to_text()

static text * pgxml_result_to_text ( xmlXPathObjectPtr  res,
xmlChar *  toptag,
xmlChar *  septag,
xmlChar *  plainsep 
)
static

Definition at line 436 of file xpath.c.

440{
441 xmlChar *xpresstr;
442 text *xpres;
443
444 if (res == NULL)
445 return NULL;
446
447 switch (res->type)
448 {
449 case XPATH_NODESET:
450 xpresstr = pgxmlNodeSetToText(res->nodesetval,
451 toptag,
452 septag, plainsep);
453 break;
454
455 case XPATH_STRING:
456 xpresstr = xmlStrdup(res->stringval);
457 break;
458
459 default:
460 elog(NOTICE, "unsupported XQuery result: %d", res->type);
461 xpresstr = xmlStrdup((const xmlChar *) "<unsupported/>");
462 }
463
464 /* Now convert this result back to text */
465 xpres = cstring_to_text((char *) xpresstr);
466
467 /* Free various storage */
468 xmlFree(xpresstr);
469
470 return xpres;
471}
#define elog(elevel,...)
Definition: elog.h:225
#define NOTICE
Definition: elog.h:35
Definition: c.h:658
text * cstring_to_text(const char *s)
Definition: varlena.c:192
static xmlChar * pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlChar *toptagname, xmlChar *septagname, xmlChar *plainsep)
Definition: xpath.c:120

References cstring_to_text(), elog, NOTICE, and pgxmlNodeSetToText().

Referenced by xpath_list(), xpath_nodeset(), and xpath_string().

◆ pgxml_texttoxmlchar()

static xmlChar * pgxml_texttoxmlchar ( text textstring)
static

Definition at line 189 of file xpath.c.

190{
191 return (xmlChar *) text_to_cstring(textstring);
192}
char * text_to_cstring(const text *t)
Definition: varlena.c:225

References text_to_cstring().

Referenced by xml_encode_special_chars(), xpath_bool(), xpath_list(), xpath_nodeset(), and xpath_number().

◆ pgxml_xpath()

static xmlXPathObjectPtr pgxml_xpath ( text document,
xmlChar *  xpath,
xpath_workspace workspace 
)
static

Definition at line 368 of file xpath.c.

369{
370 int32 docsize = VARSIZE_ANY_EXHDR(document);
371 PgXmlErrorContext *xmlerrcxt;
372 xmlXPathCompExprPtr comppath;
373
374 workspace->doctree = NULL;
375 workspace->ctxt = NULL;
376 workspace->res = NULL;
377
379
380 PG_TRY();
381 {
382 workspace->doctree = xmlReadMemory((char *) VARDATA_ANY(document),
383 docsize, NULL, NULL,
384 XML_PARSE_NOENT);
385 if (workspace->doctree != NULL)
386 {
387 workspace->ctxt = xmlXPathNewContext(workspace->doctree);
388 workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
389
390 /* compile the path */
391 comppath = xmlXPathCtxtCompile(workspace->ctxt, xpath);
392 if (comppath == NULL)
393 xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
394 "XPath Syntax Error");
395
396 /* Now evaluate the path expression. */
397 workspace->res = xmlXPathCompiledEval(comppath, workspace->ctxt);
398
399 xmlXPathFreeCompExpr(comppath);
400 }
401 }
402 PG_CATCH();
403 {
404 cleanup_workspace(workspace);
405
406 pg_xml_done(xmlerrcxt, true);
407
408 PG_RE_THROW();
409 }
410 PG_END_TRY();
411
412 if (workspace->res == NULL)
413 cleanup_workspace(workspace);
414
415 pg_xml_done(xmlerrcxt, false);
416
417 return workspace->res;
418}
int32_t int32
Definition: c.h:498
#define PG_RE_THROW()
Definition: elog.h:404
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:381
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
Datum xpath(PG_FUNCTION_ARGS)
Definition: xml.c:4519
void xml_ereport(PgXmlErrorContext *errcxt, int level, int sqlcode, const char *msg)
void pg_xml_done(PgXmlErrorContext *errcxt, bool isError)
@ PG_XML_STRICTNESS_LEGACY
Definition: xml.h:41
PgXmlErrorContext * pgxml_parser_init(PgXmlStrictness strictness)
Definition: xpath.c:67
static void cleanup_workspace(xpath_workspace *workspace)
Definition: xpath.c:422

References cleanup_workspace(), xpath_workspace::ctxt, xpath_workspace::doctree, ERROR, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pg_xml_done(), PG_XML_STRICTNESS_LEGACY, pgxml_parser_init(), xpath_workspace::res, VARDATA_ANY, VARSIZE_ANY_EXHDR, xml_ereport(), and xpath().

Referenced by xpath_bool(), xpath_list(), xpath_nodeset(), xpath_number(), and xpath_string().

◆ pgxmlNodeSetToText()

static xmlChar * pgxmlNodeSetToText ( xmlNodeSetPtr  nodeset,
xmlChar *  toptagname,
xmlChar *  septagname,
xmlChar *  plainsep 
)
static

Definition at line 120 of file xpath.c.

124{
125 xmlBufferPtr buf;
126 xmlChar *result;
127 int i;
128
129 buf = xmlBufferCreate();
130
131 if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
132 {
133 xmlBufferWriteChar(buf, "<");
134 xmlBufferWriteCHAR(buf, toptagname);
135 xmlBufferWriteChar(buf, ">");
136 }
137 if (nodeset != NULL)
138 {
139 for (i = 0; i < nodeset->nodeNr; i++)
140 {
141 if (plainsep != NULL)
142 {
143 xmlBufferWriteCHAR(buf,
144 xmlXPathCastNodeToString(nodeset->nodeTab[i]));
145
146 /* If this isn't the last entry, write the plain sep. */
147 if (i < (nodeset->nodeNr) - 1)
148 xmlBufferWriteChar(buf, (char *) plainsep);
149 }
150 else
151 {
152 if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
153 {
154 xmlBufferWriteChar(buf, "<");
155 xmlBufferWriteCHAR(buf, septagname);
156 xmlBufferWriteChar(buf, ">");
157 }
158 xmlNodeDump(buf,
159 nodeset->nodeTab[i]->doc,
160 nodeset->nodeTab[i],
161 1, 0);
162
163 if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
164 {
165 xmlBufferWriteChar(buf, "</");
166 xmlBufferWriteCHAR(buf, septagname);
167 xmlBufferWriteChar(buf, ">");
168 }
169 }
170 }
171 }
172
173 if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
174 {
175 xmlBufferWriteChar(buf, "</");
176 xmlBufferWriteCHAR(buf, toptagname);
177 xmlBufferWriteChar(buf, ">");
178 }
179 result = xmlStrdup(buf->content);
180 xmlBufferFree(buf);
181 return result;
182}
int i
Definition: isn.c:77
static char * buf
Definition: pg_test_fsync.c:72

References buf, and i.

Referenced by pgxml_result_to_text().

◆ xml_encode_special_chars()

Datum xml_encode_special_chars ( PG_FUNCTION_ARGS  )

Definition at line 88 of file xpath.c.

89{
90 text *tin = PG_GETARG_TEXT_PP(0);
91 text *tout;
92 xmlChar *ts,
93 *tt;
94
95 ts = pgxml_texttoxmlchar(tin);
96
97 tt = xmlEncodeSpecialChars(NULL, ts);
98
99 pfree(ts);
100
101 tout = cstring_to_text((char *) tt);
102
103 xmlFree(tt);
104
105 PG_RETURN_TEXT_P(tout);
106}
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
void pfree(void *pointer)
Definition: mcxt.c:2150
static xmlChar * pgxml_texttoxmlchar(text *textstring)
Definition: xpath.c:189

References cstring_to_text(), pfree(), PG_GETARG_TEXT_PP, PG_RETURN_TEXT_P, and pgxml_texttoxmlchar().

◆ xpath_bool()

Datum xpath_bool ( PG_FUNCTION_ARGS  )

Definition at line 338 of file xpath.c.

339{
340 text *document = PG_GETARG_TEXT_PP(0);
341 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
342 xmlChar *xpath;
343 int bRes;
344 xmlXPathObjectPtr res;
345 xpath_workspace workspace;
346
347 xpath = pgxml_texttoxmlchar(xpathsupp);
348
349 res = pgxml_xpath(document, xpath, &workspace);
350
351 pfree(xpath);
352
353 if (res == NULL)
354 PG_RETURN_BOOL(false);
355
356 bRes = xmlXPathCastToBoolean(res);
357
358 cleanup_workspace(&workspace);
359
360 PG_RETURN_BOOL(bRes);
361}
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
Definition: xpath.c:368

References cleanup_workspace(), pfree(), PG_GETARG_TEXT_PP, PG_RETURN_BOOL, pgxml_texttoxmlchar(), pgxml_xpath(), and xpath().

◆ xpath_list()

Datum xpath_list ( PG_FUNCTION_ARGS  )

Definition at line 236 of file xpath.c.

237{
238 text *document = PG_GETARG_TEXT_PP(0);
239 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
240 xmlChar *plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_PP(2));
241 xmlChar *xpath;
242 text *xpres;
243 xmlXPathObjectPtr res;
244 xpath_workspace workspace;
245
246 xpath = pgxml_texttoxmlchar(xpathsupp);
247
248 res = pgxml_xpath(document, xpath, &workspace);
249
250 xpres = pgxml_result_to_text(res, NULL, NULL, plainsep);
251
252 cleanup_workspace(&workspace);
253
254 pfree(xpath);
255
256 if (xpres == NULL)
258 PG_RETURN_TEXT_P(xpres);
259}
#define PG_RETURN_NULL()
Definition: fmgr.h:345
static text * pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag, xmlChar *septag, xmlChar *plainsep)
Definition: xpath.c:436

References cleanup_workspace(), pfree(), PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, pgxml_result_to_text(), pgxml_texttoxmlchar(), pgxml_xpath(), and xpath().

◆ xpath_nodeset()

Datum xpath_nodeset ( PG_FUNCTION_ARGS  )

Definition at line 203 of file xpath.c.

204{
205 text *document = PG_GETARG_TEXT_PP(0);
206 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
207 xmlChar *toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_PP(2));
208 xmlChar *septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_PP(3));
209 xmlChar *xpath;
210 text *xpres;
211 xmlXPathObjectPtr res;
212 xpath_workspace workspace;
213
214 xpath = pgxml_texttoxmlchar(xpathsupp);
215
216 res = pgxml_xpath(document, xpath, &workspace);
217
218 xpres = pgxml_result_to_text(res, toptag, septag, NULL);
219
220 cleanup_workspace(&workspace);
221
222 pfree(xpath);
223
224 if (xpres == NULL)
226 PG_RETURN_TEXT_P(xpres);
227}

References cleanup_workspace(), pfree(), PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, pgxml_result_to_text(), pgxml_texttoxmlchar(), pgxml_xpath(), and xpath().

◆ xpath_number()

Datum xpath_number ( PG_FUNCTION_ARGS  )

Definition at line 306 of file xpath.c.

307{
308 text *document = PG_GETARG_TEXT_PP(0);
309 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
310 xmlChar *xpath;
311 float4 fRes;
312 xmlXPathObjectPtr res;
313 xpath_workspace workspace;
314
315 xpath = pgxml_texttoxmlchar(xpathsupp);
316
317 res = pgxml_xpath(document, xpath, &workspace);
318
319 pfree(xpath);
320
321 if (res == NULL)
323
324 fRes = xmlXPathCastToNumber(res);
325
326 cleanup_workspace(&workspace);
327
328 if (xmlXPathIsNaN(fRes))
330
331 PG_RETURN_FLOAT4(fRes);
332}
float float4
Definition: c.h:600
#define PG_RETURN_FLOAT4(x)
Definition: fmgr.h:366

References cleanup_workspace(), pfree(), PG_GETARG_TEXT_PP, PG_RETURN_FLOAT4, PG_RETURN_NULL, pgxml_texttoxmlchar(), pgxml_xpath(), and xpath().

◆ xpath_string()

Datum xpath_string ( PG_FUNCTION_ARGS  )

Definition at line 265 of file xpath.c.

266{
267 text *document = PG_GETARG_TEXT_PP(0);
268 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
269 xmlChar *xpath;
270 int32 pathsize;
271 text *xpres;
272 xmlXPathObjectPtr res;
273 xpath_workspace workspace;
274
275 pathsize = VARSIZE_ANY_EXHDR(xpathsupp);
276
277 /*
278 * We encapsulate the supplied path with "string()" = 8 chars + 1 for NUL
279 * at end
280 */
281 /* We could try casting to string using the libxml function? */
282
283 xpath = (xmlChar *) palloc(pathsize + 9);
284 memcpy(xpath, "string(", 7);
285 memcpy(xpath + 7, VARDATA_ANY(xpathsupp), pathsize);
286 xpath[pathsize + 7] = ')';
287 xpath[pathsize + 8] = '\0';
288
289 res = pgxml_xpath(document, xpath, &workspace);
290
291 xpres = pgxml_result_to_text(res, NULL, NULL, NULL);
292
293 cleanup_workspace(&workspace);
294
295 pfree(xpath);
296
297 if (xpres == NULL)
299 PG_RETURN_TEXT_P(xpres);
300}
void * palloc(Size size)
Definition: mcxt.c:1943

References cleanup_workspace(), palloc(), pfree(), PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, pgxml_result_to_text(), pgxml_xpath(), VARDATA_ANY, VARSIZE_ANY_EXHDR, and xpath().

◆ xpath_table()

Datum xpath_table ( PG_FUNCTION_ARGS  )

Definition at line 480 of file xpath.c.

481{
482 /* Function parameters */
483 char *pkeyfield = text_to_cstring(PG_GETARG_TEXT_PP(0));
484 char *xmlfield = text_to_cstring(PG_GETARG_TEXT_PP(1));
486 char *xpathset = text_to_cstring(PG_GETARG_TEXT_PP(3));
487 char *condition = text_to_cstring(PG_GETARG_TEXT_PP(4));
488
489 /* SPI (input tuple) support */
490 SPITupleTable *tuptable;
491 HeapTuple spi_tuple;
492 TupleDesc spi_tupdesc;
493
494
495 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
496 AttInMetadata *attinmeta;
497
498 char **values;
499 xmlChar **xpaths;
500 char *pos;
501 const char *pathsep = "|";
502
503 int numpaths;
504 int ret;
505 uint64 proc;
506 int j;
507 int rownr; /* For issuing multiple rows from one original
508 * document */
509 bool had_values; /* To determine end of nodeset results */
510 StringInfoData query_buf;
511 PgXmlErrorContext *xmlerrcxt;
512 volatile xmlDocPtr doctree = NULL;
513
515
516 /* must have at least one output column (for the pkey) */
517 if (rsinfo->setDesc->natts < 1)
519 (errcode(ERRCODE_SYNTAX_ERROR),
520 errmsg("xpath_table must have at least one output column")));
521
522 /*
523 * At the moment we assume that the returned attributes make sense for the
524 * XPath specified (i.e. we trust the caller). It's not fatal if they get
525 * it wrong - the input function for the column type will raise an error
526 * if the path result can't be converted into the correct binary
527 * representation.
528 */
529
530 attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc);
531
532 values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *));
533 xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *));
534
535 /*
536 * Split XPaths. xpathset is a writable CString.
537 *
538 * Note that we stop splitting once we've done all needed for tupdesc
539 */
540 numpaths = 0;
541 pos = xpathset;
542 while (numpaths < (rsinfo->setDesc->natts - 1))
543 {
544 xpaths[numpaths++] = (xmlChar *) pos;
545 pos = strstr(pos, pathsep);
546 if (pos != NULL)
547 {
548 *pos = '\0';
549 pos++;
550 }
551 else
552 break;
553 }
554
555 /* Now build query */
556 initStringInfo(&query_buf);
557
558 /* Build initial sql statement */
559 appendStringInfo(&query_buf, "SELECT %s, %s FROM %s WHERE %s",
560 pkeyfield,
561 xmlfield,
562 relname,
563 condition);
564
565 SPI_connect();
566
567 if ((ret = SPI_exec(query_buf.data, 0)) != SPI_OK_SELECT)
568 elog(ERROR, "xpath_table: SPI execution failed for query %s",
569 query_buf.data);
570
571 proc = SPI_processed;
572 tuptable = SPI_tuptable;
573 spi_tupdesc = tuptable->tupdesc;
574
575 /*
576 * Check that SPI returned correct result. If you put a comma into one of
577 * the function parameters, this will catch it when the SPI query returns
578 * e.g. 3 columns.
579 */
580 if (spi_tupdesc->natts != 2)
581 {
582 ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
583 errmsg("expression returning multiple columns is not valid in parameter list"),
584 errdetail("Expected two columns in SPI result, got %d.", spi_tupdesc->natts)));
585 }
586
587 /*
588 * Setup the parser. This should happen after we are done evaluating the
589 * query, in case it calls functions that set up libxml differently.
590 */
592
593 PG_TRY();
594 {
595 /* For each row i.e. document returned from SPI */
596 uint64 i;
597
598 for (i = 0; i < proc; i++)
599 {
600 char *pkey;
601 char *xmldoc;
602 xmlXPathContextPtr ctxt;
603 xmlXPathObjectPtr res;
604 xmlChar *resstr;
605 xmlXPathCompExprPtr comppath;
606 HeapTuple ret_tuple;
607
608 /* Extract the row data as C Strings */
609 spi_tuple = tuptable->vals[i];
610 pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
611 xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2);
612
613 /*
614 * Clear the values array, so that not-well-formed documents
615 * return NULL in all columns. Note that this also means that
616 * spare columns will be NULL.
617 */
618 for (j = 0; j < rsinfo->setDesc->natts; j++)
619 values[j] = NULL;
620
621 /* Insert primary key */
622 values[0] = pkey;
623
624 /* Parse the document */
625 if (xmldoc)
626 doctree = xmlReadMemory(xmldoc, strlen(xmldoc),
627 NULL, NULL,
628 XML_PARSE_NOENT);
629 else /* treat NULL as not well-formed */
630 doctree = NULL;
631
632 if (doctree == NULL)
633 {
634 /* not well-formed, so output all-NULL tuple */
635 ret_tuple = BuildTupleFromCStrings(attinmeta, values);
636 tuplestore_puttuple(rsinfo->setResult, ret_tuple);
637 heap_freetuple(ret_tuple);
638 }
639 else
640 {
641 /* New loop here - we have to deal with nodeset results */
642 rownr = 0;
643
644 do
645 {
646 /* Now evaluate the set of xpaths. */
647 had_values = false;
648 for (j = 0; j < numpaths; j++)
649 {
650 ctxt = xmlXPathNewContext(doctree);
651 ctxt->node = xmlDocGetRootElement(doctree);
652
653 /* compile the path */
654 comppath = xmlXPathCtxtCompile(ctxt, xpaths[j]);
655 if (comppath == NULL)
656 xml_ereport(xmlerrcxt, ERROR,
657 ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
658 "XPath Syntax Error");
659
660 /* Now evaluate the path expression. */
661 res = xmlXPathCompiledEval(comppath, ctxt);
662 xmlXPathFreeCompExpr(comppath);
663
664 if (res != NULL)
665 {
666 switch (res->type)
667 {
668 case XPATH_NODESET:
669 /* We see if this nodeset has enough nodes */
670 if (res->nodesetval != NULL &&
671 rownr < res->nodesetval->nodeNr)
672 {
673 resstr = xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]);
674 had_values = true;
675 }
676 else
677 resstr = NULL;
678
679 break;
680
681 case XPATH_STRING:
682 resstr = xmlStrdup(res->stringval);
683 break;
684
685 default:
686 elog(NOTICE, "unsupported XQuery result: %d", res->type);
687 resstr = xmlStrdup((const xmlChar *) "<unsupported/>");
688 }
689
690 /*
691 * Insert this into the appropriate column in the
692 * result tuple.
693 */
694 values[j + 1] = (char *) resstr;
695 }
696 xmlXPathFreeContext(ctxt);
697 }
698
699 /* Now add the tuple to the output, if there is one. */
700 if (had_values)
701 {
702 ret_tuple = BuildTupleFromCStrings(attinmeta, values);
703 tuplestore_puttuple(rsinfo->setResult, ret_tuple);
704 heap_freetuple(ret_tuple);
705 }
706
707 rownr++;
708 } while (had_values);
709 }
710
711 if (doctree != NULL)
712 xmlFreeDoc(doctree);
713 doctree = NULL;
714
715 if (pkey)
716 pfree(pkey);
717 if (xmldoc)
718 pfree(xmldoc);
719 }
720 }
721 PG_CATCH();
722 {
723 if (doctree != NULL)
724 xmlFreeDoc(doctree);
725
726 pg_xml_done(xmlerrcxt, true);
727
728 PG_RE_THROW();
729 }
730 PG_END_TRY();
731
732 if (doctree != NULL)
733 xmlFreeDoc(doctree);
734
735 pg_xml_done(xmlerrcxt, false);
736
737 SPI_finish();
738
739 /*
740 * SFRM_Materialize mode expects us to return a NULL Datum. The actual
741 * tuples are in our tuplestore and passed back through rsinfo->setResult.
742 * rsinfo->setDesc is set to the tuple description that we actually used
743 * to build our tuples with, so the caller can verify we did what it was
744 * expecting.
745 */
746 return (Datum) 0;
747}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
uint64_t uint64
Definition: c.h:503
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2324
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2275
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
NameData relname
Definition: pg_class.h:38
uintptr_t Datum
Definition: postgres.h:69
uint64 SPI_processed
Definition: spi.c:44
SPITupleTable * SPI_tuptable
Definition: spi.c:45
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 setDesc
Definition: execnodes.h:359
Tuplestorestate * setResult
Definition: execnodes.h:358
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:764

References appendStringInfo(), BuildTupleFromCStrings(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, heap_freetuple(), i, InitMaterializedSRF(), initStringInfo(), j, MAT_SRF_USE_EXPECTED_DESC, TupleDescData::natts, NOTICE, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_GETARG_TEXT_PP, PG_RE_THROW, PG_TRY, pg_xml_done(), PG_XML_STRICTNESS_LEGACY, pgxml_parser_init(), relname, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SPI_connect(), SPI_exec(), SPI_finish(), SPI_getvalue(), SPI_OK_SELECT, SPI_processed, SPI_tuptable, text_to_cstring(), SPITupleTable::tupdesc, TupleDescGetAttInMetadata(), tuplestore_puttuple(), SPITupleTable::vals, values, and xml_ereport().