PostgreSQL Source Code  git master
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 "miscadmin.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 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:37
xmlDocPtr doctree
Definition: xpath.c:36
xmlXPathObjectPtr res
Definition: xpath.c:38

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

66 {
67  PgXmlErrorContext *xmlerrcxt;
68 
69  /* Set up error handling (we share the core's error handler) */
70  xmlerrcxt = pg_xml_init(strictness);
71 
72  /* Note: we're assuming an elog cannot be thrown by the following calls */
73 
74  /* Initialize libxml */
75  xmlInitParser();
76 
77  xmlSubstituteEntitiesDefault(1);
78  xmlLoadExtDtdDefaultValue = 1;
79 
80  return xmlerrcxt;
81 }
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:218
#define NOTICE
Definition: elog.h:29
Definition: c.h:633
text * cstring_to_text(const char *s)
Definition: varlena.c:188
static xmlChar * pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlChar *toptagname, xmlChar *septagname, xmlChar *plainsep)
Definition: xpath.c:121

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

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

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

370 {
371  int32 docsize = VARSIZE_ANY_EXHDR(document);
372  PgXmlErrorContext *xmlerrcxt;
373  xmlXPathCompExprPtr comppath;
374 
375  workspace->doctree = NULL;
376  workspace->ctxt = NULL;
377  workspace->res = NULL;
378 
380 
381  PG_TRY();
382  {
383  workspace->doctree = xmlParseMemory((char *) VARDATA_ANY(document),
384  docsize);
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 = xmlXPathCompile(xpath);
392  if (comppath == NULL)
393  xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
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 }
signed int int32
Definition: c.h:440
#define PG_RE_THROW()
Definition: elog.h:340
#define PG_END_TRY()
Definition: elog.h:324
#define PG_TRY()
Definition: elog.h:299
#define ERROR
Definition: elog.h:33
#define PG_CATCH()
Definition: elog.h:309
#define VARDATA_ANY(PTR)
Definition: postgres.h:361
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:354
Datum xpath(PG_FUNCTION_ARGS)
Definition: xml.c:4166
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:65
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 121 of file xpath.c.

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

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

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

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

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

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

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

◆ xpath_nodeset()

Datum xpath_nodeset ( PG_FUNCTION_ARGS  )

Definition at line 204 of file xpath.c.

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

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

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

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

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 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)
518  ereport(ERROR,
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  if ((ret = SPI_connect()) < 0)
566  elog(ERROR, "xpath_table: SPI_connect returned %d", ret);
567 
568  if ((ret = SPI_exec(query_buf.data, 0)) != SPI_OK_SELECT)
569  elog(ERROR, "xpath_table: SPI execution failed for query %s",
570  query_buf.data);
571 
572  proc = SPI_processed;
573  tuptable = SPI_tuptable;
574  spi_tupdesc = tuptable->tupdesc;
575 
576  /*
577  * Check that SPI returned correct result. If you put a comma into one of
578  * the function parameters, this will catch it when the SPI query returns
579  * e.g. 3 columns.
580  */
581  if (spi_tupdesc->natts != 2)
582  {
583  ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
584  errmsg("expression returning multiple columns is not valid in parameter list"),
585  errdetail("Expected two columns in SPI result, got %d.", spi_tupdesc->natts)));
586  }
587 
588  /*
589  * Setup the parser. This should happen after we are done evaluating the
590  * query, in case it calls functions that set up libxml differently.
591  */
593 
594  PG_TRY();
595  {
596  /* For each row i.e. document returned from SPI */
597  uint64 i;
598 
599  for (i = 0; i < proc; i++)
600  {
601  char *pkey;
602  char *xmldoc;
603  xmlXPathContextPtr ctxt;
604  xmlXPathObjectPtr res;
605  xmlChar *resstr;
606  xmlXPathCompExprPtr comppath;
607  HeapTuple ret_tuple;
608 
609  /* Extract the row data as C Strings */
610  spi_tuple = tuptable->vals[i];
611  pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
612  xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2);
613 
614  /*
615  * Clear the values array, so that not-well-formed documents
616  * return NULL in all columns. Note that this also means that
617  * spare columns will be NULL.
618  */
619  for (j = 0; j < rsinfo->setDesc->natts; j++)
620  values[j] = NULL;
621 
622  /* Insert primary key */
623  values[0] = pkey;
624 
625  /* Parse the document */
626  if (xmldoc)
627  doctree = xmlParseMemory(xmldoc, strlen(xmldoc));
628  else /* treat NULL as not well-formed */
629  doctree = NULL;
630 
631  if (doctree == NULL)
632  {
633  /* not well-formed, so output all-NULL tuple */
634  ret_tuple = BuildTupleFromCStrings(attinmeta, values);
635  tuplestore_puttuple(rsinfo->setResult, ret_tuple);
636  heap_freetuple(ret_tuple);
637  }
638  else
639  {
640  /* New loop here - we have to deal with nodeset results */
641  rownr = 0;
642 
643  do
644  {
645  /* Now evaluate the set of xpaths. */
646  had_values = false;
647  for (j = 0; j < numpaths; j++)
648  {
649  ctxt = xmlXPathNewContext(doctree);
650  ctxt->node = xmlDocGetRootElement(doctree);
651 
652  /* compile the path */
653  comppath = xmlXPathCompile(xpaths[j]);
654  if (comppath == NULL)
655  xml_ereport(xmlerrcxt, ERROR,
656  ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
657  "XPath Syntax Error");
658 
659  /* Now evaluate the path expression. */
660  res = xmlXPathCompiledEval(comppath, ctxt);
661  xmlXPathFreeCompExpr(comppath);
662 
663  if (res != NULL)
664  {
665  switch (res->type)
666  {
667  case XPATH_NODESET:
668  /* We see if this nodeset has enough nodes */
669  if (res->nodesetval != NULL &&
670  rownr < res->nodesetval->nodeNr)
671  {
672  resstr = xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]);
673  had_values = true;
674  }
675  else
676  resstr = NULL;
677 
678  break;
679 
680  case XPATH_STRING:
681  resstr = xmlStrdup(res->stringval);
682  break;
683 
684  default:
685  elog(NOTICE, "unsupported XQuery result: %d", res->type);
686  resstr = xmlStrdup((const xmlChar *) "<unsupported/>");
687  }
688 
689  /*
690  * Insert this into the appropriate column in the
691  * result tuple.
692  */
693  values[j + 1] = (char *) resstr;
694  }
695  xmlXPathFreeContext(ctxt);
696  }
697 
698  /* Now add the tuple to the output, if there is one. */
699  if (had_values)
700  {
701  ret_tuple = BuildTupleFromCStrings(attinmeta, values);
702  tuplestore_puttuple(rsinfo->setResult, ret_tuple);
703  heap_freetuple(ret_tuple);
704  }
705 
706  rownr++;
707  } while (had_values);
708  }
709 
710  if (doctree != NULL)
711  xmlFreeDoc(doctree);
712  doctree = NULL;
713 
714  if (pkey)
715  pfree(pkey);
716  if (xmldoc)
717  pfree(xmldoc);
718  }
719  }
720  PG_CATCH();
721  {
722  if (doctree != NULL)
723  xmlFreeDoc(doctree);
724 
725  pg_xml_done(xmlerrcxt, true);
726 
727  PG_RE_THROW();
728  }
729  PG_END_TRY();
730 
731  if (doctree != NULL)
732  xmlFreeDoc(doctree);
733 
734  pg_xml_done(xmlerrcxt, false);
735 
736  SPI_finish();
737 
738  /*
739  * SFRM_Materialize mode expects us to return a NULL Datum. The actual
740  * tuples are in our tuplestore and passed back through rsinfo->setResult.
741  * rsinfo->setDesc is set to the tuple description that we actually used
742  * to build our tuples with, so the caller can verify we did what it was
743  * expecting.
744  */
745  return (Datum) 0;
746 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ereport(elevel,...)
Definition: elog.h:143
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2135
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2086
void SetSingleFuncCall(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
#define SRF_SINGLE_USE_EXPECTED
Definition: funcapi.h:291
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
int j
Definition: isn.c:74
NameData relname
Definition: pg_class.h:38
uintptr_t Datum
Definition: postgres.h:411
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:628
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition: spi.c:1218
#define SPI_OK_SELECT
Definition: spi.h:86
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
TupleDesc setDesc
Definition: execnodes.h:317
Tuplestorestate * setResult
Definition: execnodes.h:316
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:730

References appendStringInfo(), BuildTupleFromCStrings(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, heap_freetuple(), i, initStringInfo(), j, 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, SetSingleFuncCall(), SPI_connect(), SPI_exec(), SPI_finish(), SPI_getvalue(), SPI_OK_SELECT, SPI_processed, SPI_tuptable, SRF_SINGLE_USE_EXPECTED, 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 26 of file xpath.c.