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  return xmlerrcxt;
78 }
79 
80 
81 /* Encodes special characters (<, >, &, " and \r) as XML entities */
82 
84 
85 Datum
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 }
105 
106 /*
107  * Function translates a nodeset into a text representation
108  *
109  * iterates over each node in the set and calls xmlNodeDump to write it to
110  * an xmlBuffer -from which an xmlChar * string is returned.
111  *
112  * each representation is surrounded by <tagname> ... </tagname>
113  *
114  * plainsep is an ordinary (not tag) separator - if used, then nodes are
115  * cast to string as output method
116  */
117 static xmlChar *
118 pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
119  xmlChar *toptagname,
120  xmlChar *septagname,
121  xmlChar *plainsep)
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 }
181 
182 
183 /* Translate a PostgreSQL "varlena" -i.e. a variable length parameter
184  * into the libxml2 representation
185  */
186 static xmlChar *
188 {
189  return (xmlChar *) text_to_cstring(textstring);
190 }
191 
192 /* Publicly visible XPath functions */
193 
194 /*
195  * This is a "raw" xpath function. Check that it returns child elements
196  * properly
197  */
199 
200 Datum
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 }
226 
227 /*
228  * The following function is almost identical, but returns the elements in
229  * a list.
230  */
232 
233 Datum
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 }
258 
259 
261 
262 Datum
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 }
299 
300 
302 
303 Datum
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 }
331 
332 
334 
335 Datum
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 }
360 
361 
362 
363 /* Core function to evaluate XPath query */
364 
365 static xmlXPathObjectPtr
366 pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
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 }
417 
418 /* Clean up after processing the result of pgxml_xpath() */
419 static void
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 }
432 
433 static text *
434 pgxml_result_to_text(xmlXPathObjectPtr res,
435  xmlChar *toptag,
436  xmlChar *septag,
437  xmlChar *plainsep)
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 }
470 
471 /*
472  * xpath_table is a table function. It needs some tidying (as do the
473  * other functions here!
474  */
476 
477 Datum
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:152
signed int int32
Definition: c.h:481
float float4
Definition: c.h:616
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#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 elog(elevel,...)
Definition: elog.h:224
#define NOTICE
Definition: elog.h:35
#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
#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:1434
int j
Definition: isn.c:74
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1508
void * palloc(Size size)
Definition: mcxt.c:1304
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: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:627
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition: spi.c:1217
#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
Definition: c.h:674
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:4450
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:434
Datum xpath_bool(PG_FUNCTION_ARGS)
Definition: xpath.c:336
Datum xpath_number(PG_FUNCTION_ARGS)
Definition: xpath.c:304
Datum xpath_table(PG_FUNCTION_ARGS)
Definition: xpath.c:478
static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
Definition: xpath.c:366
static xmlChar * pgxml_texttoxmlchar(text *textstring)
Definition: xpath.c:187
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:263
static void cleanup_workspace(xpath_workspace *workspace)
Definition: xpath.c:420
Datum xml_encode_special_chars(PG_FUNCTION_ARGS)
Definition: xpath.c:86
Datum xpath_list(PG_FUNCTION_ARGS)
Definition: xpath.c:234
static xmlChar * pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlChar *toptagname, xmlChar *septagname, xmlChar *plainsep)
Definition: xpath.c:118
Datum xpath_nodeset(PG_FUNCTION_ARGS)
Definition: xpath.c:201
PG_FUNCTION_INFO_V1(xml_encode_special_chars)