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

421 {
422  if (workspace->res)
423  xmlXPathFreeObject(workspace->res);
424  workspace->res = NULL;
425  if (workspace->ctxt)
426  xmlXPathFreeContext(workspace->ctxt);
427  workspace->ctxt = NULL;
428  if (workspace->doctree)
429  xmlFreeDoc(workspace->doctree);
430  workspace->doctree = NULL;
431 }
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  return xmlerrcxt;
78 }
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 434 of file xpath.c.

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

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

188 {
189  return (xmlChar *) text_to_cstring(textstring);
190 }
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 366 of file xpath.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

479 {
480  /* Function parameters */
481  char *pkeyfield = text_to_cstring(PG_GETARG_TEXT_PP(0));
482  char *xmlfield = text_to_cstring(PG_GETARG_TEXT_PP(1));
484  char *xpathset = text_to_cstring(PG_GETARG_TEXT_PP(3));
485  char *condition = text_to_cstring(PG_GETARG_TEXT_PP(4));
486 
487  /* SPI (input tuple) support */
488  SPITupleTable *tuptable;
489  HeapTuple spi_tuple;
490  TupleDesc spi_tupdesc;
491 
492 
493  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
494  AttInMetadata *attinmeta;
495 
496  char **values;
497  xmlChar **xpaths;
498  char *pos;
499  const char *pathsep = "|";
500 
501  int numpaths;
502  int ret;
503  uint64 proc;
504  int j;
505  int rownr; /* For issuing multiple rows from one original
506  * document */
507  bool had_values; /* To determine end of nodeset results */
508  StringInfoData query_buf;
509  PgXmlErrorContext *xmlerrcxt;
510  volatile xmlDocPtr doctree = NULL;
511 
513 
514  /* must have at least one output column (for the pkey) */
515  if (rsinfo->setDesc->natts < 1)
516  ereport(ERROR,
517  (errcode(ERRCODE_SYNTAX_ERROR),
518  errmsg("xpath_table must have at least one output column")));
519 
520  /*
521  * At the moment we assume that the returned attributes make sense for the
522  * XPath specified (i.e. we trust the caller). It's not fatal if they get
523  * it wrong - the input function for the column type will raise an error
524  * if the path result can't be converted into the correct binary
525  * representation.
526  */
527 
528  attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc);
529 
530  values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *));
531  xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *));
532 
533  /*
534  * Split XPaths. xpathset is a writable CString.
535  *
536  * Note that we stop splitting once we've done all needed for tupdesc
537  */
538  numpaths = 0;
539  pos = xpathset;
540  while (numpaths < (rsinfo->setDesc->natts - 1))
541  {
542  xpaths[numpaths++] = (xmlChar *) pos;
543  pos = strstr(pos, pathsep);
544  if (pos != NULL)
545  {
546  *pos = '\0';
547  pos++;
548  }
549  else
550  break;
551  }
552 
553  /* Now build query */
554  initStringInfo(&query_buf);
555 
556  /* Build initial sql statement */
557  appendStringInfo(&query_buf, "SELECT %s, %s FROM %s WHERE %s",
558  pkeyfield,
559  xmlfield,
560  relname,
561  condition);
562 
563  if ((ret = SPI_connect()) < 0)
564  elog(ERROR, "xpath_table: SPI_connect returned %d", ret);
565 
566  if ((ret = SPI_exec(query_buf.data, 0)) != SPI_OK_SELECT)
567  elog(ERROR, "xpath_table: SPI execution failed for query %s",
568  query_buf.data);
569 
570  proc = SPI_processed;
571  tuptable = SPI_tuptable;
572  spi_tupdesc = tuptable->tupdesc;
573 
574  /*
575  * Check that SPI returned correct result. If you put a comma into one of
576  * the function parameters, this will catch it when the SPI query returns
577  * e.g. 3 columns.
578  */
579  if (spi_tupdesc->natts != 2)
580  {
581  ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
582  errmsg("expression returning multiple columns is not valid in parameter list"),
583  errdetail("Expected two columns in SPI result, got %d.", spi_tupdesc->natts)));
584  }
585 
586  /*
587  * Setup the parser. This should happen after we are done evaluating the
588  * query, in case it calls functions that set up libxml differently.
589  */
591 
592  PG_TRY();
593  {
594  /* For each row i.e. document returned from SPI */
595  uint64 i;
596 
597  for (i = 0; i < proc; i++)
598  {
599  char *pkey;
600  char *xmldoc;
601  xmlXPathContextPtr ctxt;
602  xmlXPathObjectPtr res;
603  xmlChar *resstr;
604  xmlXPathCompExprPtr comppath;
605  HeapTuple ret_tuple;
606 
607  /* Extract the row data as C Strings */
608  spi_tuple = tuptable->vals[i];
609  pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
610  xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2);
611 
612  /*
613  * Clear the values array, so that not-well-formed documents
614  * return NULL in all columns. Note that this also means that
615  * spare columns will be NULL.
616  */
617  for (j = 0; j < rsinfo->setDesc->natts; j++)
618  values[j] = NULL;
619 
620  /* Insert primary key */
621  values[0] = pkey;
622 
623  /* Parse the document */
624  if (xmldoc)
625  doctree = xmlReadMemory(xmldoc, strlen(xmldoc),
626  NULL, NULL,
627  XML_PARSE_NOENT);
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:1208
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2134
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2085
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:74
NameData relname
Definition: pg_class.h:38
uintptr_t Datum
Definition: postgres.h:64
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:97
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
TupleDesc setDesc
Definition: execnodes.h:340
Tuplestorestate * setResult
Definition: execnodes.h:339
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, 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 26 of file xpath.c.