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

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)
 

Variables

 PG_MODULE_MAGIC
 

Function Documentation

◆ cleanup_workspace()

static void cleanup_workspace ( xpath_workspace workspace)
static

Definition at line 419 of file xpath.c.

420{
421 if (workspace->res)
422 xmlXPathFreeObject(workspace->res);
423 workspace->res = NULL;
424 if (workspace->ctxt)
425 xmlXPathFreeContext(workspace->ctxt);
426 workspace->ctxt = NULL;
427 if (workspace->doctree)
428 xmlFreeDoc(workspace->doctree);
429 workspace->doctree = NULL;
430}
xmlXPathContextPtr ctxt
Definition: xpath.c:36
xmlDocPtr doctree
Definition: xpath.c:35
xmlXPathObjectPtr res
Definition: xpath.c:37

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  )

◆ pgxml_parser_init()

PgXmlErrorContext * pgxml_parser_init ( PgXmlStrictness  strictness)

Definition at line 64 of file xpath.c.

65{
66 PgXmlErrorContext *xmlerrcxt;
67
68 /* Set up error handling (we share the core's error handler) */
69 xmlerrcxt = pg_xml_init(strictness);
70
71 /* Note: we're assuming an elog cannot be thrown by the following calls */
72
73 /* Initialize libxml */
74 xmlInitParser();
75
76 return xmlerrcxt;
77}
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 433 of file xpath.c.

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

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

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

◆ pgxml_texttoxmlchar()

static xmlChar * pgxml_texttoxmlchar ( text textstring)
static

Definition at line 186 of file xpath.c.

187{
188 return (xmlChar *) text_to_cstring(textstring);
189}
char * text_to_cstring(const text *t)
Definition: varlena.c:217

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 365 of file xpath.c.

366{
367 int32 docsize = VARSIZE_ANY_EXHDR(document);
368 PgXmlErrorContext *xmlerrcxt;
369 xmlXPathCompExprPtr comppath;
370
371 workspace->doctree = NULL;
372 workspace->ctxt = NULL;
373 workspace->res = NULL;
374
376
377 PG_TRY();
378 {
379 workspace->doctree = xmlReadMemory((char *) VARDATA_ANY(document),
380 docsize, NULL, NULL,
381 XML_PARSE_NOENT);
382 if (workspace->doctree != NULL)
383 {
384 workspace->ctxt = xmlXPathNewContext(workspace->doctree);
385 workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
386
387 /* compile the path */
388 comppath = xmlXPathCtxtCompile(workspace->ctxt, xpath);
389 if (comppath == NULL)
390 xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
391 "XPath Syntax Error");
392
393 /* Now evaluate the path expression. */
394 workspace->res = xmlXPathCompiledEval(comppath, workspace->ctxt);
395
396 xmlXPathFreeCompExpr(comppath);
397 }
398 }
399 PG_CATCH();
400 {
401 cleanup_workspace(workspace);
402
403 pg_xml_done(xmlerrcxt, true);
404
405 PG_RE_THROW();
406 }
407 PG_END_TRY();
408
409 if (workspace->res == NULL)
410 cleanup_workspace(workspace);
411
412 pg_xml_done(xmlerrcxt, false);
413
414 return workspace->res;
415}
int32_t int32
Definition: c.h:481
#define PG_RE_THROW()
Definition: elog.h:412
#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:64
static void cleanup_workspace(xpath_workspace *workspace)
Definition: xpath.c:419

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 117 of file xpath.c.

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

86{
87 text *tin = PG_GETARG_TEXT_PP(0);
88 text *tout;
89 xmlChar *ts,
90 *tt;
91
92 ts = pgxml_texttoxmlchar(tin);
93
94 tt = xmlEncodeSpecialChars(NULL, ts);
95
96 pfree(ts);
97
98 tout = cstring_to_text((char *) tt);
99
100 xmlFree(tt);
101
102 PG_RETURN_TEXT_P(tout);
103}
#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:1521
static xmlChar * pgxml_texttoxmlchar(text *textstring)
Definition: xpath.c:186

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 335 of file xpath.c.

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

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

◆ xpath_list()

Datum xpath_list ( PG_FUNCTION_ARGS  )

Definition at line 233 of file xpath.c.

234{
235 text *document = PG_GETARG_TEXT_PP(0);
236 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
237 xmlChar *plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_PP(2));
238 xmlChar *xpath;
239 text *xpres;
240 xmlXPathObjectPtr res;
241 xpath_workspace workspace;
242
243 xpath = pgxml_texttoxmlchar(xpathsupp);
244
245 res = pgxml_xpath(document, xpath, &workspace);
246
247 xpres = pgxml_result_to_text(res, NULL, NULL, plainsep);
248
249 cleanup_workspace(&workspace);
250
251 pfree(xpath);
252
253 if (xpres == NULL)
255 PG_RETURN_TEXT_P(xpres);
256}
#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:433

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

◆ xpath_nodeset()

Datum xpath_nodeset ( PG_FUNCTION_ARGS  )

Definition at line 200 of file xpath.c.

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

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

◆ xpath_number()

Datum xpath_number ( PG_FUNCTION_ARGS  )

Definition at line 303 of file xpath.c.

304{
305 text *document = PG_GETARG_TEXT_PP(0);
306 text *xpathsupp = PG_GETARG_TEXT_PP(1); /* XPath expression */
307 xmlChar *xpath;
308 float4 fRes;
309 xmlXPathObjectPtr res;
310 xpath_workspace workspace;
311
312 xpath = pgxml_texttoxmlchar(xpathsupp);
313
314 res = pgxml_xpath(document, xpath, &workspace);
315
316 pfree(xpath);
317
318 if (res == NULL)
320
321 fRes = xmlXPathCastToNumber(res);
322
323 cleanup_workspace(&workspace);
324
325 if (xmlXPathIsNaN(fRes))
327
328 PG_RETURN_FLOAT4(fRes);
329}
float float4
Definition: c.h:583
#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(), res, and xpath().

◆ xpath_string()

Datum xpath_string ( PG_FUNCTION_ARGS  )

Definition at line 262 of file xpath.c.

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

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

◆ xpath_table()

Datum xpath_table ( PG_FUNCTION_ARGS  )

Definition at line 477 of file xpath.c.

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

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 25 of file xpath.c.