PostgreSQL Source Code  git master
xpath.c
Go to the documentation of this file.
1 /*
2  * contrib/xml2/xpath.c
3  *
4  * Parser interface for DOM-based parser (libxml) rather than
5  * stream-based SAX-type parser
6  */
7 #include "postgres.h"
8 
9 #include "access/htup_details.h"
10 #include "executor/spi.h"
11 #include "fmgr.h"
12 #include "funcapi.h"
13 #include "lib/stringinfo.h"
14 #include "miscadmin.h"
15 #include "utils/builtins.h"
16 #include "utils/xml.h"
17 
18 /* libxml includes */
19 
20 #include <libxml/xpath.h>
21 #include <libxml/tree.h>
22 #include <libxml/xmlmemory.h>
23 #include <libxml/xmlerror.h>
24 #include <libxml/parserInternals.h>
25 
27 
28 /* exported for use by xslt_proc.c */
29 
31 
32 /* workspace for pgxml_xpath() */
33 
34 typedef struct
35 {
36  xmlDocPtr doctree;
37  xmlXPathContextPtr ctxt;
38  xmlXPathObjectPtr res;
40 
41 /* local declarations */
42 
43 static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
44  xmlChar *toptagname, xmlChar *septagname,
45  xmlChar *plainsep);
46 
47 static text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
48  xmlChar *septag, xmlChar *plainsep);
49 
50 static xmlChar *pgxml_texttoxmlchar(text *textstring);
51 
52 static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath,
53  xpath_workspace *workspace);
54 
55 static void cleanup_workspace(xpath_workspace *workspace);
56 
57 
58 /*
59  * Initialize for xml parsing.
60  *
61  * As with the underlying pg_xml_init function, calls to this MUST be followed
62  * by a PG_TRY block that guarantees that pg_xml_done is called.
63  */
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 }
82 
83 
84 /* Encodes special characters (<, >, &, " and \r) as XML entities */
85 
87 
88 Datum
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 }
108 
109 /*
110  * Function translates a nodeset into a text representation
111  *
112  * iterates over each node in the set and calls xmlNodeDump to write it to
113  * an xmlBuffer -from which an xmlChar * string is returned.
114  *
115  * each representation is surrounded by <tagname> ... </tagname>
116  *
117  * plainsep is an ordinary (not tag) separator - if used, then nodes are
118  * cast to string as output method
119  */
120 static xmlChar *
121 pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
122  xmlChar *toptagname,
123  xmlChar *septagname,
124  xmlChar *plainsep)
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 }
184 
185 
186 /* Translate a PostgreSQL "varlena" -i.e. a variable length parameter
187  * into the libxml2 representation
188  */
189 static xmlChar *
191 {
192  return (xmlChar *) text_to_cstring(textstring);
193 }
194 
195 /* Publicly visible XPath functions */
196 
197 /*
198  * This is a "raw" xpath function. Check that it returns child elements
199  * properly
200  */
202 
203 Datum
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 }
229 
230 /*
231  * The following function is almost identical, but returns the elements in
232  * a list.
233  */
235 
236 Datum
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 }
261 
262 
264 
265 Datum
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 }
302 
303 
305 
306 Datum
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 }
334 
335 
337 
338 Datum
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 }
363 
364 
365 
366 /* Core function to evaluate XPath query */
367 
368 static xmlXPathObjectPtr
369 pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
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 }
419 
420 /* Clean up after processing the result of pgxml_xpath() */
421 static void
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 }
434 
435 static text *
436 pgxml_result_to_text(xmlXPathObjectPtr res,
437  xmlChar *toptag,
438  xmlChar *septag,
439  xmlChar *plainsep)
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 }
472 
473 /*
474  * xpath_table is a table function. It needs some tidying (as do the
475  * other functions here!
476  */
478 
479 Datum
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
signed int int32
Definition: c.h:483
float float4
Definition: c.h:618
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#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 NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2136
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2087
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_RETURN_FLOAT4(x)
Definition: fmgr.h:366
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
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
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1456
void * palloc(Size size)
Definition: mcxt.c:1226
NameData relname
Definition: pg_class.h:38
static char * buf
Definition: pg_test_fsync.c:73
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:333
Tuplestorestate * setResult
Definition: execnodes.h:332
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26
Definition: c.h:676
xmlXPathContextPtr ctxt
Definition: xpath.c:37
xmlDocPtr doctree
Definition: xpath.c:36
xmlXPathObjectPtr res
Definition: xpath.c:38
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:730
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
char * text_to_cstring(const text *t)
Definition: varlena.c:217
text * cstring_to_text(const char *s)
Definition: varlena.c:184
Datum xpath(PG_FUNCTION_ARGS)
Definition: xml.c:4443
struct PgXmlErrorContext PgXmlErrorContext
Definition: xml.h:48
void xml_ereport(PgXmlErrorContext *errcxt, int level, int sqlcode, const char *msg)
void pg_xml_done(PgXmlErrorContext *errcxt, bool isError)
PgXmlErrorContext * pg_xml_init(PgXmlStrictness strictness)
PgXmlStrictness
Definition: xml.h:40
@ PG_XML_STRICTNESS_LEGACY
Definition: xml.h:41
static text * pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag, xmlChar *septag, xmlChar *plainsep)
Definition: xpath.c:436
Datum xpath_bool(PG_FUNCTION_ARGS)
Definition: xpath.c:339
Datum xpath_number(PG_FUNCTION_ARGS)
Definition: xpath.c:307
Datum xpath_table(PG_FUNCTION_ARGS)
Definition: xpath.c:480
static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
Definition: xpath.c:369
static xmlChar * pgxml_texttoxmlchar(text *textstring)
Definition: xpath.c:190
PG_MODULE_MAGIC
Definition: xpath.c:26
PgXmlErrorContext * pgxml_parser_init(PgXmlStrictness strictness)
Definition: xpath.c:65
Datum xpath_string(PG_FUNCTION_ARGS)
Definition: xpath.c:266
static void cleanup_workspace(xpath_workspace *workspace)
Definition: xpath.c:422
Datum xml_encode_special_chars(PG_FUNCTION_ARGS)
Definition: xpath.c:89
Datum xpath_list(PG_FUNCTION_ARGS)
Definition: xpath.c:237
static xmlChar * pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlChar *toptagname, xmlChar *septagname, xmlChar *plainsep)
Definition: xpath.c:121
Datum xpath_nodeset(PG_FUNCTION_ARGS)
Definition: xpath.c:204
PG_FUNCTION_INFO_V1(xml_encode_special_chars)