PostgreSQL Source Code  git master
xml.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * xml.c
4  * XML data type support.
5  *
6  *
7  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * src/backend/utils/adt/xml.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 
15 /*
16  * Generally, XML type support is only available when libxml use was
17  * configured during the build. But even if that is not done, the
18  * type and all the functions are available, but most of them will
19  * fail. For one thing, this avoids having to manage variant catalog
20  * installations. But it also has nice effects such as that you can
21  * dump a database containing XML type data even if the server is not
22  * linked with libxml. Thus, make sure xml_out() works even if nothing
23  * else does.
24  */
25 
26 /*
27  * Notes on memory management:
28  *
29  * Sometimes libxml allocates global structures in the hope that it can reuse
30  * them later on. This makes it impractical to change the xmlMemSetup
31  * functions on-the-fly; that is likely to lead to trying to pfree() chunks
32  * allocated with malloc() or vice versa. Since libxml might be used by
33  * loadable modules, eg libperl, our only safe choices are to change the
34  * functions at postmaster/backend launch or not at all. Since we'd rather
35  * not activate libxml in sessions that might never use it, the latter choice
36  * is the preferred one. However, for debugging purposes it can be awfully
37  * handy to constrain libxml's allocations to be done in a specific palloc
38  * context, where they're easy to track. Therefore there is code here that
39  * can be enabled in debug builds to redirect libxml's allocations into a
40  * special context LibxmlContext. It's not recommended to turn this on in
41  * a production build because of the possibility of bad interactions with
42  * external modules.
43  */
44 /* #define USE_LIBXMLCONTEXT */
45 
46 #include "postgres.h"
47 
48 #ifdef USE_LIBXML
49 #include <libxml/chvalid.h>
50 #include <libxml/entities.h>
51 #include <libxml/parser.h>
52 #include <libxml/parserInternals.h>
53 #include <libxml/tree.h>
54 #include <libxml/uri.h>
55 #include <libxml/xmlerror.h>
56 #include <libxml/xmlsave.h>
57 #include <libxml/xmlversion.h>
58 #include <libxml/xmlwriter.h>
59 #include <libxml/xpath.h>
60 #include <libxml/xpathInternals.h>
61 
62 /*
63  * We used to check for xmlStructuredErrorContext via a configure test; but
64  * that doesn't work on Windows, so instead use this grottier method of
65  * testing the library version number.
66  */
67 #if LIBXML_VERSION >= 20704
68 #define HAVE_XMLSTRUCTUREDERRORCONTEXT 1
69 #endif
70 #endif /* USE_LIBXML */
71 
72 #include "access/htup_details.h"
73 #include "access/table.h"
74 #include "catalog/namespace.h"
75 #include "catalog/pg_class.h"
76 #include "catalog/pg_type.h"
77 #include "commands/dbcommands.h"
78 #include "executor/spi.h"
79 #include "executor/tablefunc.h"
80 #include "fmgr.h"
81 #include "lib/stringinfo.h"
82 #include "libpq/pqformat.h"
83 #include "mb/pg_wchar.h"
84 #include "miscadmin.h"
85 #include "nodes/execnodes.h"
86 #include "nodes/miscnodes.h"
87 #include "nodes/nodeFuncs.h"
88 #include "utils/array.h"
89 #include "utils/builtins.h"
90 #include "utils/date.h"
91 #include "utils/datetime.h"
92 #include "utils/lsyscache.h"
93 #include "utils/memutils.h"
94 #include "utils/rel.h"
95 #include "utils/syscache.h"
96 #include "utils/xml.h"
97 
98 
99 /* GUC variables */
102 
103 #ifdef USE_LIBXML
104 
105 /* random number to identify PgXmlErrorContext */
106 #define ERRCXT_MAGIC 68275028
107 
108 struct PgXmlErrorContext
109 {
110  int magic;
111  /* strictness argument passed to pg_xml_init */
112  PgXmlStrictness strictness;
113  /* current error status and accumulated message, if any */
114  bool err_occurred;
115  StringInfoData err_buf;
116  /* previous libxml error handling state (saved by pg_xml_init) */
117  xmlStructuredErrorFunc saved_errfunc;
118  void *saved_errcxt;
119  /* previous libxml entity handler (saved by pg_xml_init) */
120  xmlExternalEntityLoader saved_entityfunc;
121 };
122 
123 static xmlParserInputPtr xmlPgEntityLoader(const char *URL, const char *ID,
124  xmlParserCtxtPtr ctxt);
125 static void xml_errsave(Node *escontext, PgXmlErrorContext *errcxt,
126  int sqlcode, const char *msg);
127 static void xml_errorHandler(void *data, xmlErrorPtr error);
128 static int errdetail_for_xml_code(int code);
129 static void chopStringInfoNewlines(StringInfo str);
130 static void appendStringInfoLineSeparator(StringInfo str);
131 
132 #ifdef USE_LIBXMLCONTEXT
133 
134 static MemoryContext LibxmlContext = NULL;
135 
136 static void xml_memory_init(void);
137 static void *xml_palloc(size_t size);
138 static void *xml_repalloc(void *ptr, size_t size);
139 static void xml_pfree(void *ptr);
140 static char *xml_pstrdup(const char *string);
141 #endif /* USE_LIBXMLCONTEXT */
142 
143 static xmlChar *xml_text2xmlChar(text *in);
144 static int parse_xml_decl(const xmlChar *str, size_t *lenp,
145  xmlChar **version, xmlChar **encoding, int *standalone);
146 static bool print_xml_decl(StringInfo buf, const xmlChar *version,
147  pg_enc encoding, int standalone);
148 static bool xml_doctype_in_content(const xmlChar *str);
149 static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg,
150  bool preserve_whitespace, int encoding,
151  XmlOptionType *parsed_xmloptiontype,
152  xmlNodePtr *parsed_nodes,
153  Node *escontext);
154 static text *xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt);
155 static int xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
156  ArrayBuildState *astate,
157  PgXmlErrorContext *xmlerrcxt);
158 static xmlChar *pg_xmlCharStrndup(const char *str, size_t len);
159 #endif /* USE_LIBXML */
160 
161 static void xmldata_root_element_start(StringInfo result, const char *eltname,
162  const char *xmlschema, const char *targetns,
163  bool top_level);
164 static void xmldata_root_element_end(StringInfo result, const char *eltname);
165 static StringInfo query_to_xml_internal(const char *query, char *tablename,
166  const char *xmlschema, bool nulls, bool tableforest,
167  const char *targetns, bool top_level);
168 static const char *map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid,
169  bool nulls, bool tableforest, const char *targetns);
170 static const char *map_sql_schema_to_xmlschema_types(Oid nspid,
171  List *relid_list, bool nulls,
172  bool tableforest, const char *targetns);
173 static const char *map_sql_catalog_to_xmlschema_types(List *nspid_list,
174  bool nulls, bool tableforest,
175  const char *targetns);
176 static const char *map_sql_type_to_xml_name(Oid typeoid, int typmod);
177 static const char *map_sql_typecoll_to_xmlschema_types(List *tupdesc_list);
178 static const char *map_sql_type_to_xmlschema_type(Oid typeoid, int typmod);
179 static void SPI_sql_row_to_xmlelement(uint64 rownum, StringInfo result,
180  char *tablename, bool nulls, bool tableforest,
181  const char *targetns, bool top_level);
182 
183 /* XMLTABLE support */
184 #ifdef USE_LIBXML
185 /* random number to identify XmlTableContext */
186 #define XMLTABLE_CONTEXT_MAGIC 46922182
187 typedef struct XmlTableBuilderData
188 {
189  int magic;
190  int natts;
191  long int row_count;
192  PgXmlErrorContext *xmlerrcxt;
193  xmlParserCtxtPtr ctxt;
194  xmlDocPtr doc;
195  xmlXPathContextPtr xpathcxt;
196  xmlXPathCompExprPtr xpathcomp;
197  xmlXPathObjectPtr xpathobj;
198  xmlXPathCompExprPtr *xpathscomp;
199 } XmlTableBuilderData;
200 #endif
201 
202 static void XmlTableInitOpaque(struct TableFuncScanState *state, int natts);
204 static void XmlTableSetNamespace(struct TableFuncScanState *state, const char *name,
205  const char *uri);
206 static void XmlTableSetRowFilter(struct TableFuncScanState *state, const char *path);
208  const char *path, int colnum);
209 static bool XmlTableFetchRow(struct TableFuncScanState *state);
210 static Datum XmlTableGetValue(struct TableFuncScanState *state, int colnum,
211  Oid typid, int32 typmod, bool *isnull);
212 static void XmlTableDestroyOpaque(struct TableFuncScanState *state);
213 
215 {
224 };
225 
226 #define NO_XML_SUPPORT() \
227  ereport(ERROR, \
228  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
229  errmsg("unsupported XML feature"), \
230  errdetail("This functionality requires the server to be built with libxml support.")))
231 
232 
233 /* from SQL/XML:2008 section 4.9 */
234 #define NAMESPACE_XSD "http://www.w3.org/2001/XMLSchema"
235 #define NAMESPACE_XSI "http://www.w3.org/2001/XMLSchema-instance"
236 #define NAMESPACE_SQLXML "http://standards.iso.org/iso/9075/2003/sqlxml"
237 
238 
239 #ifdef USE_LIBXML
240 
241 static int
242 xmlChar_to_encoding(const xmlChar *encoding_name)
243 {
244  int encoding = pg_char_to_encoding((const char *) encoding_name);
245 
246  if (encoding < 0)
247  ereport(ERROR,
248  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
249  errmsg("invalid encoding name \"%s\"",
250  (const char *) encoding_name)));
251  return encoding;
252 }
253 #endif
254 
255 
256 /*
257  * xml_in uses a plain C string to VARDATA conversion, so for the time being
258  * we use the conversion function for the text datatype.
259  *
260  * This is only acceptable so long as xmltype and text use the same
261  * representation.
262  */
263 Datum
265 {
266 #ifdef USE_LIBXML
267  char *s = PG_GETARG_CSTRING(0);
268  xmltype *vardata;
269  xmlDocPtr doc;
270 
271  /* Build the result object. */
272  vardata = (xmltype *) cstring_to_text(s);
273 
274  /*
275  * Parse the data to check if it is well-formed XML data.
276  *
277  * Note: we don't need to worry about whether a soft error is detected.
278  */
279  doc = xml_parse(vardata, xmloption, true, GetDatabaseEncoding(),
280  NULL, NULL, fcinfo->context);
281  if (doc != NULL)
282  xmlFreeDoc(doc);
283 
284  PG_RETURN_XML_P(vardata);
285 #else
286  NO_XML_SUPPORT();
287  return 0;
288 #endif
289 }
290 
291 
292 #define PG_XML_DEFAULT_VERSION "1.0"
293 
294 
295 /*
296  * xml_out_internal uses a plain VARDATA to C string conversion, so for the
297  * time being we use the conversion function for the text datatype.
298  *
299  * This is only acceptable so long as xmltype and text use the same
300  * representation.
301  */
302 static char *
303 xml_out_internal(xmltype *x, pg_enc target_encoding)
304 {
305  char *str = text_to_cstring((text *) x);
306 
307 #ifdef USE_LIBXML
308  size_t len = strlen(str);
309  xmlChar *version;
310  int standalone;
311  int res_code;
312 
313  if ((res_code = parse_xml_decl((xmlChar *) str,
314  &len, &version, NULL, &standalone)) == 0)
315  {
317 
319 
320  if (!print_xml_decl(&buf, version, target_encoding, standalone))
321  {
322  /*
323  * If we are not going to produce an XML declaration, eat a single
324  * newline in the original string to prevent empty first lines in
325  * the output.
326  */
327  if (*(str + len) == '\n')
328  len += 1;
329  }
331 
332  pfree(str);
333 
334  return buf.data;
335  }
336 
338  errcode(ERRCODE_INTERNAL_ERROR),
339  errmsg_internal("could not parse XML declaration in stored value"),
340  errdetail_for_xml_code(res_code));
341 #endif
342  return str;
343 }
344 
345 
346 Datum
348 {
349  xmltype *x = PG_GETARG_XML_P(0);
350 
351  /*
352  * xml_out removes the encoding property in all cases. This is because we
353  * cannot control from here whether the datum will be converted to a
354  * different client encoding, so we'd do more harm than good by including
355  * it.
356  */
358 }
359 
360 
361 Datum
363 {
364 #ifdef USE_LIBXML
366  xmltype *result;
367  char *str;
368  char *newstr;
369  int nbytes;
370  xmlDocPtr doc;
371  xmlChar *encodingStr = NULL;
372  int encoding;
373 
374  /*
375  * Read the data in raw format. We don't know yet what the encoding is, as
376  * that information is embedded in the xml declaration; so we have to
377  * parse that before converting to server encoding.
378  */
379  nbytes = buf->len - buf->cursor;
380  str = (char *) pq_getmsgbytes(buf, nbytes);
381 
382  /*
383  * We need a null-terminated string to pass to parse_xml_decl(). Rather
384  * than make a separate copy, make the temporary result one byte bigger
385  * than it needs to be.
386  */
387  result = palloc(nbytes + 1 + VARHDRSZ);
388  SET_VARSIZE(result, nbytes + VARHDRSZ);
389  memcpy(VARDATA(result), str, nbytes);
390  str = VARDATA(result);
391  str[nbytes] = '\0';
392 
393  parse_xml_decl((const xmlChar *) str, NULL, NULL, &encodingStr, NULL);
394 
395  /*
396  * If encoding wasn't explicitly specified in the XML header, treat it as
397  * UTF-8, as that's the default in XML. This is different from xml_in(),
398  * where the input has to go through the normal client to server encoding
399  * conversion.
400  */
401  encoding = encodingStr ? xmlChar_to_encoding(encodingStr) : PG_UTF8;
402 
403  /*
404  * Parse the data to check if it is well-formed XML data. Assume that
405  * xml_parse will throw ERROR if not.
406  */
407  doc = xml_parse(result, xmloption, true, encoding, NULL, NULL, NULL);
408  xmlFreeDoc(doc);
409 
410  /* Now that we know what we're dealing with, convert to server encoding */
411  newstr = pg_any_to_server(str, nbytes, encoding);
412 
413  if (newstr != str)
414  {
415  pfree(result);
416  result = (xmltype *) cstring_to_text(newstr);
417  pfree(newstr);
418  }
419 
420  PG_RETURN_XML_P(result);
421 #else
422  NO_XML_SUPPORT();
423  return 0;
424 #endif
425 }
426 
427 
428 Datum
430 {
431  xmltype *x = PG_GETARG_XML_P(0);
432  char *outval;
434 
435  /*
436  * xml_out_internal doesn't convert the encoding, it just prints the right
437  * declaration. pq_sendtext will do the conversion.
438  */
440 
442  pq_sendtext(&buf, outval, strlen(outval));
443  pfree(outval);
445 }
446 
447 
448 #ifdef USE_LIBXML
449 static void
451 {
453 }
454 #endif
455 
456 
457 static xmltype *
459 {
460  return (xmltype *) cstring_to_text_with_len(buf->data, buf->len);
461 }
462 
463 
464 static xmltype *
465 cstring_to_xmltype(const char *string)
466 {
467  return (xmltype *) cstring_to_text(string);
468 }
469 
470 
471 #ifdef USE_LIBXML
472 static xmltype *
473 xmlBuffer_to_xmltype(xmlBufferPtr buf)
474 {
475  return (xmltype *) cstring_to_text_with_len((const char *) xmlBufferContent(buf),
476  xmlBufferLength(buf));
477 }
478 #endif
479 
480 
481 Datum
483 {
484 #ifdef USE_LIBXML
485  text *arg = PG_GETARG_TEXT_PP(0);
486  char *argdata = VARDATA_ANY(arg);
487  int len = VARSIZE_ANY_EXHDR(arg);
489  int i;
490 
491  /* check for "--" in string or "-" at the end */
492  for (i = 1; i < len; i++)
493  {
494  if (argdata[i] == '-' && argdata[i - 1] == '-')
495  ereport(ERROR,
496  (errcode(ERRCODE_INVALID_XML_COMMENT),
497  errmsg("invalid XML comment")));
498  }
499  if (len > 0 && argdata[len - 1] == '-')
500  ereport(ERROR,
501  (errcode(ERRCODE_INVALID_XML_COMMENT),
502  errmsg("invalid XML comment")));
503 
505  appendStringInfoString(&buf, "<!--");
507  appendStringInfoString(&buf, "-->");
508 
510 #else
511  NO_XML_SUPPORT();
512  return 0;
513 #endif
514 }
515 
516 
517 Datum
519 {
520 #ifdef USE_LIBXML
521  text *arg = PG_GETARG_TEXT_PP(0);
522  text *result;
523  xmlChar *xmlbuf = NULL;
524 
525  xmlbuf = xmlEncodeSpecialChars(NULL, xml_text2xmlChar(arg));
526 
527  Assert(xmlbuf);
528 
529  result = cstring_to_text_with_len((const char *) xmlbuf, xmlStrlen(xmlbuf));
530  xmlFree(xmlbuf);
531  PG_RETURN_XML_P(result);
532 #else
533  NO_XML_SUPPORT();
534  return 0;
535 #endif /* not USE_LIBXML */
536 }
537 
538 
539 /*
540  * TODO: xmlconcat needs to merge the notations and unparsed entities
541  * of the argument values. Not very important in practice, though.
542  */
543 xmltype *
545 {
546 #ifdef USE_LIBXML
547  int global_standalone = 1;
548  xmlChar *global_version = NULL;
549  bool global_version_no_value = false;
551  ListCell *v;
552 
554  foreach(v, args)
555  {
557  size_t len;
558  xmlChar *version;
559  int standalone;
560  char *str;
561 
562  len = VARSIZE(x) - VARHDRSZ;
563  str = text_to_cstring((text *) x);
564 
565  parse_xml_decl((xmlChar *) str, &len, &version, NULL, &standalone);
566 
567  if (standalone == 0 && global_standalone == 1)
568  global_standalone = 0;
569  if (standalone < 0)
570  global_standalone = -1;
571 
572  if (!version)
573  global_version_no_value = true;
574  else if (!global_version)
575  global_version = version;
576  else if (xmlStrcmp(version, global_version) != 0)
577  global_version_no_value = true;
578 
580  pfree(str);
581  }
582 
583  if (!global_version_no_value || global_standalone >= 0)
584  {
585  StringInfoData buf2;
586 
587  initStringInfo(&buf2);
588 
589  print_xml_decl(&buf2,
590  (!global_version_no_value) ? global_version : NULL,
591  0,
592  global_standalone);
593 
594  appendBinaryStringInfo(&buf2, buf.data, buf.len);
595  buf = buf2;
596  }
597 
598  return stringinfo_to_xmltype(&buf);
599 #else
600  NO_XML_SUPPORT();
601  return NULL;
602 #endif
603 }
604 
605 
606 /*
607  * XMLAGG support
608  */
609 Datum
611 {
612  if (PG_ARGISNULL(0))
613  {
614  if (PG_ARGISNULL(1))
615  PG_RETURN_NULL();
616  else
618  }
619  else if (PG_ARGISNULL(1))
621  else
623  PG_GETARG_XML_P(1))));
624 }
625 
626 
627 Datum
629 {
631 
633 }
634 
635 
636 Datum
638 {
640 
641  /* It's actually binary compatible. */
643 }
644 
645 
646 text *
647 xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
648 {
649 #ifdef USE_LIBXML
650  text *volatile result;
651  xmlDocPtr doc;
652  XmlOptionType parsed_xmloptiontype;
653  xmlNodePtr content_nodes;
654  volatile xmlBufferPtr buf = NULL;
655  volatile xmlSaveCtxtPtr ctxt = NULL;
656  ErrorSaveContext escontext = {T_ErrorSaveContext};
657  PgXmlErrorContext *xmlerrcxt;
658 #endif
659 
660  if (xmloption_arg != XMLOPTION_DOCUMENT && !indent)
661  {
662  /*
663  * We don't actually need to do anything, so just return the
664  * binary-compatible input. For backwards-compatibility reasons,
665  * allow such cases to succeed even without USE_LIBXML.
666  */
667  return (text *) data;
668  }
669 
670 #ifdef USE_LIBXML
671  /* Parse the input according to the xmloption */
672  doc = xml_parse(data, xmloption_arg, true, GetDatabaseEncoding(),
673  &parsed_xmloptiontype, &content_nodes,
674  (Node *) &escontext);
675  if (doc == NULL || escontext.error_occurred)
676  {
677  if (doc)
678  xmlFreeDoc(doc);
679  /* A soft error must be failure to conform to XMLOPTION_DOCUMENT */
680  ereport(ERROR,
681  (errcode(ERRCODE_NOT_AN_XML_DOCUMENT),
682  errmsg("not an XML document")));
683  }
684 
685  /* If we weren't asked to indent, we're done. */
686  if (!indent)
687  {
688  xmlFreeDoc(doc);
689  return (text *) data;
690  }
691 
692  /* Otherwise, we gotta spin up some error handling. */
693  xmlerrcxt = pg_xml_init(PG_XML_STRICTNESS_ALL);
694 
695  PG_TRY();
696  {
697  size_t decl_len = 0;
698 
699  /* The serialized data will go into this buffer. */
700  buf = xmlBufferCreate();
701 
702  if (buf == NULL || xmlerrcxt->err_occurred)
703  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
704  "could not allocate xmlBuffer");
705 
706  /* Detect whether there's an XML declaration */
707  parse_xml_decl(xml_text2xmlChar(data), &decl_len, NULL, NULL, NULL);
708 
709  /*
710  * Emit declaration only if the input had one. Note: some versions of
711  * xmlSaveToBuffer leak memory if a non-null encoding argument is
712  * passed, so don't do that. We don't want any encoding conversion
713  * anyway.
714  */
715  if (decl_len == 0)
716  ctxt = xmlSaveToBuffer(buf, NULL,
717  XML_SAVE_NO_DECL | XML_SAVE_FORMAT);
718  else
719  ctxt = xmlSaveToBuffer(buf, NULL,
720  XML_SAVE_FORMAT);
721 
722  if (ctxt == NULL || xmlerrcxt->err_occurred)
723  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
724  "could not allocate xmlSaveCtxt");
725 
726  if (parsed_xmloptiontype == XMLOPTION_DOCUMENT)
727  {
728  /* If it's a document, saving is easy. */
729  if (xmlSaveDoc(ctxt, doc) == -1 || xmlerrcxt->err_occurred)
730  xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
731  "could not save document to xmlBuffer");
732  }
733  else if (content_nodes != NULL)
734  {
735  /*
736  * Deal with the case where we have non-singly-rooted XML.
737  * libxml's dump functions don't work well for that without help.
738  * We build a fake root node that serves as a container for the
739  * content nodes, and then iterate over the nodes.
740  */
741  xmlNodePtr root;
742  xmlNodePtr newline;
743 
744  root = xmlNewNode(NULL, (const xmlChar *) "content-root");
745  if (root == NULL || xmlerrcxt->err_occurred)
746  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
747  "could not allocate xml node");
748 
749  /* This attaches root to doc, so we need not free it separately. */
750  xmlDocSetRootElement(doc, root);
751  xmlAddChild(root, content_nodes);
752 
753  /*
754  * We use this node to insert newlines in the dump. Note: in at
755  * least some libxml versions, xmlNewDocText would not attach the
756  * node to the document even if we passed it. Therefore, manage
757  * freeing of this node manually, and pass NULL here to make sure
758  * there's not a dangling link.
759  */
760  newline = xmlNewDocText(NULL, (const xmlChar *) "\n");
761  if (newline == NULL || xmlerrcxt->err_occurred)
762  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
763  "could not allocate xml node");
764 
765  for (xmlNodePtr node = root->children; node; node = node->next)
766  {
767  /* insert newlines between nodes */
768  if (node->type != XML_TEXT_NODE && node->prev != NULL)
769  {
770  if (xmlSaveTree(ctxt, newline) == -1 || xmlerrcxt->err_occurred)
771  {
772  xmlFreeNode(newline);
773  xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
774  "could not save newline to xmlBuffer");
775  }
776  }
777 
778  if (xmlSaveTree(ctxt, node) == -1 || xmlerrcxt->err_occurred)
779  {
780  xmlFreeNode(newline);
781  xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
782  "could not save content to xmlBuffer");
783  }
784  }
785 
786  xmlFreeNode(newline);
787  }
788 
789  if (xmlSaveClose(ctxt) == -1 || xmlerrcxt->err_occurred)
790  {
791  ctxt = NULL; /* don't try to close it again */
792  xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
793  "could not close xmlSaveCtxtPtr");
794  }
795 
796  result = (text *) xmlBuffer_to_xmltype(buf);
797  }
798  PG_CATCH();
799  {
800  if (ctxt)
801  xmlSaveClose(ctxt);
802  if (buf)
803  xmlBufferFree(buf);
804  if (doc)
805  xmlFreeDoc(doc);
806 
807  pg_xml_done(xmlerrcxt, true);
808 
809  PG_RE_THROW();
810  }
811  PG_END_TRY();
812 
813  xmlBufferFree(buf);
814  xmlFreeDoc(doc);
815 
816  pg_xml_done(xmlerrcxt, false);
817 
818  return result;
819 #else
820  NO_XML_SUPPORT();
821  return NULL;
822 #endif
823 }
824 
825 
826 xmltype *
828  Datum *named_argvalue, bool *named_argnull,
829  Datum *argvalue, bool *argnull)
830 {
831 #ifdef USE_LIBXML
832  xmltype *result;
833  List *named_arg_strings;
834  List *arg_strings;
835  int i;
836  ListCell *arg;
837  ListCell *narg;
838  PgXmlErrorContext *xmlerrcxt;
839  volatile xmlBufferPtr buf = NULL;
840  volatile xmlTextWriterPtr writer = NULL;
841 
842  /*
843  * All arguments are already evaluated, and their values are passed in the
844  * named_argvalue/named_argnull or argvalue/argnull arrays. This avoids
845  * issues if one of the arguments involves a call to some other function
846  * or subsystem that wants to use libxml on its own terms. We examine the
847  * original XmlExpr to identify the numbers and types of the arguments.
848  */
849  named_arg_strings = NIL;
850  i = 0;
851  foreach(arg, xexpr->named_args)
852  {
853  Expr *e = (Expr *) lfirst(arg);
854  char *str;
855 
856  if (named_argnull[i])
857  str = NULL;
858  else
859  str = map_sql_value_to_xml_value(named_argvalue[i],
860  exprType((Node *) e),
861  false);
862  named_arg_strings = lappend(named_arg_strings, str);
863  i++;
864  }
865 
866  arg_strings = NIL;
867  i = 0;
868  foreach(arg, xexpr->args)
869  {
870  Expr *e = (Expr *) lfirst(arg);
871  char *str;
872 
873  /* here we can just forget NULL elements immediately */
874  if (!argnull[i])
875  {
876  str = map_sql_value_to_xml_value(argvalue[i],
877  exprType((Node *) e),
878  true);
879  arg_strings = lappend(arg_strings, str);
880  }
881  i++;
882  }
883 
884  xmlerrcxt = pg_xml_init(PG_XML_STRICTNESS_ALL);
885 
886  PG_TRY();
887  {
888  buf = xmlBufferCreate();
889  if (buf == NULL || xmlerrcxt->err_occurred)
890  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
891  "could not allocate xmlBuffer");
892  writer = xmlNewTextWriterMemory(buf, 0);
893  if (writer == NULL || xmlerrcxt->err_occurred)
894  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
895  "could not allocate xmlTextWriter");
896 
897  xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name);
898 
899  forboth(arg, named_arg_strings, narg, xexpr->arg_names)
900  {
901  char *str = (char *) lfirst(arg);
902  char *argname = strVal(lfirst(narg));
903 
904  if (str)
905  xmlTextWriterWriteAttribute(writer,
906  (xmlChar *) argname,
907  (xmlChar *) str);
908  }
909 
910  foreach(arg, arg_strings)
911  {
912  char *str = (char *) lfirst(arg);
913 
914  xmlTextWriterWriteRaw(writer, (xmlChar *) str);
915  }
916 
917  xmlTextWriterEndElement(writer);
918 
919  /* we MUST do this now to flush data out to the buffer ... */
920  xmlFreeTextWriter(writer);
921  writer = NULL;
922 
923  result = xmlBuffer_to_xmltype(buf);
924  }
925  PG_CATCH();
926  {
927  if (writer)
928  xmlFreeTextWriter(writer);
929  if (buf)
930  xmlBufferFree(buf);
931 
932  pg_xml_done(xmlerrcxt, true);
933 
934  PG_RE_THROW();
935  }
936  PG_END_TRY();
937 
938  xmlBufferFree(buf);
939 
940  pg_xml_done(xmlerrcxt, false);
941 
942  return result;
943 #else
944  NO_XML_SUPPORT();
945  return NULL;
946 #endif
947 }
948 
949 
950 xmltype *
951 xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace)
952 {
953 #ifdef USE_LIBXML
954  xmlDocPtr doc;
955 
956  doc = xml_parse(data, xmloption_arg, preserve_whitespace,
957  GetDatabaseEncoding(), NULL, NULL, NULL);
958  xmlFreeDoc(doc);
959 
960  return (xmltype *) data;
961 #else
962  NO_XML_SUPPORT();
963  return NULL;
964 #endif
965 }
966 
967 
968 xmltype *
969 xmlpi(const char *target, text *arg, bool arg_is_null, bool *result_is_null)
970 {
971 #ifdef USE_LIBXML
972  xmltype *result;
974 
975  if (pg_strcasecmp(target, "xml") == 0)
976  ereport(ERROR,
977  (errcode(ERRCODE_SYNTAX_ERROR), /* really */
978  errmsg("invalid XML processing instruction"),
979  errdetail("XML processing instruction target name cannot be \"%s\".", target)));
980 
981  /*
982  * Following the SQL standard, the null check comes after the syntax check
983  * above.
984  */
985  *result_is_null = arg_is_null;
986  if (*result_is_null)
987  return NULL;
988 
990 
991  appendStringInfo(&buf, "<?%s", target);
992 
993  if (arg != NULL)
994  {
995  char *string;
996 
997  string = text_to_cstring(arg);
998  if (strstr(string, "?>") != NULL)
999  ereport(ERROR,
1000  (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
1001  errmsg("invalid XML processing instruction"),
1002  errdetail("XML processing instruction cannot contain \"?>\".")));
1003 
1004  appendStringInfoChar(&buf, ' ');
1005  appendStringInfoString(&buf, string + strspn(string, " "));
1006  pfree(string);
1007  }
1008  appendStringInfoString(&buf, "?>");
1009 
1010  result = stringinfo_to_xmltype(&buf);
1011  pfree(buf.data);
1012  return result;
1013 #else
1014  NO_XML_SUPPORT();
1015  return NULL;
1016 #endif
1017 }
1018 
1019 
1020 xmltype *
1021 xmlroot(xmltype *data, text *version, int standalone)
1022 {
1023 #ifdef USE_LIBXML
1024  char *str;
1025  size_t len;
1026  xmlChar *orig_version;
1027  int orig_standalone;
1029 
1030  len = VARSIZE(data) - VARHDRSZ;
1031  str = text_to_cstring((text *) data);
1032 
1033  parse_xml_decl((xmlChar *) str, &len, &orig_version, NULL, &orig_standalone);
1034 
1035  if (version)
1036  orig_version = xml_text2xmlChar(version);
1037  else
1038  orig_version = NULL;
1039 
1040  switch (standalone)
1041  {
1042  case XML_STANDALONE_YES:
1043  orig_standalone = 1;
1044  break;
1045  case XML_STANDALONE_NO:
1046  orig_standalone = 0;
1047  break;
1049  orig_standalone = -1;
1050  break;
1052  /* leave original value */
1053  break;
1054  }
1055 
1056  initStringInfo(&buf);
1057  print_xml_decl(&buf, orig_version, 0, orig_standalone);
1059 
1060  return stringinfo_to_xmltype(&buf);
1061 #else
1062  NO_XML_SUPPORT();
1063  return NULL;
1064 #endif
1065 }
1066 
1067 
1068 /*
1069  * Validate document (given as string) against DTD (given as external link)
1070  *
1071  * This has been removed because it is a security hole: unprivileged users
1072  * should not be able to use Postgres to fetch arbitrary external files,
1073  * which unfortunately is exactly what libxml is willing to do with the DTD
1074  * parameter.
1075  */
1076 Datum
1078 {
1079  ereport(ERROR,
1080  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1081  errmsg("xmlvalidate is not implemented")));
1082  return 0;
1083 }
1084 
1085 
1086 bool
1088 {
1089 #ifdef USE_LIBXML
1090  xmlDocPtr doc;
1091  ErrorSaveContext escontext = {T_ErrorSaveContext};
1092 
1093  /*
1094  * We'll report "true" if no soft error is reported by xml_parse().
1095  */
1096  doc = xml_parse((text *) arg, XMLOPTION_DOCUMENT, true,
1097  GetDatabaseEncoding(), NULL, NULL, (Node *) &escontext);
1098  if (doc)
1099  xmlFreeDoc(doc);
1100 
1101  return !escontext.error_occurred;
1102 #else /* not USE_LIBXML */
1103  NO_XML_SUPPORT();
1104  return false;
1105 #endif /* not USE_LIBXML */
1106 }
1107 
1108 
1109 #ifdef USE_LIBXML
1110 
1111 /*
1112  * pg_xml_init_library --- set up for use of libxml
1113  *
1114  * This should be called by each function that is about to use libxml
1115  * facilities but doesn't require error handling. It initializes libxml
1116  * and verifies compatibility with the loaded libxml version. These are
1117  * once-per-session activities.
1118  *
1119  * TODO: xmlChar is utf8-char, make proper tuning (initdb with enc!=utf8 and
1120  * check)
1121  */
1122 void
1123 pg_xml_init_library(void)
1124 {
1125  static bool first_time = true;
1126 
1127  if (first_time)
1128  {
1129  /* Stuff we need do only once per session */
1130 
1131  /*
1132  * Currently, we have no pure UTF-8 support for internals -- check if
1133  * we can work.
1134  */
1135  if (sizeof(char) != sizeof(xmlChar))
1136  ereport(ERROR,
1137  (errmsg("could not initialize XML library"),
1138  errdetail("libxml2 has incompatible char type: sizeof(char)=%zu, sizeof(xmlChar)=%zu.",
1139  sizeof(char), sizeof(xmlChar))));
1140 
1141 #ifdef USE_LIBXMLCONTEXT
1142  /* Set up libxml's memory allocation our way */
1143  xml_memory_init();
1144 #endif
1145 
1146  /* Check library compatibility */
1147  LIBXML_TEST_VERSION;
1148 
1149  first_time = false;
1150  }
1151 }
1152 
1153 /*
1154  * pg_xml_init --- set up for use of libxml and register an error handler
1155  *
1156  * This should be called by each function that is about to use libxml
1157  * facilities and requires error handling. It initializes libxml with
1158  * pg_xml_init_library() and establishes our libxml error handler.
1159  *
1160  * strictness determines which errors are reported and which are ignored.
1161  *
1162  * Calls to this function MUST be followed by a PG_TRY block that guarantees
1163  * that pg_xml_done() is called during either normal or error exit.
1164  *
1165  * This is exported for use by contrib/xml2, as well as other code that might
1166  * wish to share use of this module's libxml error handler.
1167  */
1169 pg_xml_init(PgXmlStrictness strictness)
1170 {
1171  PgXmlErrorContext *errcxt;
1172  void *new_errcxt;
1173 
1174  /* Do one-time setup if needed */
1176 
1177  /* Create error handling context structure */
1178  errcxt = (PgXmlErrorContext *) palloc(sizeof(PgXmlErrorContext));
1179  errcxt->magic = ERRCXT_MAGIC;
1180  errcxt->strictness = strictness;
1181  errcxt->err_occurred = false;
1182  initStringInfo(&errcxt->err_buf);
1183 
1184  /*
1185  * Save original error handler and install ours. libxml originally didn't
1186  * distinguish between the contexts for generic and for structured error
1187  * handlers. If we're using an old libxml version, we must thus save the
1188  * generic error context, even though we're using a structured error
1189  * handler.
1190  */
1191  errcxt->saved_errfunc = xmlStructuredError;
1192 
1193 #ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
1194  errcxt->saved_errcxt = xmlStructuredErrorContext;
1195 #else
1196  errcxt->saved_errcxt = xmlGenericErrorContext;
1197 #endif
1198 
1199  xmlSetStructuredErrorFunc((void *) errcxt, xml_errorHandler);
1200 
1201  /*
1202  * Verify that xmlSetStructuredErrorFunc set the context variable we
1203  * expected it to. If not, the error context pointer we just saved is not
1204  * the correct thing to restore, and since that leaves us without a way to
1205  * restore the context in pg_xml_done, we must fail.
1206  *
1207  * The only known situation in which this test fails is if we compile with
1208  * headers from a libxml2 that doesn't track the structured error context
1209  * separately (< 2.7.4), but at runtime use a version that does, or vice
1210  * versa. The libxml2 authors did not treat that change as constituting
1211  * an ABI break, so the LIBXML_TEST_VERSION test in pg_xml_init_library
1212  * fails to protect us from this.
1213  */
1214 
1215 #ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
1216  new_errcxt = xmlStructuredErrorContext;
1217 #else
1218  new_errcxt = xmlGenericErrorContext;
1219 #endif
1220 
1221  if (new_errcxt != (void *) errcxt)
1222  ereport(ERROR,
1223  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1224  errmsg("could not set up XML error handler"),
1225  errhint("This probably indicates that the version of libxml2"
1226  " being used is not compatible with the libxml2"
1227  " header files that PostgreSQL was built with.")));
1228 
1229  /*
1230  * Also, install an entity loader to prevent unwanted fetches of external
1231  * files and URLs.
1232  */
1233  errcxt->saved_entityfunc = xmlGetExternalEntityLoader();
1234  xmlSetExternalEntityLoader(xmlPgEntityLoader);
1235 
1236  return errcxt;
1237 }
1238 
1239 
1240 /*
1241  * pg_xml_done --- restore previous libxml error handling
1242  *
1243  * Resets libxml's global error-handling state to what it was before
1244  * pg_xml_init() was called.
1245  *
1246  * This routine verifies that all pending errors have been dealt with
1247  * (in assert-enabled builds, anyway).
1248  */
1249 void
1250 pg_xml_done(PgXmlErrorContext *errcxt, bool isError)
1251 {
1252  void *cur_errcxt;
1253 
1254  /* An assert seems like enough protection here */
1255  Assert(errcxt->magic == ERRCXT_MAGIC);
1256 
1257  /*
1258  * In a normal exit, there should be no un-handled libxml errors. But we
1259  * shouldn't try to enforce this during error recovery, since the longjmp
1260  * could have been thrown before xml_ereport had a chance to run.
1261  */
1262  Assert(!errcxt->err_occurred || isError);
1263 
1264  /*
1265  * Check that libxml's global state is correct, warn if not. This is a
1266  * real test and not an Assert because it has a higher probability of
1267  * happening.
1268  */
1269 #ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
1270  cur_errcxt = xmlStructuredErrorContext;
1271 #else
1272  cur_errcxt = xmlGenericErrorContext;
1273 #endif
1274 
1275  if (cur_errcxt != (void *) errcxt)
1276  elog(WARNING, "libxml error handling state is out of sync with xml.c");
1277 
1278  /* Restore the saved handlers */
1279  xmlSetStructuredErrorFunc(errcxt->saved_errcxt, errcxt->saved_errfunc);
1280  xmlSetExternalEntityLoader(errcxt->saved_entityfunc);
1281 
1282  /*
1283  * Mark the struct as invalid, just in case somebody somehow manages to
1284  * call xml_errorHandler or xml_ereport with it.
1285  */
1286  errcxt->magic = 0;
1287 
1288  /* Release memory */
1289  pfree(errcxt->err_buf.data);
1290  pfree(errcxt);
1291 }
1292 
1293 
1294 /*
1295  * pg_xml_error_occurred() --- test the error flag
1296  */
1297 bool
1299 {
1300  return errcxt->err_occurred;
1301 }
1302 
1303 
1304 /*
1305  * SQL/XML allows storing "XML documents" or "XML content". "XML
1306  * documents" are specified by the XML specification and are parsed
1307  * easily by libxml. "XML content" is specified by SQL/XML as the
1308  * production "XMLDecl? content". But libxml can only parse the
1309  * "content" part, so we have to parse the XML declaration ourselves
1310  * to complete this.
1311  */
1312 
1313 #define CHECK_XML_SPACE(p) \
1314  do { \
1315  if (!xmlIsBlank_ch(*(p))) \
1316  return XML_ERR_SPACE_REQUIRED; \
1317  } while (0)
1318 
1319 #define SKIP_XML_SPACE(p) \
1320  while (xmlIsBlank_ch(*(p))) (p)++
1321 
1322 /* Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender */
1323 /* Beware of multiple evaluations of argument! */
1324 #define PG_XMLISNAMECHAR(c) \
1325  (xmlIsBaseChar_ch(c) || xmlIsIdeographicQ(c) \
1326  || xmlIsDigit_ch(c) \
1327  || c == '.' || c == '-' || c == '_' || c == ':' \
1328  || xmlIsCombiningQ(c) \
1329  || xmlIsExtender_ch(c))
1330 
1331 /* pnstrdup, but deal with xmlChar not char; len is measured in xmlChars */
1332 static xmlChar *
1333 xml_pnstrdup(const xmlChar *str, size_t len)
1334 {
1335  xmlChar *result;
1336 
1337  result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));
1338  memcpy(result, str, len * sizeof(xmlChar));
1339  result[len] = 0;
1340  return result;
1341 }
1342 
1343 /* Ditto, except input is char* */
1344 static xmlChar *
1345 pg_xmlCharStrndup(const char *str, size_t len)
1346 {
1347  xmlChar *result;
1348 
1349  result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));
1350  memcpy(result, str, len);
1351  result[len] = '\0';
1352 
1353  return result;
1354 }
1355 
1356 /*
1357  * Copy xmlChar string to PostgreSQL-owned memory, freeing the input.
1358  *
1359  * The input xmlChar is freed regardless of success of the copy.
1360  */
1361 static char *
1362 xml_pstrdup_and_free(xmlChar *str)
1363 {
1364  char *result;
1365 
1366  if (str)
1367  {
1368  PG_TRY();
1369  {
1370  result = pstrdup((char *) str);
1371  }
1372  PG_FINALLY();
1373  {
1374  xmlFree(str);
1375  }
1376  PG_END_TRY();
1377  }
1378  else
1379  result = NULL;
1380 
1381  return result;
1382 }
1383 
1384 /*
1385  * str is the null-terminated input string. Remaining arguments are
1386  * output arguments; each can be NULL if value is not wanted.
1387  * version and encoding are returned as locally-palloc'd strings.
1388  * Result is 0 if OK, an error code if not.
1389  */
1390 static int
1391 parse_xml_decl(const xmlChar *str, size_t *lenp,
1392  xmlChar **version, xmlChar **encoding, int *standalone)
1393 {
1394  const xmlChar *p;
1395  const xmlChar *save_p;
1396  size_t len;
1397  int utf8char;
1398  int utf8len;
1399 
1400  /*
1401  * Only initialize libxml. We don't need error handling here, but we do
1402  * need to make sure libxml is initialized before calling any of its
1403  * functions. Note that this is safe (and a no-op) if caller has already
1404  * done pg_xml_init().
1405  */
1407 
1408  /* Initialize output arguments to "not present" */
1409  if (version)
1410  *version = NULL;
1411  if (encoding)
1412  *encoding = NULL;
1413  if (standalone)
1414  *standalone = -1;
1415 
1416  p = str;
1417 
1418  if (xmlStrncmp(p, (xmlChar *) "<?xml", 5) != 0)
1419  goto finished;
1420 
1421  /*
1422  * If next char is a name char, it's a PI like <?xml-stylesheet ...?>
1423  * rather than an XMLDecl, so we have done what we came to do and found no
1424  * XMLDecl.
1425  *
1426  * We need an input length value for xmlGetUTF8Char, but there's no need
1427  * to count the whole document size, so use strnlen not strlen.
1428  */
1429  utf8len = strnlen((const char *) (p + 5), MAX_MULTIBYTE_CHAR_LEN);
1430  utf8char = xmlGetUTF8Char(p + 5, &utf8len);
1431  if (PG_XMLISNAMECHAR(utf8char))
1432  goto finished;
1433 
1434  p += 5;
1435 
1436  /* version */
1437  CHECK_XML_SPACE(p);
1438  SKIP_XML_SPACE(p);
1439  if (xmlStrncmp(p, (xmlChar *) "version", 7) != 0)
1440  return XML_ERR_VERSION_MISSING;
1441  p += 7;
1442  SKIP_XML_SPACE(p);
1443  if (*p != '=')
1444  return XML_ERR_VERSION_MISSING;
1445  p += 1;
1446  SKIP_XML_SPACE(p);
1447 
1448  if (*p == '\'' || *p == '"')
1449  {
1450  const xmlChar *q;
1451 
1452  q = xmlStrchr(p + 1, *p);
1453  if (!q)
1454  return XML_ERR_VERSION_MISSING;
1455 
1456  if (version)
1457  *version = xml_pnstrdup(p + 1, q - p - 1);
1458  p = q + 1;
1459  }
1460  else
1461  return XML_ERR_VERSION_MISSING;
1462 
1463  /* encoding */
1464  save_p = p;
1465  SKIP_XML_SPACE(p);
1466  if (xmlStrncmp(p, (xmlChar *) "encoding", 8) == 0)
1467  {
1468  CHECK_XML_SPACE(save_p);
1469  p += 8;
1470  SKIP_XML_SPACE(p);
1471  if (*p != '=')
1472  return XML_ERR_MISSING_ENCODING;
1473  p += 1;
1474  SKIP_XML_SPACE(p);
1475 
1476  if (*p == '\'' || *p == '"')
1477  {
1478  const xmlChar *q;
1479 
1480  q = xmlStrchr(p + 1, *p);
1481  if (!q)
1482  return XML_ERR_MISSING_ENCODING;
1483 
1484  if (encoding)
1485  *encoding = xml_pnstrdup(p + 1, q - p - 1);
1486  p = q + 1;
1487  }
1488  else
1489  return XML_ERR_MISSING_ENCODING;
1490  }
1491  else
1492  {
1493  p = save_p;
1494  }
1495 
1496  /* standalone */
1497  save_p = p;
1498  SKIP_XML_SPACE(p);
1499  if (xmlStrncmp(p, (xmlChar *) "standalone", 10) == 0)
1500  {
1501  CHECK_XML_SPACE(save_p);
1502  p += 10;
1503  SKIP_XML_SPACE(p);
1504  if (*p != '=')
1505  return XML_ERR_STANDALONE_VALUE;
1506  p += 1;
1507  SKIP_XML_SPACE(p);
1508  if (xmlStrncmp(p, (xmlChar *) "'yes'", 5) == 0 ||
1509  xmlStrncmp(p, (xmlChar *) "\"yes\"", 5) == 0)
1510  {
1511  if (standalone)
1512  *standalone = 1;
1513  p += 5;
1514  }
1515  else if (xmlStrncmp(p, (xmlChar *) "'no'", 4) == 0 ||
1516  xmlStrncmp(p, (xmlChar *) "\"no\"", 4) == 0)
1517  {
1518  if (standalone)
1519  *standalone = 0;
1520  p += 4;
1521  }
1522  else
1523  return XML_ERR_STANDALONE_VALUE;
1524  }
1525  else
1526  {
1527  p = save_p;
1528  }
1529 
1530  SKIP_XML_SPACE(p);
1531  if (xmlStrncmp(p, (xmlChar *) "?>", 2) != 0)
1532  return XML_ERR_XMLDECL_NOT_FINISHED;
1533  p += 2;
1534 
1535 finished:
1536  len = p - str;
1537 
1538  for (p = str; p < str + len; p++)
1539  if (*p > 127)
1540  return XML_ERR_INVALID_CHAR;
1541 
1542  if (lenp)
1543  *lenp = len;
1544 
1545  return XML_ERR_OK;
1546 }
1547 
1548 
1549 /*
1550  * Write an XML declaration. On output, we adjust the XML declaration
1551  * as follows. (These rules are the moral equivalent of the clause
1552  * "Serialization of an XML value" in the SQL standard.)
1553  *
1554  * We try to avoid generating an XML declaration if possible. This is
1555  * so that you don't get trivial things like xml '<foo/>' resulting in
1556  * '<?xml version="1.0"?><foo/>', which would surely be annoying. We
1557  * must provide a declaration if the standalone property is specified
1558  * or if we include an encoding declaration. If we have a
1559  * declaration, we must specify a version (XML requires this).
1560  * Otherwise we only make a declaration if the version is not "1.0",
1561  * which is the default version specified in SQL:2003.
1562  */
1563 static bool
1564 print_xml_decl(StringInfo buf, const xmlChar *version,
1565  pg_enc encoding, int standalone)
1566 {
1567  if ((version && strcmp((const char *) version, PG_XML_DEFAULT_VERSION) != 0)
1568  || (encoding && encoding != PG_UTF8)
1569  || standalone != -1)
1570  {
1571  appendStringInfoString(buf, "<?xml");
1572 
1573  if (version)
1574  appendStringInfo(buf, " version=\"%s\"", version);
1575  else
1576  appendStringInfo(buf, " version=\"%s\"", PG_XML_DEFAULT_VERSION);
1577 
1578  if (encoding && encoding != PG_UTF8)
1579  {
1580  /*
1581  * XXX might be useful to convert this to IANA names (ISO-8859-1
1582  * instead of LATIN1 etc.); needs field experience
1583  */
1584  appendStringInfo(buf, " encoding=\"%s\"",
1586  }
1587 
1588  if (standalone == 1)
1589  appendStringInfoString(buf, " standalone=\"yes\"");
1590  else if (standalone == 0)
1591  appendStringInfoString(buf, " standalone=\"no\"");
1592  appendStringInfoString(buf, "?>");
1593 
1594  return true;
1595  }
1596  else
1597  return false;
1598 }
1599 
1600 /*
1601  * Test whether an input that is to be parsed as CONTENT contains a DTD.
1602  *
1603  * The SQL/XML:2003 definition of CONTENT ("XMLDecl? content") is not
1604  * satisfied by a document with a DTD, which is a bit of a wart, as it means
1605  * the CONTENT type is not a proper superset of DOCUMENT. SQL/XML:2006 and
1606  * later fix that, by redefining content with reference to the "more
1607  * permissive" Document Node of the XQuery/XPath Data Model, such that any
1608  * DOCUMENT value is indeed also a CONTENT value. That definition is more
1609  * useful, as CONTENT becomes usable for parsing input of unknown form (think
1610  * pg_restore).
1611  *
1612  * As used below in parse_xml when parsing for CONTENT, libxml does not give
1613  * us the 2006+ behavior, but only the 2003; it will choke if the input has
1614  * a DTD. But we can provide the 2006+ definition of CONTENT easily enough,
1615  * by detecting this case first and simply doing the parse as DOCUMENT.
1616  *
1617  * A DTD can be found arbitrarily far in, but that would be a contrived case;
1618  * it will ordinarily start within a few dozen characters. The only things
1619  * that can precede it are an XMLDecl (here, the caller will have called
1620  * parse_xml_decl already), whitespace, comments, and processing instructions.
1621  * This function need only return true if it sees a valid sequence of such
1622  * things leading to <!DOCTYPE. It can simply return false in any other
1623  * cases, including malformed input; that will mean the input gets parsed as
1624  * CONTENT as originally planned, with libxml reporting any errors.
1625  *
1626  * This is only to be called from xml_parse, when pg_xml_init has already
1627  * been called. The input is already in UTF8 encoding.
1628  */
1629 static bool
1630 xml_doctype_in_content(const xmlChar *str)
1631 {
1632  const xmlChar *p = str;
1633 
1634  for (;;)
1635  {
1636  const xmlChar *e;
1637 
1638  SKIP_XML_SPACE(p);
1639  if (*p != '<')
1640  return false;
1641  p++;
1642 
1643  if (*p == '!')
1644  {
1645  p++;
1646 
1647  /* if we see <!DOCTYPE, we can return true */
1648  if (xmlStrncmp(p, (xmlChar *) "DOCTYPE", 7) == 0)
1649  return true;
1650 
1651  /* otherwise, if it's not a comment, fail */
1652  if (xmlStrncmp(p, (xmlChar *) "--", 2) != 0)
1653  return false;
1654  /* find end of comment: find -- and a > must follow */
1655  p = xmlStrstr(p + 2, (xmlChar *) "--");
1656  if (!p || p[2] != '>')
1657  return false;
1658  /* advance over comment, and keep scanning */
1659  p += 3;
1660  continue;
1661  }
1662 
1663  /* otherwise, if it's not a PI <?target something?>, fail */
1664  if (*p != '?')
1665  return false;
1666  p++;
1667 
1668  /* find end of PI (the string ?> is forbidden within a PI) */
1669  e = xmlStrstr(p, (xmlChar *) "?>");
1670  if (!e)
1671  return false;
1672 
1673  /* advance over PI, keep scanning */
1674  p = e + 2;
1675  }
1676 }
1677 
1678 
1679 /*
1680  * Convert a text object to XML internal representation
1681  *
1682  * data is the source data (must not be toasted!), encoding is its encoding,
1683  * and xmloption_arg and preserve_whitespace are options for the
1684  * transformation.
1685  *
1686  * If parsed_xmloptiontype isn't NULL, *parsed_xmloptiontype is set to the
1687  * XmlOptionType actually used to parse the input (typically the same as
1688  * xmloption_arg, but a DOCTYPE node in the input can force DOCUMENT mode).
1689  *
1690  * If parsed_nodes isn't NULL and the input is not an XML document, the list
1691  * of parsed nodes from the xmlParseBalancedChunkMemory call will be returned
1692  * to *parsed_nodes.
1693  *
1694  * Errors normally result in ereport(ERROR), but if escontext is an
1695  * ErrorSaveContext, then "safe" errors are reported there instead, and the
1696  * caller must check SOFT_ERROR_OCCURRED() to see whether that happened.
1697  *
1698  * Note: it is caller's responsibility to xmlFreeDoc() the result,
1699  * else a permanent memory leak will ensue! But note the result could
1700  * be NULL after a soft error.
1701  *
1702  * TODO maybe libxml2's xmlreader is better? (do not construct DOM,
1703  * yet do not use SAX - see xmlreader.c)
1704  */
1705 static xmlDocPtr
1706 xml_parse(text *data, XmlOptionType xmloption_arg,
1707  bool preserve_whitespace, int encoding,
1708  XmlOptionType *parsed_xmloptiontype, xmlNodePtr *parsed_nodes,
1709  Node *escontext)
1710 {
1711  int32 len;
1712  xmlChar *string;
1713  xmlChar *utf8string;
1714  PgXmlErrorContext *xmlerrcxt;
1715  volatile xmlParserCtxtPtr ctxt = NULL;
1716  volatile xmlDocPtr doc = NULL;
1717 
1718  /*
1719  * This step looks annoyingly redundant, but we must do it to have a
1720  * null-terminated string in case encoding conversion isn't required.
1721  */
1722  len = VARSIZE_ANY_EXHDR(data); /* will be useful later */
1723  string = xml_text2xmlChar(data);
1724 
1725  /*
1726  * If the data isn't UTF8, we must translate before giving it to libxml.
1727  *
1728  * XXX ideally, we'd catch any encoding conversion failure and return a
1729  * soft error. However, failure to convert to UTF8 should be pretty darn
1730  * rare, so for now this is left undone.
1731  */
1732  utf8string = pg_do_encoding_conversion(string,
1733  len,
1734  encoding,
1735  PG_UTF8);
1736 
1737  /* Start up libxml and its parser */
1739 
1740  /* Use a TRY block to ensure we clean up correctly */
1741  PG_TRY();
1742  {
1743  bool parse_as_document = false;
1744  int res_code;
1745  size_t count = 0;
1746  xmlChar *version = NULL;
1747  int standalone = 0;
1748 
1749  /* Any errors here are reported as hard ereport's */
1750  xmlInitParser();
1751 
1752  ctxt = xmlNewParserCtxt();
1753  if (ctxt == NULL || xmlerrcxt->err_occurred)
1754  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
1755  "could not allocate parser context");
1756 
1757  /* Decide whether to parse as document or content */
1758  if (xmloption_arg == XMLOPTION_DOCUMENT)
1759  parse_as_document = true;
1760  else
1761  {
1762  /* Parse and skip over the XML declaration, if any */
1763  res_code = parse_xml_decl(utf8string,
1764  &count, &version, NULL, &standalone);
1765  if (res_code != 0)
1766  {
1767  errsave(escontext,
1768  errcode(ERRCODE_INVALID_XML_CONTENT),
1769  errmsg_internal("invalid XML content: invalid XML declaration"),
1770  errdetail_for_xml_code(res_code));
1771  goto fail;
1772  }
1773 
1774  /* Is there a DOCTYPE element? */
1775  if (xml_doctype_in_content(utf8string + count))
1776  parse_as_document = true;
1777  }
1778 
1779  /* initialize output parameters */
1780  if (parsed_xmloptiontype != NULL)
1781  *parsed_xmloptiontype = parse_as_document ? XMLOPTION_DOCUMENT :
1783  if (parsed_nodes != NULL)
1784  *parsed_nodes = NULL;
1785 
1786  if (parse_as_document)
1787  {
1788  /*
1789  * Note, that here we try to apply DTD defaults
1790  * (XML_PARSE_DTDATTR) according to SQL/XML:2008 GR 10.16.7.d:
1791  * 'Default values defined by internal DTD are applied'. As for
1792  * external DTDs, we try to support them too, (see SQL/XML:2008 GR
1793  * 10.16.7.e)
1794  */
1795  doc = xmlCtxtReadDoc(ctxt, utf8string,
1796  NULL,
1797  "UTF-8",
1798  XML_PARSE_NOENT | XML_PARSE_DTDATTR
1799  | (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
1800  if (doc == NULL || xmlerrcxt->err_occurred)
1801  {
1802  /* Use original option to decide which error code to report */
1803  if (xmloption_arg == XMLOPTION_DOCUMENT)
1804  xml_errsave(escontext, xmlerrcxt,
1805  ERRCODE_INVALID_XML_DOCUMENT,
1806  "invalid XML document");
1807  else
1808  xml_errsave(escontext, xmlerrcxt,
1809  ERRCODE_INVALID_XML_CONTENT,
1810  "invalid XML content");
1811  goto fail;
1812  }
1813  }
1814  else
1815  {
1816  doc = xmlNewDoc(version);
1817  if (doc == NULL || xmlerrcxt->err_occurred)
1818  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
1819  "could not allocate XML document");
1820 
1821  Assert(doc->encoding == NULL);
1822  doc->encoding = xmlStrdup((const xmlChar *) "UTF-8");
1823  if (doc->encoding == NULL || xmlerrcxt->err_occurred)
1824  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
1825  "could not allocate XML document");
1826  doc->standalone = standalone;
1827 
1828  /* allow empty content */
1829  if (*(utf8string + count))
1830  {
1831  res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
1832  utf8string + count,
1833  parsed_nodes);
1834  if (res_code != 0 || xmlerrcxt->err_occurred)
1835  {
1836  xml_errsave(escontext, xmlerrcxt,
1837  ERRCODE_INVALID_XML_CONTENT,
1838  "invalid XML content");
1839  goto fail;
1840  }
1841  }
1842  }
1843 
1844 fail:
1845  ;
1846  }
1847  PG_CATCH();
1848  {
1849  if (doc != NULL)
1850  xmlFreeDoc(doc);
1851  if (ctxt != NULL)
1852  xmlFreeParserCtxt(ctxt);
1853 
1854  pg_xml_done(xmlerrcxt, true);
1855 
1856  PG_RE_THROW();
1857  }
1858  PG_END_TRY();
1859 
1860  xmlFreeParserCtxt(ctxt);
1861 
1862  pg_xml_done(xmlerrcxt, false);
1863 
1864  return doc;
1865 }
1866 
1867 
1868 /*
1869  * xmlChar<->text conversions
1870  */
1871 static xmlChar *
1872 xml_text2xmlChar(text *in)
1873 {
1874  return (xmlChar *) text_to_cstring(in);
1875 }
1876 
1877 
1878 #ifdef USE_LIBXMLCONTEXT
1879 
1880 /*
1881  * Manage the special context used for all libxml allocations (but only
1882  * in special debug builds; see notes at top of file)
1883  */
1884 static void
1885 xml_memory_init(void)
1886 {
1887  /* Create memory context if not there already */
1888  if (LibxmlContext == NULL)
1889  LibxmlContext = AllocSetContextCreate(TopMemoryContext,
1890  "Libxml context",
1892 
1893  /* Re-establish the callbacks even if already set */
1894  xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
1895 }
1896 
1897 /*
1898  * Wrappers for memory management functions
1899  */
1900 static void *
1901 xml_palloc(size_t size)
1902 {
1903  return MemoryContextAlloc(LibxmlContext, size);
1904 }
1905 
1906 
1907 static void *
1908 xml_repalloc(void *ptr, size_t size)
1909 {
1910  return repalloc(ptr, size);
1911 }
1912 
1913 
1914 static void
1915 xml_pfree(void *ptr)
1916 {
1917  /* At least some parts of libxml assume xmlFree(NULL) is allowed */
1918  if (ptr)
1919  pfree(ptr);
1920 }
1921 
1922 
1923 static char *
1924 xml_pstrdup(const char *string)
1925 {
1926  return MemoryContextStrdup(LibxmlContext, string);
1927 }
1928 #endif /* USE_LIBXMLCONTEXT */
1929 
1930 
1931 /*
1932  * xmlPgEntityLoader --- entity loader callback function
1933  *
1934  * Silently prevent any external entity URL from being loaded. We don't want
1935  * to throw an error, so instead make the entity appear to expand to an empty
1936  * string.
1937  *
1938  * We would prefer to allow loading entities that exist in the system's
1939  * global XML catalog; but the available libxml2 APIs make that a complex
1940  * and fragile task. For now, just shut down all external access.
1941  */
1942 static xmlParserInputPtr
1943 xmlPgEntityLoader(const char *URL, const char *ID,
1944  xmlParserCtxtPtr ctxt)
1945 {
1946  return xmlNewStringInputStream(ctxt, (const xmlChar *) "");
1947 }
1948 
1949 
1950 /*
1951  * xml_ereport --- report an XML-related error
1952  *
1953  * The "msg" is the SQL-level message; some can be adopted from the SQL/XML
1954  * standard. This function adds libxml's native error message, if any, as
1955  * detail.
1956  *
1957  * This is exported for modules that want to share the core libxml error
1958  * handler. Note that pg_xml_init() *must* have been called previously.
1959  */
1960 void
1961 xml_ereport(PgXmlErrorContext *errcxt, int level, int sqlcode, const char *msg)
1962 {
1963  char *detail;
1964 
1965  /* Defend against someone passing us a bogus context struct */
1966  if (errcxt->magic != ERRCXT_MAGIC)
1967  elog(ERROR, "xml_ereport called with invalid PgXmlErrorContext");
1968 
1969  /* Flag that the current libxml error has been reported */
1970  errcxt->err_occurred = false;
1971 
1972  /* Include detail only if we have some text from libxml */
1973  if (errcxt->err_buf.len > 0)
1974  detail = errcxt->err_buf.data;
1975  else
1976  detail = NULL;
1977 
1978  ereport(level,
1979  (errcode(sqlcode),
1980  errmsg_internal("%s", msg),
1981  detail ? errdetail_internal("%s", detail) : 0));
1982 }
1983 
1984 
1985 /*
1986  * xml_errsave --- save an XML-related error
1987  *
1988  * If escontext is an ErrorSaveContext, error details are saved into it,
1989  * and control returns normally.
1990  *
1991  * Otherwise, the error is thrown, so that this is equivalent to
1992  * xml_ereport() with level == ERROR.
1993  *
1994  * This should be used only for errors that we're sure we do not need
1995  * a transaction abort to clean up after.
1996  */
1997 static void
1998 xml_errsave(Node *escontext, PgXmlErrorContext *errcxt,
1999  int sqlcode, const char *msg)
2000 {
2001  char *detail;
2002 
2003  /* Defend against someone passing us a bogus context struct */
2004  if (errcxt->magic != ERRCXT_MAGIC)
2005  elog(ERROR, "xml_errsave called with invalid PgXmlErrorContext");
2006 
2007  /* Flag that the current libxml error has been reported */
2008  errcxt->err_occurred = false;
2009 
2010  /* Include detail only if we have some text from libxml */
2011  if (errcxt->err_buf.len > 0)
2012  detail = errcxt->err_buf.data;
2013  else
2014  detail = NULL;
2015 
2016  errsave(escontext,
2017  (errcode(sqlcode),
2018  errmsg_internal("%s", msg),
2019  detail ? errdetail_internal("%s", detail) : 0));
2020 }
2021 
2022 
2023 /*
2024  * Error handler for libxml errors and warnings
2025  */
2026 static void
2027 xml_errorHandler(void *data, xmlErrorPtr error)
2028 {
2029  PgXmlErrorContext *xmlerrcxt = (PgXmlErrorContext *) data;
2030  xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) error->ctxt;
2031  xmlParserInputPtr input = (ctxt != NULL) ? ctxt->input : NULL;
2032  xmlNodePtr node = error->node;
2033  const xmlChar *name = (node != NULL &&
2034  node->type == XML_ELEMENT_NODE) ? node->name : NULL;
2035  int domain = error->domain;
2036  int level = error->level;
2037  StringInfo errorBuf;
2038 
2039  /*
2040  * Defend against someone passing us a bogus context struct.
2041  *
2042  * We force a backend exit if this check fails because longjmp'ing out of
2043  * libxml would likely render it unsafe to use further.
2044  */
2045  if (xmlerrcxt->magic != ERRCXT_MAGIC)
2046  elog(FATAL, "xml_errorHandler called with invalid PgXmlErrorContext");
2047 
2048  /*----------
2049  * Older libxml versions report some errors differently.
2050  * First, some errors were previously reported as coming from the parser
2051  * domain but are now reported as coming from the namespace domain.
2052  * Second, some warnings were upgraded to errors.
2053  * We attempt to compensate for that here.
2054  *----------
2055  */
2056  switch (error->code)
2057  {
2058  case XML_WAR_NS_URI:
2059  level = XML_ERR_ERROR;
2060  domain = XML_FROM_NAMESPACE;
2061  break;
2062 
2063  case XML_ERR_NS_DECL_ERROR:
2064  case XML_WAR_NS_URI_RELATIVE:
2065  case XML_WAR_NS_COLUMN:
2066  case XML_NS_ERR_XML_NAMESPACE:
2067  case XML_NS_ERR_UNDEFINED_NAMESPACE:
2068  case XML_NS_ERR_QNAME:
2069  case XML_NS_ERR_ATTRIBUTE_REDEFINED:
2070  case XML_NS_ERR_EMPTY:
2071  domain = XML_FROM_NAMESPACE;
2072  break;
2073  }
2074 
2075  /* Decide whether to act on the error or not */
2076  switch (domain)
2077  {
2078  case XML_FROM_PARSER:
2079  case XML_FROM_NONE:
2080  case XML_FROM_MEMORY:
2081  case XML_FROM_IO:
2082 
2083  /*
2084  * Suppress warnings about undeclared entities. We need to do
2085  * this to avoid problems due to not loading DTD definitions.
2086  */
2087  if (error->code == XML_WAR_UNDECLARED_ENTITY)
2088  return;
2089 
2090  /* Otherwise, accept error regardless of the parsing purpose */
2091  break;
2092 
2093  default:
2094  /* Ignore error if only doing well-formedness check */
2095  if (xmlerrcxt->strictness == PG_XML_STRICTNESS_WELLFORMED)
2096  return;
2097  break;
2098  }
2099 
2100  /* Prepare error message in errorBuf */
2101  errorBuf = makeStringInfo();
2102 
2103  if (error->line > 0)
2104  appendStringInfo(errorBuf, "line %d: ", error->line);
2105  if (name != NULL)
2106  appendStringInfo(errorBuf, "element %s: ", name);
2107  if (error->message != NULL)
2108  appendStringInfoString(errorBuf, error->message);
2109  else
2110  appendStringInfoString(errorBuf, "(no message provided)");
2111 
2112  /*
2113  * Append context information to errorBuf.
2114  *
2115  * xmlParserPrintFileContext() uses libxml's "generic" error handler to
2116  * write the context. Since we don't want to duplicate libxml
2117  * functionality here, we set up a generic error handler temporarily.
2118  *
2119  * We use appendStringInfo() directly as libxml's generic error handler.
2120  * This should work because it has essentially the same signature as
2121  * libxml expects, namely (void *ptr, const char *msg, ...).
2122  */
2123  if (input != NULL)
2124  {
2125  xmlGenericErrorFunc errFuncSaved = xmlGenericError;
2126  void *errCtxSaved = xmlGenericErrorContext;
2127 
2128  xmlSetGenericErrorFunc((void *) errorBuf,
2129  (xmlGenericErrorFunc) appendStringInfo);
2130 
2131  /* Add context information to errorBuf */
2132  appendStringInfoLineSeparator(errorBuf);
2133 
2134  xmlParserPrintFileContext(input);
2135 
2136  /* Restore generic error func */
2137  xmlSetGenericErrorFunc(errCtxSaved, errFuncSaved);
2138  }
2139 
2140  /* Get rid of any trailing newlines in errorBuf */
2141  chopStringInfoNewlines(errorBuf);
2142 
2143  /*
2144  * Legacy error handling mode. err_occurred is never set, we just add the
2145  * message to err_buf. This mode exists because the xml2 contrib module
2146  * uses our error-handling infrastructure, but we don't want to change its
2147  * behaviour since it's deprecated anyway. This is also why we don't
2148  * distinguish between notices, warnings and errors here --- the old-style
2149  * generic error handler wouldn't have done that either.
2150  */
2151  if (xmlerrcxt->strictness == PG_XML_STRICTNESS_LEGACY)
2152  {
2153  appendStringInfoLineSeparator(&xmlerrcxt->err_buf);
2154  appendBinaryStringInfo(&xmlerrcxt->err_buf, errorBuf->data,
2155  errorBuf->len);
2156 
2157  pfree(errorBuf->data);
2158  pfree(errorBuf);
2159  return;
2160  }
2161 
2162  /*
2163  * We don't want to ereport() here because that'd probably leave libxml in
2164  * an inconsistent state. Instead, we remember the error and ereport()
2165  * from xml_ereport().
2166  *
2167  * Warnings and notices can be reported immediately since they won't cause
2168  * a longjmp() out of libxml.
2169  */
2170  if (level >= XML_ERR_ERROR)
2171  {
2172  appendStringInfoLineSeparator(&xmlerrcxt->err_buf);
2173  appendBinaryStringInfo(&xmlerrcxt->err_buf, errorBuf->data,
2174  errorBuf->len);
2175 
2176  xmlerrcxt->err_occurred = true;
2177  }
2178  else if (level >= XML_ERR_WARNING)
2179  {
2180  ereport(WARNING,
2181  (errmsg_internal("%s", errorBuf->data)));
2182  }
2183  else
2184  {
2185  ereport(NOTICE,
2186  (errmsg_internal("%s", errorBuf->data)));
2187  }
2188 
2189  pfree(errorBuf->data);
2190  pfree(errorBuf);
2191 }
2192 
2193 
2194 /*
2195  * Convert libxml error codes into textual errdetail messages.
2196  *
2197  * This should be called within an ereport or errsave invocation,
2198  * just as errdetail would be.
2199  *
2200  * At the moment, we only need to cover those codes that we
2201  * may raise in this file.
2202  */
2203 static int
2204 errdetail_for_xml_code(int code)
2205 {
2206  const char *det;
2207 
2208  switch (code)
2209  {
2210  case XML_ERR_INVALID_CHAR:
2211  det = gettext_noop("Invalid character value.");
2212  break;
2213  case XML_ERR_SPACE_REQUIRED:
2214  det = gettext_noop("Space required.");
2215  break;
2216  case XML_ERR_STANDALONE_VALUE:
2217  det = gettext_noop("standalone accepts only 'yes' or 'no'.");
2218  break;
2219  case XML_ERR_VERSION_MISSING:
2220  det = gettext_noop("Malformed declaration: missing version.");
2221  break;
2222  case XML_ERR_MISSING_ENCODING:
2223  det = gettext_noop("Missing encoding in text declaration.");
2224  break;
2225  case XML_ERR_XMLDECL_NOT_FINISHED:
2226  det = gettext_noop("Parsing XML declaration: '?>' expected.");
2227  break;
2228  default:
2229  det = gettext_noop("Unrecognized libxml error code: %d.");
2230  break;
2231  }
2232 
2233  return errdetail(det, code);
2234 }
2235 
2236 
2237 /*
2238  * Remove all trailing newlines from a StringInfo string
2239  */
2240 static void
2241 chopStringInfoNewlines(StringInfo str)
2242 {
2243  while (str->len > 0 && str->data[str->len - 1] == '\n')
2244  str->data[--str->len] = '\0';
2245 }
2246 
2247 
2248 /*
2249  * Append a newline after removing any existing trailing newlines
2250  */
2251 static void
2252 appendStringInfoLineSeparator(StringInfo str)
2253 {
2254  chopStringInfoNewlines(str);
2255  if (str->len > 0)
2256  appendStringInfoChar(str, '\n');
2257 }
2258 
2259 
2260 /*
2261  * Convert one char in the current server encoding to a Unicode codepoint.
2262  */
2263 static pg_wchar
2264 sqlchar_to_unicode(const char *s)
2265 {
2266  char *utf8string;
2267  pg_wchar ret[2]; /* need space for trailing zero */
2268 
2269  /* note we're not assuming s is null-terminated */
2270  utf8string = pg_server_to_any(s, pg_mblen(s), PG_UTF8);
2271 
2272  pg_encoding_mb2wchar_with_len(PG_UTF8, utf8string, ret,
2273  pg_encoding_mblen(PG_UTF8, utf8string));
2274 
2275  if (utf8string != s)
2276  pfree(utf8string);
2277 
2278  return ret[0];
2279 }
2280 
2281 
2282 static bool
2283 is_valid_xml_namefirst(pg_wchar c)
2284 {
2285  /* (Letter | '_' | ':') */
2286  return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)
2287  || c == '_' || c == ':');
2288 }
2289 
2290 
2291 static bool
2292 is_valid_xml_namechar(pg_wchar c)
2293 {
2294  /* Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender */
2295  return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)
2296  || xmlIsDigitQ(c)
2297  || c == '.' || c == '-' || c == '_' || c == ':'
2298  || xmlIsCombiningQ(c)
2299  || xmlIsExtenderQ(c));
2300 }
2301 #endif /* USE_LIBXML */
2302 
2303 
2304 /*
2305  * Map SQL identifier to XML name; see SQL/XML:2008 section 9.1.
2306  */
2307 char *
2308 map_sql_identifier_to_xml_name(const char *ident, bool fully_escaped,
2309  bool escape_period)
2310 {
2311 #ifdef USE_LIBXML
2313  const char *p;
2314 
2315  /*
2316  * SQL/XML doesn't make use of this case anywhere, so it's probably a
2317  * mistake.
2318  */
2319  Assert(fully_escaped || !escape_period);
2320 
2321  initStringInfo(&buf);
2322 
2323  for (p = ident; *p; p += pg_mblen(p))
2324  {
2325  if (*p == ':' && (p == ident || fully_escaped))
2326  appendStringInfoString(&buf, "_x003A_");
2327  else if (*p == '_' && *(p + 1) == 'x')
2328  appendStringInfoString(&buf, "_x005F_");
2329  else if (fully_escaped && p == ident &&
2330  pg_strncasecmp(p, "xml", 3) == 0)
2331  {
2332  if (*p == 'x')
2333  appendStringInfoString(&buf, "_x0078_");
2334  else
2335  appendStringInfoString(&buf, "_x0058_");
2336  }
2337  else if (escape_period && *p == '.')
2338  appendStringInfoString(&buf, "_x002E_");
2339  else
2340  {
2341  pg_wchar u = sqlchar_to_unicode(p);
2342 
2343  if ((p == ident)
2344  ? !is_valid_xml_namefirst(u)
2345  : !is_valid_xml_namechar(u))
2346  appendStringInfo(&buf, "_x%04X_", (unsigned int) u);
2347  else
2349  }
2350  }
2351 
2352  return buf.data;
2353 #else /* not USE_LIBXML */
2354  NO_XML_SUPPORT();
2355  return NULL;
2356 #endif /* not USE_LIBXML */
2357 }
2358 
2359 
2360 /*
2361  * Map XML name to SQL identifier; see SQL/XML:2008 section 9.3.
2362  */
2363 char *
2365 {
2367  const char *p;
2368 
2369  initStringInfo(&buf);
2370 
2371  for (p = name; *p; p += pg_mblen(p))
2372  {
2373  if (*p == '_' && *(p + 1) == 'x'
2374  && isxdigit((unsigned char) *(p + 2))
2375  && isxdigit((unsigned char) *(p + 3))
2376  && isxdigit((unsigned char) *(p + 4))
2377  && isxdigit((unsigned char) *(p + 5))
2378  && *(p + 6) == '_')
2379  {
2380  char cbuf[MAX_UNICODE_EQUIVALENT_STRING + 1];
2381  unsigned int u;
2382 
2383  sscanf(p + 2, "%X", &u);
2384  pg_unicode_to_server(u, (unsigned char *) cbuf);
2385  appendStringInfoString(&buf, cbuf);
2386  p += 6;
2387  }
2388  else
2390  }
2391 
2392  return buf.data;
2393 }
2394 
2395 /*
2396  * Map SQL value to XML value; see SQL/XML:2008 section 9.8.
2397  *
2398  * When xml_escape_strings is true, then certain characters in string
2399  * values are replaced by entity references (&lt; etc.), as specified
2400  * in SQL/XML:2008 section 9.8 GR 9) a) iii). This is normally what is
2401  * wanted. The false case is mainly useful when the resulting value
2402  * is used with xmlTextWriterWriteAttribute() to write out an
2403  * attribute, because that function does the escaping itself.
2404  */
2405 char *
2406 map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
2407 {
2409  {
2410  ArrayType *array;
2411  Oid elmtype;
2412  int16 elmlen;
2413  bool elmbyval;
2414  char elmalign;
2415  int num_elems;
2416  Datum *elem_values;
2417  bool *elem_nulls;
2419  int i;
2420 
2421  array = DatumGetArrayTypeP(value);
2422  elmtype = ARR_ELEMTYPE(array);
2423  get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign);
2424 
2425  deconstruct_array(array, elmtype,
2426  elmlen, elmbyval, elmalign,
2427  &elem_values, &elem_nulls,
2428  &num_elems);
2429 
2430  initStringInfo(&buf);
2431 
2432  for (i = 0; i < num_elems; i++)
2433  {
2434  if (elem_nulls[i])
2435  continue;
2436  appendStringInfoString(&buf, "<element>");
2438  map_sql_value_to_xml_value(elem_values[i],
2439  elmtype, true));
2440  appendStringInfoString(&buf, "</element>");
2441  }
2442 
2443  pfree(elem_values);
2444  pfree(elem_nulls);
2445 
2446  return buf.data;
2447  }
2448  else
2449  {
2450  Oid typeOut;
2451  bool isvarlena;
2452  char *str;
2453 
2454  /*
2455  * Flatten domains; the special-case treatments below should apply to,
2456  * eg, domains over boolean not just boolean.
2457  */
2458  type = getBaseType(type);
2459 
2460  /*
2461  * Special XSD formatting for some data types
2462  */
2463  switch (type)
2464  {
2465  case BOOLOID:
2466  if (DatumGetBool(value))
2467  return "true";
2468  else
2469  return "false";
2470 
2471  case DATEOID:
2472  {
2473  DateADT date;
2474  struct pg_tm tm;
2475  char buf[MAXDATELEN + 1];
2476 
2478  /* XSD doesn't support infinite values */
2479  if (DATE_NOT_FINITE(date))
2480  ereport(ERROR,
2481  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2482  errmsg("date out of range"),
2483  errdetail("XML does not support infinite date values.")));
2485  &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
2487 
2488  return pstrdup(buf);
2489  }
2490 
2491  case TIMESTAMPOID:
2492  {
2494  struct pg_tm tm;
2495  fsec_t fsec;
2496  char buf[MAXDATELEN + 1];
2497 
2499 
2500  /* XSD doesn't support infinite values */
2502  ereport(ERROR,
2503  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2504  errmsg("timestamp out of range"),
2505  errdetail("XML does not support infinite timestamp values.")));
2506  else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
2507  EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
2508  else
2509  ereport(ERROR,
2510  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2511  errmsg("timestamp out of range")));
2512 
2513  return pstrdup(buf);
2514  }
2515 
2516  case TIMESTAMPTZOID:
2517  {
2519  struct pg_tm tm;
2520  int tz;
2521  fsec_t fsec;
2522  const char *tzn = NULL;
2523  char buf[MAXDATELEN + 1];
2524 
2526 
2527  /* XSD doesn't support infinite values */
2529  ereport(ERROR,
2530  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2531  errmsg("timestamp out of range"),
2532  errdetail("XML does not support infinite timestamp values.")));
2533  else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
2534  EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
2535  else
2536  ereport(ERROR,
2537  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2538  errmsg("timestamp out of range")));
2539 
2540  return pstrdup(buf);
2541  }
2542 
2543 #ifdef USE_LIBXML
2544  case BYTEAOID:
2545  {
2546  bytea *bstr = DatumGetByteaPP(value);
2547  PgXmlErrorContext *xmlerrcxt;
2548  volatile xmlBufferPtr buf = NULL;
2549  volatile xmlTextWriterPtr writer = NULL;
2550  char *result;
2551 
2552  xmlerrcxt = pg_xml_init(PG_XML_STRICTNESS_ALL);
2553 
2554  PG_TRY();
2555  {
2556  buf = xmlBufferCreate();
2557  if (buf == NULL || xmlerrcxt->err_occurred)
2558  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
2559  "could not allocate xmlBuffer");
2560  writer = xmlNewTextWriterMemory(buf, 0);
2561  if (writer == NULL || xmlerrcxt->err_occurred)
2562  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
2563  "could not allocate xmlTextWriter");
2564 
2565  if (xmlbinary == XMLBINARY_BASE64)
2566  xmlTextWriterWriteBase64(writer, VARDATA_ANY(bstr),
2567  0, VARSIZE_ANY_EXHDR(bstr));
2568  else
2569  xmlTextWriterWriteBinHex(writer, VARDATA_ANY(bstr),
2570  0, VARSIZE_ANY_EXHDR(bstr));
2571 
2572  /* we MUST do this now to flush data out to the buffer */
2573  xmlFreeTextWriter(writer);
2574  writer = NULL;
2575 
2576  result = pstrdup((const char *) xmlBufferContent(buf));
2577  }
2578  PG_CATCH();
2579  {
2580  if (writer)
2581  xmlFreeTextWriter(writer);
2582  if (buf)
2583  xmlBufferFree(buf);
2584 
2585  pg_xml_done(xmlerrcxt, true);
2586 
2587  PG_RE_THROW();
2588  }
2589  PG_END_TRY();
2590 
2591  xmlBufferFree(buf);
2592 
2593  pg_xml_done(xmlerrcxt, false);
2594 
2595  return result;
2596  }
2597 #endif /* USE_LIBXML */
2598 
2599  }
2600 
2601  /*
2602  * otherwise, just use the type's native text representation
2603  */
2604  getTypeOutputInfo(type, &typeOut, &isvarlena);
2605  str = OidOutputFunctionCall(typeOut, value);
2606 
2607  /* ... exactly as-is for XML, and when escaping is not wanted */
2608  if (type == XMLOID || !xml_escape_strings)
2609  return str;
2610 
2611  /* otherwise, translate special characters as needed */
2612  return escape_xml(str);
2613  }
2614 }
2615 
2616 
2617 /*
2618  * Escape characters in text that have special meanings in XML.
2619  *
2620  * Returns a palloc'd string.
2621  *
2622  * NB: this is intentionally not dependent on libxml.
2623  */
2624 char *
2625 escape_xml(const char *str)
2626 {
2628  const char *p;
2629 
2630  initStringInfo(&buf);
2631  for (p = str; *p; p++)
2632  {
2633  switch (*p)
2634  {
2635  case '&':
2636  appendStringInfoString(&buf, "&amp;");
2637  break;
2638  case '<':
2639  appendStringInfoString(&buf, "&lt;");
2640  break;
2641  case '>':
2642  appendStringInfoString(&buf, "&gt;");
2643  break;
2644  case '\r':
2645  appendStringInfoString(&buf, "&#x0d;");
2646  break;
2647  default:
2649  break;
2650  }
2651  }
2652  return buf.data;
2653 }
2654 
2655 
2656 static char *
2657 _SPI_strdup(const char *s)
2658 {
2659  size_t len = strlen(s) + 1;
2660  char *ret = SPI_palloc(len);
2661 
2662  memcpy(ret, s, len);
2663  return ret;
2664 }
2665 
2666 
2667 /*
2668  * SQL to XML mapping functions
2669  *
2670  * What follows below was at one point intentionally organized so that
2671  * you can read along in the SQL/XML standard. The functions are
2672  * mostly split up the way the clauses lay out in the standards
2673  * document, and the identifiers are also aligned with the standard
2674  * text. Unfortunately, SQL/XML:2006 reordered the clauses
2675  * differently than SQL/XML:2003, so the order below doesn't make much
2676  * sense anymore.
2677  *
2678  * There are many things going on there:
2679  *
2680  * There are two kinds of mappings: Mapping SQL data (table contents)
2681  * to XML documents, and mapping SQL structure (the "schema") to XML
2682  * Schema. And there are functions that do both at the same time.
2683  *
2684  * Then you can map a database, a schema, or a table, each in both
2685  * ways. This breaks down recursively: Mapping a database invokes
2686  * mapping schemas, which invokes mapping tables, which invokes
2687  * mapping rows, which invokes mapping columns, although you can't
2688  * call the last two from the outside. Because of this, there are a
2689  * number of xyz_internal() functions which are to be called both from
2690  * the function manager wrapper and from some upper layer in a
2691  * recursive call.
2692  *
2693  * See the documentation about what the common function arguments
2694  * nulls, tableforest, and targetns mean.
2695  *
2696  * Some style guidelines for XML output: Use double quotes for quoting
2697  * XML attributes. Indent XML elements by two spaces, but remember
2698  * that a lot of code is called recursively at different levels, so
2699  * it's better not to indent rather than create output that indents
2700  * and outdents weirdly. Add newlines to make the output look nice.
2701  */
2702 
2703 
2704 /*
2705  * Visibility of objects for XML mappings; see SQL/XML:2008 section
2706  * 4.10.8.
2707  */
2708 
2709 /*
2710  * Given a query, which must return type oid as first column, produce
2711  * a list of Oids with the query results.
2712  */
2713 static List *
2714 query_to_oid_list(const char *query)
2715 {
2716  uint64 i;
2717  List *list = NIL;
2718  int spi_result;
2719 
2720  spi_result = SPI_execute(query, true, 0);
2721  if (spi_result != SPI_OK_SELECT)
2722  elog(ERROR, "SPI_execute returned %s for %s",
2723  SPI_result_code_string(spi_result), query);
2724 
2725  for (i = 0; i < SPI_processed; i++)
2726  {
2727  Datum oid;
2728  bool isnull;
2729 
2730  oid = SPI_getbinval(SPI_tuptable->vals[i],
2732  1,
2733  &isnull);
2734  if (!isnull)
2736  }
2737 
2738  return list;
2739 }
2740 
2741 
2742 static List *
2744 {
2745  StringInfoData query;
2746 
2747  initStringInfo(&query);
2748  appendStringInfo(&query, "SELECT oid FROM pg_catalog.pg_class"
2749  " WHERE relnamespace = %u AND relkind IN ("
2750  CppAsString2(RELKIND_RELATION) ","
2751  CppAsString2(RELKIND_MATVIEW) ","
2752  CppAsString2(RELKIND_VIEW) ")"
2753  " AND pg_catalog.has_table_privilege (oid, 'SELECT')"
2754  " ORDER BY relname;", nspid);
2755 
2756  return query_to_oid_list(query.data);
2757 }
2758 
2759 
2760 /*
2761  * Including the system schemas is probably not useful for a database
2762  * mapping.
2763  */
2764 #define XML_VISIBLE_SCHEMAS_EXCLUDE "(nspname ~ '^pg_' OR nspname = 'information_schema')"
2765 
2766 #define XML_VISIBLE_SCHEMAS "SELECT oid FROM pg_catalog.pg_namespace WHERE pg_catalog.has_schema_privilege (oid, 'USAGE') AND NOT " XML_VISIBLE_SCHEMAS_EXCLUDE
2767 
2768 
2769 static List *
2771 {
2772  return query_to_oid_list(XML_VISIBLE_SCHEMAS " ORDER BY nspname;");
2773 }
2774 
2775 
2776 static List *
2778 {
2779  /* At the moment there is no order required here. */
2780  return query_to_oid_list("SELECT oid FROM pg_catalog.pg_class"
2781  " WHERE relkind IN ("
2782  CppAsString2(RELKIND_RELATION) ","
2783  CppAsString2(RELKIND_MATVIEW) ","
2784  CppAsString2(RELKIND_VIEW) ")"
2785  " AND pg_catalog.has_table_privilege(pg_class.oid, 'SELECT')"
2786  " AND relnamespace IN (" XML_VISIBLE_SCHEMAS ");");
2787 }
2788 
2789 
2790 /*
2791  * Map SQL table to XML and/or XML Schema document; see SQL/XML:2008
2792  * section 9.11.
2793  */
2794 
2795 static StringInfo
2797  const char *xmlschema, bool nulls, bool tableforest,
2798  const char *targetns, bool top_level)
2799 {
2800  StringInfoData query;
2801 
2802  initStringInfo(&query);
2803  appendStringInfo(&query, "SELECT * FROM %s",
2805  ObjectIdGetDatum(relid))));
2806  return query_to_xml_internal(query.data, get_rel_name(relid),
2807  xmlschema, nulls, tableforest,
2808  targetns, top_level);
2809 }
2810 
2811 
2812 Datum
2814 {
2815  Oid relid = PG_GETARG_OID(0);
2816  bool nulls = PG_GETARG_BOOL(1);
2817  bool tableforest = PG_GETARG_BOOL(2);
2818  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
2819 
2821  nulls, tableforest,
2822  targetns, true)));
2823 }
2824 
2825 
2826 Datum
2828 {
2829  char *query = text_to_cstring(PG_GETARG_TEXT_PP(0));
2830  bool nulls = PG_GETARG_BOOL(1);
2831  bool tableforest = PG_GETARG_BOOL(2);
2832  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
2833 
2835  NULL, nulls, tableforest,
2836  targetns, true)));
2837 }
2838 
2839 
2840 Datum
2842 {
2844  int32 count = PG_GETARG_INT32(1);
2845  bool nulls = PG_GETARG_BOOL(2);
2846  bool tableforest = PG_GETARG_BOOL(3);
2847  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(4));
2848 
2849  StringInfoData result;
2850  Portal portal;
2851  uint64 i;
2852 
2853  initStringInfo(&result);
2854 
2855  if (!tableforest)
2856  {
2857  xmldata_root_element_start(&result, "table", NULL, targetns, true);
2858  appendStringInfoChar(&result, '\n');
2859  }
2860 
2861  SPI_connect();
2862  portal = SPI_cursor_find(name);
2863  if (portal == NULL)
2864  ereport(ERROR,
2865  (errcode(ERRCODE_UNDEFINED_CURSOR),
2866  errmsg("cursor \"%s\" does not exist", name)));
2867 
2868  SPI_cursor_fetch(portal, true, count);
2869  for (i = 0; i < SPI_processed; i++)
2870  SPI_sql_row_to_xmlelement(i, &result, NULL, nulls,
2871  tableforest, targetns, true);
2872 
2873  SPI_finish();
2874 
2875  if (!tableforest)
2876  xmldata_root_element_end(&result, "table");
2877 
2879 }
2880 
2881 
2882 /*
2883  * Write the start tag of the root element of a data mapping.
2884  *
2885  * top_level means that this is the very top level of the eventual
2886  * output. For example, when the user calls table_to_xml, then a call
2887  * with a table name to this function is the top level. When the user
2888  * calls database_to_xml, then a call with a schema name to this
2889  * function is not the top level. If top_level is false, then the XML
2890  * namespace declarations are omitted, because they supposedly already
2891  * appeared earlier in the output. Repeating them is not wrong, but
2892  * it looks ugly.
2893  */
2894 static void
2895 xmldata_root_element_start(StringInfo result, const char *eltname,
2896  const char *xmlschema, const char *targetns,
2897  bool top_level)
2898 {
2899  /* This isn't really wrong but currently makes no sense. */
2900  Assert(top_level || !xmlschema);
2901 
2902  appendStringInfo(result, "<%s", eltname);
2903  if (top_level)
2904  {
2905  appendStringInfoString(result, " xmlns:xsi=\"" NAMESPACE_XSI "\"");
2906  if (strlen(targetns) > 0)
2907  appendStringInfo(result, " xmlns=\"%s\"", targetns);
2908  }
2909  if (xmlschema)
2910  {
2911  /* FIXME: better targets */
2912  if (strlen(targetns) > 0)
2913  appendStringInfo(result, " xsi:schemaLocation=\"%s #\"", targetns);
2914  else
2915  appendStringInfoString(result, " xsi:noNamespaceSchemaLocation=\"#\"");
2916  }
2917  appendStringInfoString(result, ">\n");
2918 }
2919 
2920 
2921 static void
2922 xmldata_root_element_end(StringInfo result, const char *eltname)
2923 {
2924  appendStringInfo(result, "</%s>\n", eltname);
2925 }
2926 
2927 
2928 static StringInfo
2929 query_to_xml_internal(const char *query, char *tablename,
2930  const char *xmlschema, bool nulls, bool tableforest,
2931  const char *targetns, bool top_level)
2932 {
2933  StringInfo result;
2934  char *xmltn;
2935  uint64 i;
2936 
2937  if (tablename)
2938  xmltn = map_sql_identifier_to_xml_name(tablename, true, false);
2939  else
2940  xmltn = "table";
2941 
2942  result = makeStringInfo();
2943 
2944  SPI_connect();
2945  if (SPI_execute(query, true, 0) != SPI_OK_SELECT)
2946  ereport(ERROR,
2947  (errcode(ERRCODE_DATA_EXCEPTION),
2948  errmsg("invalid query")));
2949 
2950  if (!tableforest)
2951  {
2952  xmldata_root_element_start(result, xmltn, xmlschema,
2953  targetns, top_level);
2954  appendStringInfoChar(result, '\n');
2955  }
2956 
2957  if (xmlschema)
2958  appendStringInfo(result, "%s\n\n", xmlschema);
2959 
2960  for (i = 0; i < SPI_processed; i++)
2961  SPI_sql_row_to_xmlelement(i, result, tablename, nulls,
2962  tableforest, targetns, top_level);
2963 
2964  if (!tableforest)
2965  xmldata_root_element_end(result, xmltn);
2966 
2967  SPI_finish();
2968 
2969  return result;
2970 }
2971 
2972 
2973 Datum
2975 {
2976  Oid relid = PG_GETARG_OID(0);
2977  bool nulls = PG_GETARG_BOOL(1);
2978  bool tableforest = PG_GETARG_BOOL(2);
2979  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
2980  const char *result;
2981  Relation rel;
2982 
2983  rel = table_open(relid, AccessShareLock);
2984  result = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls,
2985  tableforest, targetns);
2986  table_close(rel, NoLock);
2987 
2989 }
2990 
2991 
2992 Datum
2994 {
2995  char *query = text_to_cstring(PG_GETARG_TEXT_PP(0));
2996  bool nulls = PG_GETARG_BOOL(1);
2997  bool tableforest = PG_GETARG_BOOL(2);
2998  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
2999  const char *result;
3000  SPIPlanPtr plan;
3001  Portal portal;
3002 
3003  SPI_connect();
3004 
3005  if ((plan = SPI_prepare(query, 0, NULL)) == NULL)
3006  elog(ERROR, "SPI_prepare(\"%s\") failed", query);
3007 
3008  if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL)
3009  elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
3010 
3012  InvalidOid, nulls,
3013  tableforest, targetns));
3014  SPI_cursor_close(portal);
3015  SPI_finish();
3016 
3018 }
3019 
3020 
3021 Datum
3023 {
3025  bool nulls = PG_GETARG_BOOL(1);
3026  bool tableforest = PG_GETARG_BOOL(2);
3027  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3028  const char *xmlschema;
3029  Portal portal;
3030 
3031  SPI_connect();
3032  portal = SPI_cursor_find(name);
3033  if (portal == NULL)
3034  ereport(ERROR,
3035  (errcode(ERRCODE_UNDEFINED_CURSOR),
3036  errmsg("cursor \"%s\" does not exist", name)));
3037  if (portal->tupDesc == NULL)
3038  ereport(ERROR,
3039  (errcode(ERRCODE_INVALID_CURSOR_STATE),
3040  errmsg("portal \"%s\" does not return tuples", name)));
3041 
3042  xmlschema = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc,
3043  InvalidOid, nulls,
3044  tableforest, targetns));
3045  SPI_finish();
3046 
3047  PG_RETURN_XML_P(cstring_to_xmltype(xmlschema));
3048 }
3049 
3050 
3051 Datum
3053 {
3054  Oid relid = PG_GETARG_OID(0);
3055  bool nulls = PG_GETARG_BOOL(1);
3056  bool tableforest = PG_GETARG_BOOL(2);
3057  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3058  Relation rel;
3059  const char *xmlschema;
3060 
3061  rel = table_open(relid, AccessShareLock);
3062  xmlschema = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls,
3063  tableforest, targetns);
3064  table_close(rel, NoLock);
3065 
3067  xmlschema, nulls, tableforest,
3068  targetns, true)));
3069 }
3070 
3071 
3072 Datum
3074 {
3075  char *query = text_to_cstring(PG_GETARG_TEXT_PP(0));
3076  bool nulls = PG_GETARG_BOOL(1);
3077  bool tableforest = PG_GETARG_BOOL(2);
3078  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3079 
3080  const char *xmlschema;
3081  SPIPlanPtr plan;
3082  Portal portal;
3083 
3084  SPI_connect();
3085 
3086  if ((plan = SPI_prepare(query, 0, NULL)) == NULL)
3087  elog(ERROR, "SPI_prepare(\"%s\") failed", query);
3088 
3089  if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL)
3090  elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
3091 
3092  xmlschema = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc,
3093  InvalidOid, nulls, tableforest, targetns));
3094  SPI_cursor_close(portal);
3095  SPI_finish();
3096 
3098  xmlschema, nulls, tableforest,
3099  targetns, true)));
3100 }
3101 
3102 
3103 /*
3104  * Map SQL schema to XML and/or XML Schema document; see SQL/XML:2008
3105  * sections 9.13, 9.14.
3106  */
3107 
3108 static StringInfo
3109 schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls,
3110  bool tableforest, const char *targetns, bool top_level)
3111 {
3112  StringInfo result;
3113  char *xmlsn;
3114  List *relid_list;
3115  ListCell *cell;
3116 
3118  true, false);
3119  result = makeStringInfo();
3120 
3121  xmldata_root_element_start(result, xmlsn, xmlschema, targetns, top_level);
3122  appendStringInfoChar(result, '\n');
3123 
3124  if (xmlschema)
3125  appendStringInfo(result, "%s\n\n", xmlschema);
3126 
3127  SPI_connect();
3128 
3129  relid_list = schema_get_xml_visible_tables(nspid);
3130 
3131  foreach(cell, relid_list)
3132  {
3133  Oid relid = lfirst_oid(cell);
3134  StringInfo subres;
3135 
3136  subres = table_to_xml_internal(relid, NULL, nulls, tableforest,
3137  targetns, false);
3138 
3139  appendBinaryStringInfo(result, subres->data, subres->len);
3140  appendStringInfoChar(result, '\n');
3141  }
3142 
3143  SPI_finish();
3144 
3145  xmldata_root_element_end(result, xmlsn);
3146 
3147  return result;
3148 }
3149 
3150 
3151 Datum
3153 {
3154  Name name = PG_GETARG_NAME(0);
3155  bool nulls = PG_GETARG_BOOL(1);
3156  bool tableforest = PG_GETARG_BOOL(2);
3157  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3158 
3159  char *schemaname;
3160  Oid nspid;
3161 
3162  schemaname = NameStr(*name);
3163  nspid = LookupExplicitNamespace(schemaname, false);
3164 
3166  nulls, tableforest, targetns, true)));
3167 }
3168 
3169 
3170 /*
3171  * Write the start element of the root element of an XML Schema mapping.
3172  */
3173 static void
3174 xsd_schema_element_start(StringInfo result, const char *targetns)
3175 {
3176  appendStringInfoString(result,
3177  "<xsd:schema\n"
3178  " xmlns:xsd=\"" NAMESPACE_XSD "\"");
3179  if (strlen(targetns) > 0)
3180  appendStringInfo(result,
3181  "\n"
3182  " targetNamespace=\"%s\"\n"
3183  " elementFormDefault=\"qualified\"",
3184  targetns);
3185  appendStringInfoString(result,
3186  ">\n\n");
3187 }
3188 
3189 
3190 static void
3192 {
3193  appendStringInfoString(result, "</xsd:schema>");
3194 }
3195 
3196 
3197 static StringInfo
3198 schema_to_xmlschema_internal(const char *schemaname, bool nulls,
3199  bool tableforest, const char *targetns)
3200 {
3201  Oid nspid;
3202  List *relid_list;
3203  List *tupdesc_list;
3204  ListCell *cell;
3205  StringInfo result;
3206 
3207  result = makeStringInfo();
3208 
3209  nspid = LookupExplicitNamespace(schemaname, false);
3210 
3211  xsd_schema_element_start(result, targetns);
3212 
3213  SPI_connect();
3214 
3215  relid_list = schema_get_xml_visible_tables(nspid);
3216 
3217  tupdesc_list = NIL;
3218  foreach(cell, relid_list)
3219  {
3220  Relation rel;
3221 
3222  rel = table_open(lfirst_oid(cell), AccessShareLock);
3223  tupdesc_list = lappend(tupdesc_list, CreateTupleDescCopy(rel->rd_att));
3224  table_close(rel, NoLock);
3225  }
3226 
3227  appendStringInfoString(result,
3228  map_sql_typecoll_to_xmlschema_types(tupdesc_list));
3229 
3230  appendStringInfoString(result,
3232  nulls, tableforest, targetns));
3233 
3234  xsd_schema_element_end(result);
3235 
3236  SPI_finish();
3237 
3238  return result;
3239 }
3240 
3241 
3242 Datum
3244 {
3245  Name name = PG_GETARG_NAME(0);
3246  bool nulls = PG_GETARG_BOOL(1);
3247  bool tableforest = PG_GETARG_BOOL(2);
3248  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3249 
3251  nulls, tableforest, targetns)));
3252 }
3253 
3254 
3255 Datum
3257 {
3258  Name name = PG_GETARG_NAME(0);
3259  bool nulls = PG_GETARG_BOOL(1);
3260  bool tableforest = PG_GETARG_BOOL(2);
3261  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3262  char *schemaname;
3263  Oid nspid;
3264  StringInfo xmlschema;
3265 
3266  schemaname = NameStr(*name);
3267  nspid = LookupExplicitNamespace(schemaname, false);
3268 
3269  xmlschema = schema_to_xmlschema_internal(schemaname, nulls,
3270  tableforest, targetns);
3271 
3273  xmlschema->data, nulls,
3274  tableforest, targetns, true)));
3275 }
3276 
3277 
3278 /*
3279  * Map SQL database to XML and/or XML Schema document; see SQL/XML:2008
3280  * sections 9.16, 9.17.
3281  */
3282 
3283 static StringInfo
3284 database_to_xml_internal(const char *xmlschema, bool nulls,
3285  bool tableforest, const char *targetns)
3286 {
3287  StringInfo result;
3288  List *nspid_list;
3289  ListCell *cell;
3290  char *xmlcn;
3291 
3293  true, false);
3294  result = makeStringInfo();
3295 
3296  xmldata_root_element_start(result, xmlcn, xmlschema, targetns, true);
3297  appendStringInfoChar(result, '\n');
3298 
3299  if (xmlschema)
3300  appendStringInfo(result, "%s\n\n", xmlschema);
3301 
3302  SPI_connect();
3303 
3304  nspid_list = database_get_xml_visible_schemas();
3305 
3306  foreach(cell, nspid_list)
3307  {
3308  Oid nspid = lfirst_oid(cell);
3309  StringInfo subres;
3310 
3311  subres = schema_to_xml_internal(nspid, NULL, nulls,
3312  tableforest, targetns, false);
3313 
3314  appendBinaryStringInfo(result, subres->data, subres->len);
3315  appendStringInfoChar(result, '\n');
3316  }
3317 
3318  SPI_finish();
3319 
3320  xmldata_root_element_end(result, xmlcn);
3321 
3322  return result;
3323 }
3324 
3325 
3326 Datum
3328 {
3329  bool nulls = PG_GETARG_BOOL(0);
3330  bool tableforest = PG_GETARG_BOOL(1);
3331  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(2));
3332 
3334  tableforest, targetns)));
3335 }
3336 
3337 
3338 static StringInfo
3339 database_to_xmlschema_internal(bool nulls, bool tableforest,
3340  const char *targetns)
3341 {
3342  List *relid_list;
3343  List *nspid_list;
3344  List *tupdesc_list;
3345  ListCell *cell;
3346  StringInfo result;
3347 
3348  result = makeStringInfo();
3349 
3350  xsd_schema_element_start(result, targetns);
3351 
3352  SPI_connect();
3353 
3354  relid_list = database_get_xml_visible_tables();
3355  nspid_list = database_get_xml_visible_schemas();
3356 
3357  tupdesc_list = NIL;
3358  foreach(cell, relid_list)
3359  {
3360  Relation rel;
3361 
3362  rel = table_open(lfirst_oid(cell), AccessShareLock);
3363  tupdesc_list = lappend(tupdesc_list, CreateTupleDescCopy(rel->rd_att));
3364  table_close(rel, NoLock);
3365  }
3366 
3367  appendStringInfoString(result,
3368  map_sql_typecoll_to_xmlschema_types(tupdesc_list));
3369 
3370  appendStringInfoString(result,
3371  map_sql_catalog_to_xmlschema_types(nspid_list, nulls, tableforest, targetns));
3372 
3373  xsd_schema_element_end(result);
3374 
3375  SPI_finish();
3376 
3377  return result;
3378 }
3379 
3380 
3381 Datum
3383 {
3384  bool nulls = PG_GETARG_BOOL(0);
3385  bool tableforest = PG_GETARG_BOOL(1);
3386  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(2));
3387 
3389  tableforest, targetns)));
3390 }
3391 
3392 
3393 Datum
3395 {
3396  bool nulls = PG_GETARG_BOOL(0);
3397  bool tableforest = PG_GETARG_BOOL(1);
3398  const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(2));
3399  StringInfo xmlschema;
3400 
3401  xmlschema = database_to_xmlschema_internal(nulls, tableforest, targetns);
3402 
3404  nulls, tableforest, targetns)));
3405 }
3406 
3407 
3408 /*
3409  * Map a multi-part SQL name to an XML name; see SQL/XML:2008 section
3410  * 9.2.
3411  */
3412 static char *
3413 map_multipart_sql_identifier_to_xml_name(const char *a, const char *b, const char *c, const char *d)
3414 {
3415  StringInfoData result;
3416 
3417  initStringInfo(&result);
3418 
3419  if (a)
3420  appendStringInfoString(&result,
3421  map_sql_identifier_to_xml_name(a, true, true));
3422  if (b)
3423  appendStringInfo(&result, ".%s",
3424  map_sql_identifier_to_xml_name(b, true, true));
3425  if (c)
3426  appendStringInfo(&result, ".%s",
3427  map_sql_identifier_to_xml_name(c, true, true));
3428  if (d)
3429  appendStringInfo(&result, ".%s",
3430  map_sql_identifier_to_xml_name(d, true, true));
3431 
3432  return result.data;
3433 }
3434 
3435 
3436 /*
3437  * Map an SQL table to an XML Schema document; see SQL/XML:2008
3438  * section 9.11.
3439  *
3440  * Map an SQL table to XML Schema data types; see SQL/XML:2008 section
3441  * 9.9.
3442  */
3443 static const char *
3444 map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls,
3445  bool tableforest, const char *targetns)
3446 {
3447  int i;
3448  char *xmltn;
3449  char *tabletypename;
3450  char *rowtypename;
3451  StringInfoData result;
3452 
3453  initStringInfo(&result);
3454 
3455  if (OidIsValid(relid))
3456  {
3457  HeapTuple tuple;
3458  Form_pg_class reltuple;
3459 
3460  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
3461  if (!HeapTupleIsValid(tuple))
3462  elog(ERROR, "cache lookup failed for relation %u", relid);
3463  reltuple = (Form_pg_class) GETSTRUCT(tuple);
3464 
3465  xmltn = map_sql_identifier_to_xml_name(NameStr(reltuple->relname),
3466  true, false);
3467 
3468  tabletypename = map_multipart_sql_identifier_to_xml_name("TableType",
3470  get_namespace_name(reltuple->relnamespace),
3471  NameStr(reltuple->relname));
3472 
3473  rowtypename = map_multipart_sql_identifier_to_xml_name("RowType",
3475  get_namespace_name(reltuple->relnamespace),
3476  NameStr(reltuple->relname));
3477 
3478  ReleaseSysCache(tuple);
3479  }
3480  else
3481  {
3482  if (tableforest)
3483  xmltn = "row";
3484  else
3485  xmltn = "table";
3486 
3487  tabletypename = "TableType";
3488  rowtypename = "RowType";
3489  }
3490 
3491  xsd_schema_element_start(&result, targetns);
3492 
3493  appendStringInfoString(&result,
3495 
3496  appendStringInfo(&result,
3497  "<xsd:complexType name=\"%s\">\n"
3498  " <xsd:sequence>\n",
3499  rowtypename);
3500 
3501  for (i = 0; i < tupdesc->natts; i++)
3502  {
3503  Form_pg_attribute att = TupleDescAttr(tupdesc, i);
3504 
3505  if (att->attisdropped)
3506  continue;
3507  appendStringInfo(&result,
3508  " <xsd:element name=\"%s\" type=\"%s\"%s></xsd:element>\n",
3510  true, false),
3511  map_sql_type_to_xml_name(att->atttypid, -1),
3512  nulls ? " nillable=\"true\"" : " minOccurs=\"0\"");
3513  }
3514 
3515  appendStringInfoString(&result,
3516  " </xsd:sequence>\n"
3517  "</xsd:complexType>\n\n");
3518 
3519  if (!tableforest)
3520  {
3521  appendStringInfo(&result,
3522  "<xsd:complexType name=\"%s\">\n"
3523  " <xsd:sequence>\n"
3524  " <xsd:element name=\"row\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n"
3525  " </xsd:sequence>\n"
3526  "</xsd:complexType>\n\n",
3527  tabletypename, rowtypename);
3528 
3529  appendStringInfo(&result,
3530  "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3531  xmltn, tabletypename);
3532  }
3533  else
3534  appendStringInfo(&result,
3535  "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3536  xmltn, rowtypename);
3537 
3538  xsd_schema_element_end(&result);
3539 
3540  return result.data;
3541 }
3542 
3543 
3544 /*
3545  * Map an SQL schema to XML Schema data types; see SQL/XML:2008
3546  * section 9.12.
3547  */
3548 static const char *
3550  bool tableforest, const char *targetns)
3551 {
3552  char *dbname;
3553  char *nspname;
3554  char *xmlsn;
3555  char *schematypename;
3556  StringInfoData result;
3557  ListCell *cell;
3558 
3560  nspname = get_namespace_name(nspid);
3561 
3562  initStringInfo(&result);
3563 
3564  xmlsn = map_sql_identifier_to_xml_name(nspname, true, false);
3565 
3566  schematypename = map_multipart_sql_identifier_to_xml_name("SchemaType",
3567  dbname,
3568  nspname,
3569  NULL);
3570 
3571  appendStringInfo(&result,
3572  "<xsd:complexType name=\"%s\">\n", schematypename);
3573  if (!tableforest)
3574  appendStringInfoString(&result,
3575  " <xsd:all>\n");
3576  else
3577  appendStringInfoString(&result,
3578  " <xsd:sequence>\n");
3579 
3580  foreach(cell, relid_list)
3581  {
3582  Oid relid = lfirst_oid(cell);
3583  char *relname = get_rel_name(relid);
3584  char *xmltn = map_sql_identifier_to_xml_name(relname, true, false);
3585  char *tabletypename = map_multipart_sql_identifier_to_xml_name(tableforest ? "RowType" : "TableType",
3586  dbname,
3587  nspname,
3588  relname);
3589 
3590  if (!tableforest)
3591  appendStringInfo(&result,
3592  " <xsd:element name=\"%s\" type=\"%s\"/>\n",
3593  xmltn, tabletypename);
3594  else
3595  appendStringInfo(&result,
3596  " <xsd:element name=\"%s\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n",
3597  xmltn, tabletypename);
3598  }
3599 
3600  if (!tableforest)
3601  appendStringInfoString(&result,
3602  " </xsd:all>\n");
3603  else
3604  appendStringInfoString(&result,
3605  " </xsd:sequence>\n");
3606  appendStringInfoString(&result,
3607  "</xsd:complexType>\n\n");
3608 
3609  appendStringInfo(&result,
3610  "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3611  xmlsn, schematypename);
3612 
3613  return result.data;
3614 }
3615 
3616 
3617 /*
3618  * Map an SQL catalog to XML Schema data types; see SQL/XML:2008
3619  * section 9.15.
3620  */
3621 static const char *
3623  bool tableforest, const char *targetns)
3624 {
3625  char *dbname;
3626  char *xmlcn;
3627  char *catalogtypename;
3628  StringInfoData result;
3629  ListCell *cell;
3630 
3632 
3633  initStringInfo(&result);
3634 
3635  xmlcn = map_sql_identifier_to_xml_name(dbname, true, false);
3636 
3637  catalogtypename = map_multipart_sql_identifier_to_xml_name("CatalogType",
3638  dbname,
3639  NULL,
3640  NULL);
3641 
3642  appendStringInfo(&result,
3643  "<xsd:complexType name=\"%s\">\n", catalogtypename);
3644  appendStringInfoString(&result,
3645  " <xsd:all>\n");
3646 
3647  foreach(cell, nspid_list)
3648  {
3649  Oid nspid = lfirst_oid(cell);
3650  char *nspname = get_namespace_name(nspid);
3651  char *xmlsn = map_sql_identifier_to_xml_name(nspname, true, false);
3652  char *schematypename = map_multipart_sql_identifier_to_xml_name("SchemaType",
3653  dbname,
3654  nspname,
3655  NULL);
3656 
3657  appendStringInfo(&result,
3658  " <xsd:element name=\"%s\" type=\"%s\"/>\n",
3659  xmlsn, schematypename);
3660  }
3661 
3662  appendStringInfoString(&result,
3663  " </xsd:all>\n");
3664  appendStringInfoString(&result,
3665  "</xsd:complexType>\n\n");
3666 
3667  appendStringInfo(&result,
3668  "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3669  xmlcn, catalogtypename);
3670 
3671  return result.data;
3672 }
3673 
3674 
3675 /*
3676  * Map an SQL data type to an XML name; see SQL/XML:2008 section 9.4.
3677  */
3678 static const char *
3679 map_sql_type_to_xml_name(Oid typeoid, int typmod)
3680 {
3681  StringInfoData result;
3682 
3683  initStringInfo(&result);
3684 
3685  switch (typeoid)
3686  {
3687  case BPCHAROID:
3688  if (typmod == -1)
3689  appendStringInfoString(&result, "CHAR");
3690  else
3691  appendStringInfo(&result, "CHAR_%d", typmod - VARHDRSZ);
3692  break;
3693  case VARCHAROID:
3694  if (typmod == -1)
3695  appendStringInfoString(&result, "VARCHAR");
3696  else
3697  appendStringInfo(&result, "VARCHAR_%d", typmod - VARHDRSZ);
3698  break;
3699  case NUMERICOID:
3700  if (typmod == -1)
3701  appendStringInfoString(&result, "NUMERIC");
3702  else
3703  appendStringInfo(&result, "NUMERIC_%d_%d",
3704  ((typmod - VARHDRSZ) >> 16) & 0xffff,
3705  (typmod - VARHDRSZ) & 0xffff);
3706  break;
3707  case INT4OID:
3708  appendStringInfoString(&result, "INTEGER");
3709  break;
3710  case INT2OID:
3711  appendStringInfoString(&result, "SMALLINT");
3712  break;
3713  case INT8OID:
3714  appendStringInfoString(&result, "BIGINT");
3715  break;
3716  case FLOAT4OID:
3717  appendStringInfoString(&result, "REAL");
3718  break;
3719  case FLOAT8OID:
3720  appendStringInfoString(&result, "DOUBLE");
3721  break;
3722  case BOOLOID:
3723  appendStringInfoString(&result, "BOOLEAN");
3724  break;
3725  case TIMEOID:
3726  if (typmod == -1)
3727  appendStringInfoString(&result, "TIME");
3728  else
3729  appendStringInfo(&result, "TIME_%d", typmod);
3730  break;
3731  case TIMETZOID:
3732  if (typmod == -1)
3733  appendStringInfoString(&result, "TIME_WTZ");
3734  else
3735  appendStringInfo(&result, "TIME_WTZ_%d", typmod);
3736  break;
3737  case TIMESTAMPOID:
3738  if (typmod == -1)
3739  appendStringInfoString(&result, "TIMESTAMP");
3740  else
3741  appendStringInfo(&result, "TIMESTAMP_%d", typmod);
3742  break;
3743  case TIMESTAMPTZOID:
3744  if (typmod == -1)
3745  appendStringInfoString(&result, "TIMESTAMP_WTZ");
3746  else
3747  appendStringInfo(&result, "TIMESTAMP_WTZ_%d", typmod);
3748  break;
3749  case DATEOID:
3750  appendStringInfoString(&result, "DATE");
3751  break;
3752  case XMLOID:
3753  appendStringInfoString(&result, "XML");
3754  break;
3755  default:
3756  {
3757  HeapTuple tuple;
3758  Form_pg_type typtuple;
3759 
3760  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeoid));
3761  if (!HeapTupleIsValid(tuple))
3762  elog(ERROR, "cache lookup failed for type %u", typeoid);
3763  typtuple = (Form_pg_type) GETSTRUCT(tuple);
3764 
3765  appendStringInfoString(&result,
3766  map_multipart_sql_identifier_to_xml_name((typtuple->typtype == TYPTYPE_DOMAIN) ? "Domain" : "UDT",
3768  get_namespace_name(typtuple->typnamespace),
3769  NameStr(typtuple->typname)));
3770 
3771  ReleaseSysCache(tuple);
3772  }
3773  }
3774 
3775  return result.data;
3776 }
3777 
3778 
3779 /*
3780  * Map a collection of SQL data types to XML Schema data types; see
3781  * SQL/XML:2008 section 9.7.
3782  */
3783 static const char *
3785 {
3786  List *uniquetypes = NIL;
3787  int i;
3788  StringInfoData result;
3789  ListCell *cell0;
3790 
3791  /* extract all column types used in the set of TupleDescs */
3792  foreach(cell0, tupdesc_list)
3793  {
3794  TupleDesc tupdesc = (TupleDesc) lfirst(cell0);
3795 
3796  for (i = 0; i < tupdesc->natts; i++)
3797  {
3798  Form_pg_attribute att = TupleDescAttr(tupdesc, i);
3799 
3800  if (att->attisdropped)
3801  continue;
3802  uniquetypes = list_append_unique_oid(uniquetypes, att->atttypid);
3803  }
3804  }
3805 
3806  /* add base types of domains */
3807  foreach(cell0, uniquetypes)
3808  {
3809  Oid typid = lfirst_oid(cell0);
3810  Oid basetypid = getBaseType(typid);
3811 
3812  if (basetypid != typid)
3813  uniquetypes = list_append_unique_oid(uniquetypes, basetypid);
3814  }
3815 
3816  /* Convert to textual form */
3817  initStringInfo(&result);
3818 
3819  foreach(cell0, uniquetypes)
3820  {
3821  appendStringInfo(&result, "%s\n",
3823  -1));
3824  }
3825 
3826  return result.data;
3827 }
3828 
3829 
3830 /*
3831  * Map an SQL data type to a named XML Schema data type; see
3832  * SQL/XML:2008 sections 9.5 and 9.6.
3833  *
3834  * (The distinction between 9.5 and 9.6 is basically that 9.6 adds
3835  * a name attribute, which this function does. The name-less version
3836  * 9.5 doesn't appear to be required anywhere.)
3837  */
3838 static const char *
3840 {
3841  StringInfoData result;
3842  const char *typename = map_sql_type_to_xml_name(typeoid, typmod);
3843 
3844  initStringInfo(&result);
3845 
3846  if (typeoid == XMLOID)
3847  {
3848  appendStringInfoString(&result,
3849  "<xsd:complexType mixed=\"true\">\n"
3850  " <xsd:sequence>\n"
3851  " <xsd:any name=\"element\" minOccurs=\"0\" maxOccurs=\"unbounded\" processContents=\"skip\"/>\n"
3852  " </xsd:sequence>\n"
3853  "</xsd:complexType>\n");
3854  }
3855  else
3856  {
3857  appendStringInfo(&result,
3858  "<xsd:simpleType name=\"%s\">\n", typename);
3859 
3860  switch (typeoid)
3861  {
3862  case BPCHAROID:
3863  case VARCHAROID:
3864  case TEXTOID:
3865  appendStringInfoString(&result,
3866  " <xsd:restriction base=\"xsd:string\">\n");
3867  if (typmod != -1)
3868  appendStringInfo(&result,
3869  " <xsd:maxLength value=\"%d\"/>\n",
3870  typmod - VARHDRSZ);
3871  appendStringInfoString(&result, " </xsd:restriction>\n");
3872  break;
3873 
3874  case BYTEAOID:
3875  appendStringInfo(&result,
3876  " <xsd:restriction base=\"xsd:%s\">\n"
3877  " </xsd:restriction>\n",
3878  xmlbinary == XMLBINARY_BASE64 ? "base64Binary" : "hexBinary");
3879  break;
3880 
3881  case NUMERICOID:
3882  if (typmod != -1)
3883  appendStringInfo(&result,
3884  " <xsd:restriction base=\"xsd:decimal\">\n"
3885  " <xsd:totalDigits value=\"%d\"/>\n"
3886  " <xsd:fractionDigits value=\"%d\"/>\n"
3887  " </xsd:restriction>\n",
3888  ((typmod - VARHDRSZ) >> 16) & 0xffff,
3889  (typmod - VARHDRSZ) & 0xffff);
3890  break;
3891 
3892  case INT2OID:
3893  appendStringInfo(&result,
3894  " <xsd:restriction base=\"xsd:short\">\n"
3895  " <xsd:maxInclusive value=\"%d\"/>\n"
3896  " <xsd:minInclusive value=\"%d\"/>\n"
3897  " </xsd:restriction>\n",
3898  SHRT_MAX, SHRT_MIN);
3899  break;
3900 
3901  case INT4OID:
3902  appendStringInfo(&result,
3903  " <xsd:restriction base=\"xsd:int\">\n"
3904  " <xsd:maxInclusive value=\"%d\"/>\n"
3905  " <xsd:minInclusive value=\"%d\"/>\n"
3906  " </xsd:restriction>\n",
3907  INT_MAX, INT_MIN);
3908  break;
3909 
3910  case INT8OID:
3911  appendStringInfo(&result,
3912  " <xsd:restriction base=\"xsd:long\">\n"
3913  " <xsd:maxInclusive value=\"" INT64_FORMAT "\"/>\n"
3914  " <xsd:minInclusive value=\"" INT64_FORMAT "\"/>\n"
3915  " </xsd:restriction>\n",
3916  PG_INT64_MAX,
3917  PG_INT64_MIN);
3918  break;
3919 
3920  case FLOAT4OID:
3921  appendStringInfoString(&result,
3922  " <xsd:restriction base=\"xsd:float\"></xsd:restriction>\n");
3923  break;
3924 
3925  case FLOAT8OID:
3926  appendStringInfoString(&result,
3927  " <xsd:restriction base=\"xsd:double\"></xsd:restriction>\n");
3928  break;
3929 
3930  case BOOLOID:
3931  appendStringInfoString(&result,
3932  " <xsd:restriction base=\"xsd:boolean\"></xsd:restriction>\n");
3933  break;
3934 
3935  case TIMEOID:
3936  case TIMETZOID:
3937  {
3938  const char *tz = (typeoid == TIMETZOID ? "(\\+|-)\\p{Nd}{2}:\\p{Nd}{2}" : "");
3939 
3940  if (typmod == -1)
3941  appendStringInfo(&result,
3942  " <xsd:restriction base=\"xsd:time\">\n"
3943  " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}(.\\p{Nd}+)?%s\"/>\n"
3944  " </xsd:restriction>\n", tz);
3945  else if (typmod == 0)
3946  appendStringInfo(&result,
3947  " <xsd:restriction base=\"xsd:time\">\n"
3948  " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"
3949  " </xsd:restriction>\n", tz);
3950  else
3951  appendStringInfo(&result,
3952  " <xsd:restriction base=\"xsd:time\">\n"
3953  " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}.\\p{Nd}{%d}%s\"/>\n"
3954  " </xsd:restriction>\n", typmod - VARHDRSZ, tz);
3955  break;
3956  }
3957 
3958  case TIMESTAMPOID:
3959  case TIMESTAMPTZOID:
3960  {
3961  const char *tz = (typeoid == TIMESTAMPTZOID ? "(\\+|-)\\p{Nd}{2}:\\p{Nd}{2}" : "");
3962 
3963  if (typmod == -1)
3964  appendStringInfo(&result,
3965  " <xsd:restriction base=\"xsd:dateTime\">\n"
3966  " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}(.\\p{Nd}+)?%s\"/>\n"
3967  " </xsd:restriction>\n", tz);
3968  else if (typmod == 0)
3969  appendStringInfo(&result,
3970  " <xsd:restriction base=\"xsd:dateTime\">\n"
3971  " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"
3972  " </xsd:restriction>\n", tz);
3973  else
3974  appendStringInfo(&result,
3975  " <xsd:restriction base=\"xsd:dateTime\">\n"
3976  " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}.\\p{Nd}{%d}%s\"/>\n"
3977  " </xsd:restriction>\n", typmod - VARHDRSZ, tz);
3978  break;
3979  }
3980 
3981  case DATEOID:
3982  appendStringInfoString(&result,
3983  " <xsd:restriction base=\"xsd:date\">\n"
3984  " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}\"/>\n"
3985  " </xsd:restriction>\n");
3986  break;
3987 
3988  default:
3989  if (get_typtype(typeoid) == TYPTYPE_DOMAIN)
3990  {
3991  Oid base_typeoid;
3992  int32 base_typmod = -1;
3993 
3994  base_typeoid = getBaseTypeAndTypmod(typeoid, &base_typmod);
3995 
3996  appendStringInfo(&result,
3997  " <xsd:restriction base=\"%s\"/>\n",
3998  map_sql_type_to_xml_name(base_typeoid, base_typmod));
3999  }
4000  break;
4001  }
4002  appendStringInfoString(&result, "</xsd:simpleType>\n");
4003  }
4004 
4005  return result.data;
4006 }
4007 
4008 
4009 /*
4010  * Map an SQL row to an XML element, taking the row from the active
4011  * SPI cursor. See also SQL/XML:2008 section 9.10.
4012  */
4013 static void
4014 SPI_sql_row_to_xmlelement(uint64 rownum, StringInfo result, char *tablename,
4015  bool nulls, bool tableforest,
4016  const char *targetns, bool top_level)
4017 {
4018  int i;
4019  char *xmltn;
4020 
4021  if (tablename)
4022  xmltn = map_sql_identifier_to_xml_name(tablename, true, false);
4023  else
4024  {
4025  if (tableforest)
4026  xmltn = "row";
4027  else
4028  xmltn = "table";
4029  }
4030 
4031  if (tableforest)
4032  xmldata_root_element_start(result, xmltn, NULL, targetns, top_level);
4033  else
4034  appendStringInfoString(result, "<row>\n");
4035 
4036  for (i = 1; i <= SPI_tuptable->tupdesc->natts; i++)
4037  {
4038  char *colname;
4039  Datum colval;
4040  bool isnull;
4041 
4043  true, false);
4044  colval = SPI_getbinval(SPI_tuptable->vals[rownum],
4046  i,
4047  &isnull);
4048  if (isnull)
4049  {
4050  if (nulls)
4051  appendStringInfo(result, " <%s xsi:nil=\"true\"/>\n", colname);
4052  }
4053  else
4054  appendStringInfo(result, " <%s>%s</%s>\n",
4055  colname,
4057  SPI_gettypeid(SPI_tuptable->tupdesc, i), true),
4058  colname);
4059  }
4060 
4061  if (tableforest)
4062  {
4063  xmldata_root_element_end(result, xmltn);
4064  appendStringInfoChar(result, '\n');
4065  }
4066  else
4067  appendStringInfoString(result, "</row>\n\n");
4068 }
4069 
4070 
4071 /*
4072  * XPath related functions
4073  */
4074 
4075 #ifdef USE_LIBXML
4076 
4077 /*
4078  * Convert XML node to text.
4079  *
4080  * For attribute and text nodes, return the escaped text. For anything else,
4081  * dump the whole subtree.
4082  */
4083 static text *
4084 xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt)
4085 {
4086  xmltype *result = NULL;
4087 
4088  if (cur->type != XML_ATTRIBUTE_NODE && cur->type != XML_TEXT_NODE)
4089  {
4090  void (*volatile nodefree) (xmlNodePtr) = NULL;
4091  volatile xmlBufferPtr buf = NULL;
4092  volatile xmlNodePtr cur_copy = NULL;
4093 
4094  PG_TRY();
4095  {
4096  int bytes;
4097 
4098  buf = xmlBufferCreate();
4099  if (buf == NULL || xmlerrcxt->err_occurred)
4100  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
4101  "could not allocate xmlBuffer");
4102 
4103  /*
4104  * Produce a dump of the node that we can serialize. xmlNodeDump
4105  * does that, but the result of that function won't contain
4106  * namespace definitions from ancestor nodes, so we first do a
4107  * xmlCopyNode() which duplicates the node along with its required
4108  * namespace definitions.
4109  *
4110  * Some old libxml2 versions such as 2.7.6 produce partially
4111  * broken XML_DOCUMENT_NODE nodes (unset content field) when
4112  * copying them. xmlNodeDump of such a node works fine, but
4113  * xmlFreeNode crashes; set us up to call xmlFreeDoc instead.
4114  */
4115  cur_copy = xmlCopyNode(cur, 1);
4116  if (cur_copy == NULL || xmlerrcxt->err_occurred)
4117  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
4118  "could not copy node");
4119  nodefree = (cur_copy->type == XML_DOCUMENT_NODE) ?
4120  (void (*) (xmlNodePtr)) xmlFreeDoc : xmlFreeNode;
4121 
4122  bytes = xmlNodeDump(buf, NULL, cur_copy, 0, 0);
4123  if (bytes == -1 || xmlerrcxt->err_occurred)
4124  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
4125  "could not dump node");
4126 
4127  result = xmlBuffer_to_xmltype(buf);
4128  }
4129  PG_FINALLY();
4130  {
4131  if (nodefree)
4132  nodefree(cur_copy);
4133  if (buf)
4134  xmlBufferFree(buf);
4135  }
4136  PG_END_TRY();
4137  }
4138  else
4139  {
4140  xmlChar *str;
4141 
4142  str = xmlXPathCastNodeToString(cur);
4143  PG_TRY();
4144  {
4145  /* Here we rely on XML having the same representation as TEXT */
4146  char *escaped = escape_xml((char *) str);
4147 
4148  result = (xmltype *) cstring_to_text(escaped);
4149  pfree(escaped);
4150  }
4151  PG_FINALLY();
4152  {
4153  xmlFree(str);
4154  }
4155  PG_END_TRY();
4156  }
4157 
4158  return result;
4159 }
4160 
4161 /*
4162  * Convert an XML XPath object (the result of evaluating an XPath expression)
4163  * to an array of xml values, which are appended to astate. The function
4164  * result value is the number of elements in the array.
4165  *
4166  * If "astate" is NULL then we don't generate the array value, but we still
4167  * return the number of elements it would have had.
4168  *
4169  * Nodesets are converted to an array containing the nodes' textual
4170  * representations. Primitive values (float, double, string) are converted
4171  * to a single-element array containing the value's string representation.
4172  */
4173 static int
4174 xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
4175  ArrayBuildState *astate,
4176  PgXmlErrorContext *xmlerrcxt)
4177 {
4178  int result = 0;
4179  Datum datum;
4180  Oid datumtype;
4181  char *result_str;
4182 
4183  switch (xpathobj->type)
4184  {
4185  case XPATH_NODESET:
4186  if (xpathobj->nodesetval != NULL)
4187  {
4188  result = xpathobj->nodesetval->nodeNr;
4189  if (astate != NULL)
4190  {
4191  int i;
4192 
4193  for (i = 0; i < result; i++)
4194  {
4195  datum = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],
4196  xmlerrcxt));
4197  (void) accumArrayResult(astate, datum, false,
4198  XMLOID, CurrentMemoryContext);
4199  }
4200  }
4201  }
4202  return result;
4203 
4204  case XPATH_BOOLEAN:
4205  if (astate == NULL)
4206  return 1;
4207  datum = BoolGetDatum(xpathobj->boolval);
4208  datumtype = BOOLOID;
4209  break;
4210 
4211  case XPATH_NUMBER:
4212  if (astate == NULL)
4213  return 1;
4214  datum = Float8GetDatum(xpathobj->floatval);
4215  datumtype = FLOAT8OID;
4216  break;
4217 
4218  case XPATH_STRING:
4219  if (astate == NULL)
4220  return 1;
4221  datum = CStringGetDatum((char *) xpathobj->stringval);
4222  datumtype = CSTRINGOID;
4223  break;
4224 
4225  default:
4226  elog(ERROR, "xpath expression result type %d is unsupported",
4227  xpathobj->type);
4228  return 0; /* keep compiler quiet */
4229  }
4230 
4231  /* Common code for scalar-value cases */
4232  result_str = map_sql_value_to_xml_value(datum, datumtype, true);
4233  datum = PointerGetDatum(cstring_to_xmltype(result_str));
4234  (void) accumArrayResult(astate, datum, false,
4235  XMLOID, CurrentMemoryContext);
4236  return 1;
4237 }
4238 
4239 
4240 /*
4241  * Common code for xpath() and xmlexists()
4242  *
4243  * Evaluate XPath expression and return number of nodes in res_nitems
4244  * and array of XML values in astate. Either of those pointers can be
4245  * NULL if the corresponding result isn't wanted.
4246  *
4247  * It is up to the user to ensure that the XML passed is in fact
4248  * an XML document - XPath doesn't work easily on fragments without
4249  * a context node being known.
4250  */
4251 static void
4252 xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
4253  int *res_nitems, ArrayBuildState *astate)
4254 {
4255  PgXmlErrorContext *xmlerrcxt;
4256  volatile xmlParserCtxtPtr ctxt = NULL;
4257  volatile xmlDocPtr doc = NULL;
4258  volatile xmlXPathContextPtr xpathctx = NULL;
4259  volatile xmlXPathCompExprPtr xpathcomp = NULL;
4260  volatile xmlXPathObjectPtr xpathobj = NULL;
4261  char *datastr;
4262  int32 len;
4263  int32 xpath_len;
4264  xmlChar *string;
4265  xmlChar *xpath_expr;
4266  size_t xmldecl_len = 0;
4267  int i;
4268  int ndim;
4269  Datum *ns_names_uris;
4270  bool *ns_names_uris_nulls;
4271  int ns_count;
4272 
4273  /*
4274  * Namespace mappings are passed as text[]. If an empty array is passed
4275  * (ndim = 0, "0-dimensional"), then there are no namespace mappings.
4276  * Else, a 2-dimensional array with length of the second axis being equal
4277  * to 2 should be passed, i.e., every subarray contains 2 elements, the
4278  * first element defining the name, the second one the URI. Example:
4279  * ARRAY[ARRAY['myns', 'http://example.com'], ARRAY['myns2',
4280  * 'http://example2.com']].
4281  */
4282  ndim = namespaces ? ARR_NDIM(namespaces) : 0;
4283  if (ndim != 0)
4284  {
4285  int *dims;
4286 
4287  dims = ARR_DIMS(namespaces);
4288 
4289  if (ndim != 2 || dims[1] != 2)
4290  ereport(ERROR,
4291  (errcode(ERRCODE_DATA_EXCEPTION),
4292  errmsg("invalid array for XML namespace mapping"),
4293  errdetail("The array must be two-dimensional with length of the second axis equal to 2.")));
4294 
4295  Assert(ARR_ELEMTYPE(namespaces) == TEXTOID);
4296 
4297  deconstruct_array_builtin(namespaces, TEXTOID,
4298  &ns_names_uris, &ns_names_uris_nulls,
4299  &ns_count);
4300 
4301  Assert((ns_count % 2) == 0); /* checked above */
4302  ns_count /= 2; /* count pairs only */
4303  }
4304  else
4305  {
4306  ns_names_uris = NULL;
4307  ns_names_uris_nulls = NULL;
4308  ns_count = 0;
4309  }
4310 
4311  datastr = VARDATA(data);
4312  len = VARSIZE(data) - VARHDRSZ;
4313  xpath_len = VARSIZE_ANY_EXHDR(xpath_expr_text);
4314  if (xpath_len == 0)
4315  ereport(ERROR,
4316  (errcode(ERRCODE_DATA_EXCEPTION),
4317  errmsg("empty XPath expression")));
4318 
4319  string = pg_xmlCharStrndup(datastr, len);
4320  xpath_expr = pg_xmlCharStrndup(VARDATA_ANY(xpath_expr_text), xpath_len);
4321 
4322  /*
4323  * In a UTF8 database, skip any xml declaration, which might assert
4324  * another encoding. Ignore parse_xml_decl() failure, letting
4325  * xmlCtxtReadMemory() report parse errors. Documentation disclaims
4326  * xpath() support for non-ASCII data in non-UTF8 databases, so leave
4327  * those scenarios bug-compatible with historical behavior.
4328  */
4329  if (GetDatabaseEncoding() == PG_UTF8)
4330  parse_xml_decl(string, &xmldecl_len, NULL, NULL, NULL);
4331 
4332  xmlerrcxt = pg_xml_init(PG_XML_STRICTNESS_ALL);
4333 
4334  PG_TRY();
4335  {
4336  xmlInitParser();
4337 
4338  /*
4339  * redundant XML parsing (two parsings for the same value during one
4340  * command execution are possible)
4341  */
4342  ctxt = xmlNewParserCtxt();
4343  if (ctxt == NULL || xmlerrcxt->err_occurred)
4344  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
4345  "could not allocate parser context");
4346  doc = xmlCtxtReadMemory(ctxt, (char *) string + xmldecl_len,
4347  len - xmldecl_len, NULL, NULL, 0);
4348  if (doc == NULL || xmlerrcxt->err_occurred)
4349  xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
4350  "could not parse XML document");
4351  xpathctx = xmlXPathNewContext(doc);
4352  if (xpathctx == NULL || xmlerrcxt->err_occurred)
4353  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
4354  "could not allocate XPath context");
4355  xpathctx->node = (xmlNodePtr) doc;
4356 
4357  /* register namespaces, if any */
4358  if (ns_count > 0)
4359  {
4360  for (i = 0; i < ns_count; i++)
4361  {
4362  char *ns_name;
4363  char *ns_uri;
4364 
4365  if (ns_names_uris_nulls[i * 2] ||
4366  ns_names_uris_nulls[i * 2 + 1])
4367  ereport(ERROR,
4368  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4369  errmsg("neither namespace name nor URI may be null")));
4370  ns_name = TextDatumGetCString(ns_names_uris[i * 2]);
4371  ns_uri = TextDatumGetCString(ns_names_uris[i * 2 + 1]);
4372  if (xmlXPathRegisterNs(xpathctx,
4373  (xmlChar *) ns_name,
4374  (xmlChar *) ns_uri) != 0)
4375  ereport(ERROR, /* is this an internal error??? */
4376  (errmsg("could not register XML namespace with name \"%s\" and URI \"%s\"",
4377  ns_name, ns_uri)));
4378  }
4379  }
4380 
4381  xpathcomp = xmlXPathCompile(xpath_expr);
4382  if (xpathcomp == NULL || xmlerrcxt->err_occurred)
4383  xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
4384  "invalid XPath expression");
4385 
4386  /*
4387  * Version 2.6.27 introduces a function named
4388  * xmlXPathCompiledEvalToBoolean, which would be enough for xmlexists,
4389  * but we can derive the existence by whether any nodes are returned,
4390  * thereby preventing a library version upgrade and keeping the code
4391  * the same.
4392  */
4393  xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
4394  if (xpathobj == NULL || xmlerrcxt->err_occurred)
4395  xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
4396  "could not create XPath object");
4397 
4398  /*
4399  * Extract the results as requested.
4400  */
4401  if (res_nitems != NULL)
4402  *res_nitems = xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);
4403  else
4404  (void) xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);
4405  }
4406  PG_CATCH();
4407  {
4408  if (xpathobj)
4409  xmlXPathFreeObject(xpathobj);
4410  if (xpathcomp)
4411  xmlXPathFreeCompExpr(xpathcomp);
4412  if (xpathctx)
4413  xmlXPathFreeContext(xpathctx);
4414  if (doc)
4415  xmlFreeDoc(doc);
4416  if (ctxt)
4417  xmlFreeParserCtxt(ctxt);
4418 
4419  pg_xml_done(xmlerrcxt, true);
4420 
4421  PG_RE_THROW();
4422  }
4423  PG_END_TRY();
4424 
4425  xmlXPathFreeObject(xpathobj);
4426  xmlXPathFreeCompExpr(xpathcomp);
4427  xmlXPathFreeContext(xpathctx);
4428  xmlFreeDoc(doc);
4429  xmlFreeParserCtxt(ctxt);
4430 
4431  pg_xml_done(xmlerrcxt, false);
4432 }
4433 #endif /* USE_LIBXML */
4434 
4435 /*
4436  * Evaluate XPath expression and return array of XML values.
4437  *
4438  * As we have no support of XQuery sequences yet, this function seems
4439  * to be the most useful one (array of XML functions plays a role of
4440  * some kind of substitution for XQuery sequences).
4441  */
4442 Datum
4444 {
4445 #ifdef USE_LIBXML
4446  text *xpath_expr_text = PG_GETARG_TEXT_PP(0);
4448  ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
4449  ArrayBuildState *astate;
4450 
4451  astate = initArrayResult(XMLOID, CurrentMemoryContext, true);
4452  xpath_internal(xpath_expr_text, data, namespaces,
4453  NULL, astate);
4455 #else
4456  NO_XML_SUPPORT();
4457  return 0;
4458 #endif
4459 }
4460 
4461 /*
4462  * Determines if the node specified by the supplied XPath exists
4463  * in a given XML document, returning a boolean.
4464  */
4465 Datum
4467 {
4468 #ifdef USE_LIBXML
4469  text *xpath_expr_text = PG_GETARG_TEXT_PP(0);
4471  int res_nitems;
4472 
4473  xpath_internal(xpath_expr_text, data, NULL,
4474  &res_nitems, NULL);
4475 
4476  PG_RETURN_BOOL(res_nitems > 0);
4477 #else
4478  NO_XML_SUPPORT();
4479  return 0;
4480 #endif
4481 }
4482 
4483 /*
4484  * Determines if the node specified by the supplied XPath exists
4485  * in a given XML document, returning a boolean. Differs from
4486  * xmlexists as it supports namespaces and is not defined in SQL/XML.
4487  */
4488 Datum
4490 {
4491 #ifdef USE_LIBXML
4492  text *xpath_expr_text = PG_GETARG_TEXT_PP(0);
4494  ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
4495  int res_nitems;
4496 
4497  xpath_internal(xpath_expr_text, data, namespaces,
4498  &res_nitems, NULL);
4499 
4500  PG_RETURN_BOOL(res_nitems > 0);
4501 #else
4502  NO_XML_SUPPORT();
4503  return 0;
4504 #endif
4505 }
4506 
4507 /*
4508  * Functions for checking well-formed-ness
4509  */
4510 
4511 #ifdef USE_LIBXML
4512 static bool
4513 wellformed_xml(text *data, XmlOptionType xmloption_arg)
4514 {
4515  xmlDocPtr doc;
4516  ErrorSaveContext escontext = {T_ErrorSaveContext};
4517 
4518  /*
4519  * We'll report "true" if no soft error is reported by xml_parse().
4520  */
4521  doc = xml_parse(data, xmloption_arg, true,
4522  GetDatabaseEncoding(), NULL, NULL, (Node *) &escontext);
4523  if (doc)
4524  xmlFreeDoc(doc);
4525 
4526  return !escontext.error_occurred;
4527 }
4528 #endif
4529 
4530 Datum
4532 {
4533 #ifdef USE_LIBXML
4534  text *data = PG_GETARG_TEXT_PP(0);
4535 
4536  PG_RETURN_BOOL(wellformed_xml(data, xmloption));
4537 #else
4538  NO_XML_SUPPORT();
4539  return 0;
4540 #endif /* not USE_LIBXML */
4541 }
4542 
4543 Datum
4545 {
4546 #ifdef USE_LIBXML
4547  text *data = PG_GETARG_TEXT_PP(0);
4548 
4549  PG_RETURN_BOOL(wellformed_xml(data, XMLOPTION_DOCUMENT));
4550 #else
4551  NO_XML_SUPPORT();
4552  return 0;
4553 #endif /* not USE_LIBXML */
4554 }
4555 
4556 Datum
4558 {
4559 #ifdef USE_LIBXML
4560  text *data = PG_GETARG_TEXT_PP(0);
4561 
4562  PG_RETURN_BOOL(wellformed_xml(data, XMLOPTION_CONTENT));
4563 #else
4564  NO_XML_SUPPORT();
4565  return 0;
4566 #endif /* not USE_LIBXML */
4567 }
4568 
4569 /*
4570  * support functions for XMLTABLE
4571  *
4572  */
4573 #ifdef USE_LIBXML
4574 
4575 /*
4576  * Returns private data from executor state. Ensure validity by check with
4577  * MAGIC number.
4578  */
4579 static inline XmlTableBuilderData *
4580 GetXmlTableBuilderPrivateData(TableFuncScanState *state, const char *fname)
4581 {
4582  XmlTableBuilderData *result;
4583 
4584  if (!IsA(state, TableFuncScanState))
4585  elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4586  result = (XmlTableBuilderData *) state->opaque;
4587  if (result->magic != XMLTABLE_CONTEXT_MAGIC)
4588  elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4589 
4590  return result;
4591 }
4592 #endif
4593 
4594 /*
4595  * XmlTableInitOpaque
4596  * Fill in TableFuncScanState->opaque for XmlTable processor; initialize
4597  * the XML parser.
4598  *
4599  * Note: Because we call pg_xml_init() here and pg_xml_done() in
4600  * XmlTableDestroyOpaque, it is critical for robustness that no other
4601  * executor nodes run until this node is processed to completion. Caller
4602  * must execute this to completion (probably filling a tuplestore to exhaust
4603  * this node in a single pass) instead of using row-per-call mode.
4604  */
4605 static void
4607 {
4608 #ifdef USE_LIBXML
4609  volatile xmlParserCtxtPtr ctxt = NULL;
4610  XmlTableBuilderData *xtCxt;
4611  PgXmlErrorContext *xmlerrcxt;
4612 
4613  xtCxt = palloc0(sizeof(XmlTableBuilderData));
4614  xtCxt->magic = XMLTABLE_CONTEXT_MAGIC;
4615  xtCxt->natts = natts;
4616  xtCxt->xpathscomp = palloc0(sizeof(xmlXPathCompExprPtr) * natts);
4617 
4618  xmlerrcxt = pg_xml_init(PG_XML_STRICTNESS_ALL);
4619 
4620  PG_TRY();
4621  {
4622  xmlInitParser();
4623 
4624  ctxt = xmlNewParserCtxt();
4625  if (ctxt == NULL || xmlerrcxt->err_occurred)
4626  xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
4627  "could not allocate parser context");
4628  }
4629  PG_CATCH();
4630  {
4631  if (ctxt != NULL)
4632  xmlFreeParserCtxt(ctxt);
4633 
4634  pg_xml_done(xmlerrcxt, true);
4635 
4636  PG_RE_THROW();
4637  }
4638  PG_END_TRY();
4639 
4640  xtCxt->xmlerrcxt = xmlerrcxt;
4641  xtCxt->ctxt = ctxt;
4642 
4643  state->opaque = xtCxt;
4644 #else
4645  NO_XML_SUPPORT();
4646 #endif /* not USE_LIBXML */
4647 }
4648 
4649 /*
4650  * XmlTableSetDocument
4651  * Install the input document
4652  */
4653 static void
4655 {
4656 #ifdef USE_LIBXML
4657  XmlTableBuilderData *xtCxt;
4658  xmltype *xmlval = DatumGetXmlP(value);
4659  char *str;
4660  xmlChar *xstr;
4661  int length;
4662  volatile xmlDocPtr doc = NULL;
4663  volatile xmlXPathContextPtr xpathcxt = NULL;
4664 
4665  xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetDocument");
4666 
4667  /*
4668  * Use out function for casting to string (remove encoding property). See
4669  * comment in xml_out.
4670  */
4671  str = xml_out_internal(xmlval, 0);
4672 
4673  length = strlen(str);
4674  xstr = pg_xmlCharStrndup(str, length);
4675 
4676  PG_TRY();
4677  {
4678  doc = xmlCtxtReadMemory(xtCxt->ctxt, (char *) xstr, length, NULL, NULL, 0);
4679  if (doc == NULL || xtCxt->xmlerrcxt->err_occurred)
4680  xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
4681  "could not parse XML document");
4682  xpathcxt = xmlXPathNewContext(doc);
4683  if (xpathcxt == NULL || xtCxt->xmlerrcxt->err_occurred)
4684  xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
4685  "could not allocate XPath context");
4686  xpathcxt->node = (xmlNodePtr) doc;
4687  }
4688  PG_CATCH();
4689  {
4690  if (xpathcxt != NULL)
4691  xmlXPathFreeContext(xpathcxt);
4692  if (doc != NULL)
4693  xmlFreeDoc(doc);
4694 
4695  PG_RE_THROW();
4696  }
4697  PG_END_TRY();
4698 
4699  xtCxt->doc = doc;
4700  xtCxt->xpathcxt = xpathcxt;
4701 #else
4702  NO_XML_SUPPORT();
4703 #endif /* not USE_LIBXML */
4704 }
4705 
4706 /*
4707  * XmlTableSetNamespace
4708  * Add a namespace declaration
4709  */
4710 static void
4711 XmlTableSetNamespace(TableFuncScanState *state, const char *name, const char *uri)
4712 {
4713 #ifdef USE_LIBXML
4714  XmlTableBuilderData *xtCxt;
4715 
4716  if (name == NULL)
4717  ereport(ERROR,
4718  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4719  errmsg("DEFAULT namespace is not supported")));
4720  xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetNamespace");
4721 
4722  if (xmlXPathRegisterNs(xtCxt->xpathcxt,
4723  pg_xmlCharStrndup(name, strlen(name)),
4724  pg_xmlCharStrndup(uri, strlen(uri))))
4725  xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_DATA_EXCEPTION,
4726  "could not set XML namespace");
4727 #else
4728  NO_XML_SUPPORT();
4729 #endif /* not USE_LIBXML */
4730 }
4731 
4732 /*
4733  * XmlTableSetRowFilter
4734  * Install the row-filter Xpath expression.
4735  */
4736 static void
4738 {
4739 #ifdef USE_LIBXML
4740  XmlTableBuilderData *xtCxt;
4741  xmlChar *xstr;
4742 
4743  xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetRowFilter");
4744 
4745  if (*path == '\0')
4746  ereport(ERROR,
4747  (errcode(ERRCODE_DATA_EXCEPTION),
4748  errmsg("row path filter must not be empty string")));
4749 
4750  xstr = pg_xmlCharStrndup(path, strlen(path));
4751 
4752  xtCxt->xpathcomp = xmlXPathCompile(xstr);
4753  if (xtCxt->xpathcomp == NULL || xtCxt->xmlerrcxt->err_occurred)
4754  xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_SYNTAX_ERROR,
4755  "invalid XPath expression");
4756 #else
4757  NO_XML_SUPPORT();
4758 #endif /* not USE_LIBXML */
4759 }
4760 
4761 /*
4762  * XmlTableSetColumnFilter
4763  * Install the column-filter Xpath expression, for the given column.
4764  */
4765 static void
4766 XmlTableSetColumnFilter(TableFuncScanState *state, const char *path, int colnum)
4767 {
4768 #ifdef USE_LIBXML
4769  XmlTableBuilderData *xtCxt;
4770  xmlChar *xstr;
4771 
4772  Assert(PointerIsValid(path));
4773 
4774  xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetColumnFilter");
4775 
4776  if (*path == '\0')
4777  ereport(ERROR,
4778  (errcode(ERRCODE_DATA_EXCEPTION),
4779  errmsg("column path filter must not be empty string")));
4780 
4781  xstr = pg_xmlCharStrndup(path, strlen(path));
4782 
4783  xtCxt->xpathscomp[colnum] = xmlXPathCompile(xstr);
4784  if (xtCxt->xpathscomp[colnum] == NULL || xtCxt->xmlerrcxt->err_occurred)
4785  xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_DATA_EXCEPTION,
4786  "invalid XPath expression");
4787 #else
4788  NO_XML_SUPPORT();
4789 #endif /* not USE_LIBXML */
4790 }
4791 
4792 /*
4793  * XmlTableFetchRow
4794  * Prepare the next "current" tuple for upcoming GetValue calls.
4795  * Returns false if the row-filter expression returned no more rows.
4796  */
4797 static bool
4799 {
4800 #ifdef USE_LIBXML
4801  XmlTableBuilderData *xtCxt;
4802 
4803  xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableFetchRow");
4804 
4805  /* Propagate our own error context to libxml2 */
4806  xmlSetStructuredErrorFunc((void *) xtCxt->xmlerrcxt, xml_errorHandler);
4807 
4808  if (xtCxt->xpathobj == NULL)
4809  {
4810  xtCxt->xpathobj = xmlXPathCompiledEval(xtCxt->xpathcomp, xtCxt->xpathcxt);
4811  if (xtCxt->xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)
4812  xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
4813  "could not create XPath object");
4814 
4815  xtCxt->row_count = 0;
4816  }
4817 
4818  if (xtCxt->xpathobj->type == XPATH_NODESET)
4819  {
4820  if (xtCxt->xpathobj->nodesetval != NULL)
4821  {
4822  if (xtCxt->row_count++ < xtCxt->xpathobj->nodesetval->nodeNr)
4823  return true;
4824  }
4825  }
4826 
4827  return false;
4828 #else
4829  NO_XML_SUPPORT();
4830  return false;
4831 #endif /* not USE_LIBXML */
4832 }
4833 
4834 /*
4835  * XmlTableGetValue
4836  * Return the value for column number 'colnum' for the current row. If
4837  * column -1 is requested, return representation of the whole row.
4838  *
4839  * This leaks memory, so be sure to reset often the context in which it's
4840  * called.
4841  */
4842 static Datum
4844  Oid typid, int32 typmod, bool *isnull)
4845 {
4846 #ifdef USE_LIBXML
4847  XmlTableBuilderData *xtCxt;
4848  Datum result = (Datum) 0;
4849  xmlNodePtr cur;
4850  char *cstr = NULL;
4851  volatile xmlXPathObjectPtr xpathobj = NULL;
4852 
4853  xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableGetValue");
4854 
4855  Assert(xtCxt->xpathobj &&
4856  xtCxt->xpathobj->type == XPATH_NODESET &&
4857  xtCxt->xpathobj->nodesetval != NULL);
4858 
4859  /* Propagate our own error context to libxml2 */
4860  xmlSetStructuredErrorFunc((void *) xtCxt->xmlerrcxt, xml_errorHandler);
4861 
4862  *isnull = false;
4863 
4864  cur = xtCxt->xpathobj->nodesetval->nodeTab[xtCxt->row_count - 1];
4865 
4866  Assert(xtCxt->xpathscomp[colnum] != NULL);
4867 
4868  PG_TRY();
4869  {
4870  /* Set current node as entry point for XPath evaluation */
4871  xtCxt->xpathcxt->node = cur;
4872 
4873  /* Evaluate column path */
4874  xpathobj = xmlXPathCompiledEval(xtCxt->xpathscomp[colnum], xtCxt->xpathcxt);
4875  if (xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)
4876  xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
4877  "could not create XPath object");
4878 
4879  /*
4880  * There are four possible cases, depending on the number of nodes
4881  * returned by the XPath expression and the type of the target column:
4882  * a) XPath returns no nodes. b) The target type is XML (return all
4883  * as XML). For non-XML return types: c) One node (return content).
4884  * d) Multiple nodes (error).
4885  */
4886  if (xpathobj->type == XPATH_NODESET)
4887  {
4888  int count = 0;
4889 
4890  if (xpathobj->nodesetval != NULL)
4891  count = xpathobj->nodesetval->nodeNr;
4892 
4893  if (xpathobj->nodesetval == NULL || count == 0)
4894  {
4895  *isnull = true;
4896  }
4897  else
4898  {
4899  if (typid == XMLOID)
4900  {
4901  text *textstr;
4903 
4904  /* Concatenate serialized values */
4905  initStringInfo(&str);
4906  for (int i = 0; i < count; i++)
4907  {
4908  textstr =
4909  xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],
4910  xtCxt->xmlerrcxt);
4911 
4912  appendStringInfoText(&str, textstr);
4913  }
4914  cstr = str.data;
4915  }
4916  else
4917  {
4918  xmlChar *str;
4919 
4920  if (count > 1)
4921  ereport(ERROR,
4922  (errcode(ERRCODE_CARDINALITY_VIOLATION),
4923  errmsg("more than one value returned by column XPath expression")));
4924 
4925  str = xmlXPathCastNodeSetToString(xpathobj->nodesetval);
4926  cstr = str ? xml_pstrdup_and_free(str) : "";
4927  }
4928  }
4929  }
4930  else if (xpathobj->type == XPATH_STRING)
4931  {
4932  /* Content should be escaped when target will be XML */
4933  if (typid == XMLOID)
4934  cstr = escape_xml((char *) xpathobj->stringval);
4935  else
4936  cstr = (char *) xpathobj->stringval;
4937  }
4938  else if (xpathobj->type == XPATH_BOOLEAN)
4939  {
4940  char typcategory;
4941  bool typispreferred;
4942  xmlChar *str;
4943 
4944  /* Allow implicit casting from boolean to numbers */
4945  get_type_category_preferred(typid, &typcategory, &typispreferred);
4946 
4947  if (typcategory != TYPCATEGORY_NUMERIC)
4948  str = xmlXPathCastBooleanToString(xpathobj->boolval);
4949  else
4950  str = xmlXPathCastNumberToString(xmlXPathCastBooleanToNumber(xpathobj->boolval));
4951 
4952  cstr = xml_pstrdup_and_free(str);
4953  }
4954  else if (xpathobj->type == XPATH_NUMBER)
4955  {
4956  xmlChar *str;
4957 
4958  str = xmlXPathCastNumberToString(xpathobj->floatval);
4959  cstr = xml_pstrdup_and_free(str);
4960  }
4961  else
4962  elog(ERROR, "unexpected XPath object type %u", xpathobj->type);
4963 
4964  /*
4965  * By here, either cstr contains the result value, or the isnull flag
4966  * has been set.
4967  */
4968  Assert(cstr || *isnull);
4969 
4970  if (!*isnull)
4971  result = InputFunctionCall(&state->in_functions[colnum],
4972  cstr,
4973  state->typioparams[colnum],
4974  typmod);
4975  }
4976  PG_FINALLY();
4977  {
4978  if (xpathobj != NULL)
4979  xmlXPathFreeObject(xpathobj);
4980  }
4981  PG_END_TRY();
4982 
4983  return result;
4984 #else
4985  NO_XML_SUPPORT();
4986  return 0;
4987 #endif /* not USE_LIBXML */
4988 }
4989 
4990 /*
4991  * XmlTableDestroyOpaque
4992  * Release all libxml2 resources
4993  */
4994 static void
4996 {
4997 #ifdef USE_LIBXML
4998  XmlTableBuilderData *xtCxt;
4999 
5000  xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableDestroyOpaque");
5001 
5002  /* Propagate our own error context to libxml2 */
5003  xmlSetStructuredErrorFunc((void *) xtCxt->xmlerrcxt, xml_errorHandler);
5004 
5005  if (xtCxt->xpathscomp != NULL)
5006  {
5007  int i;
5008 
5009  for (i = 0; i < xtCxt->natts; i++)
5010  if (xtCxt->xpathscomp[i] != NULL)
5011  xmlXPathFreeCompExpr(xtCxt->xpathscomp[i]);
5012  }
5013 
5014  if (xtCxt->xpathobj != NULL)
5015  xmlXPathFreeObject(xtCxt->xpathobj);
5016  if (xtCxt->xpathcomp != NULL)
5017  xmlXPathFreeCompExpr(xtCxt->xpathcomp);
5018  if (xtCxt->xpathcxt != NULL)
5019  xmlXPathFreeContext(xtCxt->xpathcxt);
5020  if (xtCxt->doc != NULL)
5021  xmlFreeDoc(xtCxt->doc);
5022  if (xtCxt->ctxt != NULL)
5023  xmlFreeParserCtxt(xtCxt->ctxt);
5024 
5025  pg_xml_done(xtCxt->xmlerrcxt, true);
5026 
5027  /* not valid anymore */
5028  xtCxt->magic = 0;
5029  state->opaque = NULL;
5030 
5031 #else
5032  NO_XML_SUPPORT();
5033 #endif /* not USE_LIBXML */
5034 }
#define ARR_NDIM(a)
Definition: array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5332
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5275
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3613
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3679
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5402
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:313
void EncodeDateTime(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
Definition: datetime.c:4257
void EncodeDateOnly(struct pg_tm *tm, int style, char *str)
Definition: datetime.c:4142
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1896
#define TextDatumGetCString(d)
Definition: builtins.h:95
#define NameStr(name)
Definition: c.h:735
signed short int16
Definition: c.h:482
signed int int32
Definition: c.h:483
#define gettext_noop(x)
Definition: c.h:1209
#define INT64_FORMAT
Definition: c.h:537
#define VARHDRSZ
Definition: c.h:681
#define PointerIsValid(pointer)
Definition: c.h:752
#define CppAsString2(x)
Definition: c.h:316
#define PG_INT64_MAX
Definition: c.h:581
#define PG_INT64_MIN
Definition: c.h:580
#define OidIsValid(objectId)
Definition: c.h:764
int nspid
int64 Timestamp
Definition: timestamp.h:38
int64 TimestampTz
Definition: timestamp.h:39
int32 fsec_t
Definition: timestamp.h:41
#define TIMESTAMP_NOT_FINITE(j)
Definition: timestamp.h:169
#define POSTGRES_EPOCH_JDATE
Definition: timestamp.h:235
#define DATE_NOT_FINITE(j)
Definition: date.h:43
int32 DateADT
Definition: date.h:23
static DateADT DatumGetDateADT(Datum X)
Definition: date.h:54
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3089
struct cursor * cur
Definition: ecpg.c:28
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1156
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1229
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errhint(const char *fmt,...)
Definition: elog.c:1316
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 errsave(context,...)
Definition: elog.h:260
#define FATAL
Definition: elog.h:41
#define PG_TRY(...)
Definition: elog.h:370
#define WARNING
Definition: elog.h:36
#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 PG_FINALLY(...)
Definition: elog.h:387
#define ereport(elevel,...)
Definition: elog.h:149
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1513
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1799
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1746
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define DatumGetByteaPP(X)
Definition: fmgr.h:291
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_NAME(n)
Definition: fmgr.h:278
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
Oid MyDatabaseId
Definition: globals.c:89
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define MAXDATELEN
Definition: datetime.h:200
#define ident
Definition: indent_codes.h:47
#define newline
Definition: indent_codes.h:35
FILE * input
static struct @148 value
int b
Definition: isn.c:70
int x
Definition: isn.c:71
int a
Definition: isn.c:69
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1379
static struct pg_tm tm
Definition: localtime.c:104
#define NoLock
Definition: lockdefs.h:34
#define AccessShareLock
Definition: lockdefs.h:36
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3348
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2889
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2253
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1932
char get_typtype(Oid typid)
Definition: lsyscache.c:2611
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2520
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2503
void get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
Definition: lsyscache.c:2692
#define type_is_array_domain(typid)
Definition: lsyscache.h:209
unsigned int pg_wchar
Definition: mbprint.c:31
unsigned char * pg_do_encoding_conversion(unsigned char *src, int len, int src_encoding, int dest_encoding)
Definition: mbutils.c:357
char * pg_any_to_server(const char *s, int len, int encoding)
Definition: mbutils.c:677
int GetDatabaseEncoding(void)
Definition: mbutils.c:1268
void pg_unicode_to_server(pg_wchar c, unsigned char *s)
Definition: mbutils.c:865
int pg_get_client_encoding(void)
Definition: mbutils.c:337
int pg_encoding_mb2wchar_with_len(int encoding, const char *from, pg_wchar *to, int len)
Definition: mbutils.c:994
char * pg_server_to_any(const char *s, int len, int encoding)
Definition: mbutils.c:750
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1024
char * pstrdup(const char *in)
Definition: mcxt.c:1644
void pfree(void *pointer)
Definition: mcxt.c:1456
MemoryContext TopMemoryContext
Definition: mcxt.c:141
void * palloc0(Size size)
Definition: mcxt.c:1257
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1476
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1021
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1631
void * palloc(Size size)
Definition: mcxt.c:1226
#define AllocSetContextCreate
Definition: memutils.h:126
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:150
#define USE_XSD_DATES
Definition: miscadmin.h:235
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:3326
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
void * arg
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
const void size_t len
const void * data
int32 encoding
Definition: pg_database.h:41
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
#define list_make1(x1)
Definition: pg_list.h:212
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define list_make2(x1, x2)
Definition: pg_list.h:214
#define plan(x)
Definition: pg_regress.c:162
static char * buf
Definition: pg_test_fsync.c:73
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
#define MAX_MULTIBYTE_CHAR_LEN
Definition: pg_wchar.h:35
pg_enc
Definition: pg_wchar.h:228
@ PG_UTF8
Definition: pg_wchar.h:235
#define MAX_UNICODE_EQUIVALENT_STRING
Definition: pg_wchar.h:332
#define pg_encoding_to_char
Definition: pg_wchar.h:563
#define pg_char_to_encoding
Definition: pg_wchar.h:562
long date
Definition: pgtypes_date.h:9
int64 timestamp
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
size_t strnlen(const char *str, size_t maxlen)
Definition: strnlen.c:26
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static char * DatumGetCString(Datum X)
Definition: postgres.h:335
uintptr_t Datum
Definition: postgres.h:64
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
void pq_sendtext(StringInfo buf, const char *str, int slen)
Definition: pqformat.c:175
const char * pq_getmsgbytes(StringInfo msg, int datalen)
Definition: pqformat.c:511
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:329
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:349
char * c
e
Definition: preproc-init.c:82
char string[11]
Definition: preproc-type.c:52
XmlOptionType
Definition: primnodes.h:1526
@ XMLOPTION_CONTENT
Definition: primnodes.h:1528
@ XMLOPTION_DOCUMENT
Definition: primnodes.h:1527
Datum regclassout(PG_FUNCTION_ARGS)
Definition: regproc.c:943
uint64 SPI_processed
Definition: spi.c:45
Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)
Definition: spi.c:1306
SPITupleTable * SPI_tuptable
Definition: spi.c:46
Portal SPI_cursor_find(const char *name)
Definition: spi.c:1792
int SPI_connect(void)
Definition: spi.c:95
const char * SPI_result_code_string(int code)
Definition: spi.c:1970
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1804
int SPI_finish(void)
Definition: spi.c:183
Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)
Definition: spi.c:1443
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:858
void SPI_cursor_close(Portal portal)
Definition: spi.c:1860
void * SPI_palloc(Size size)
Definition: spi.c:1336
char * SPI_fname(TupleDesc tupdesc, int fnumber)
Definition: spi.c:1196
int SPI_execute(const char *src, bool read_only, long tcount)
Definition: spi.c:594
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1250
#define SPI_OK_SELECT
Definition: spi.h:86
static void error(void)
Definition: sql-dyntest.c:147
char * dbname
Definition: streamutil.c:51
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:233
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
StringInfoData * StringInfo
Definition: stringinfo.h:54
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:203
bool error_occurred
Definition: miscnodes.h:46
Definition: pg_list.h:54
Definition: nodes.h:129
TupleDesc tupDesc
Definition: portal.h:160
TupleDesc rd_att
Definition: rel.h:112
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26
List * args
Definition: primnodes.h:1543
List * named_args
Definition: primnodes.h:1539
Definition: c.h:730
Definition: pgtime.h:35
int tm_mday
Definition: pgtime.h:39
int tm_mon
Definition: pgtime.h:40
int tm_year
Definition: pgtime.h:41
Definition: regguts.h:323
Definition: c.h:676
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
@ TYPEOID
Definition: syscache.h:114
@ RELOID
Definition: syscache.h:89
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:133
struct TupleDescData * TupleDesc
Definition: tupdesc.h:89
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static Timestamp DatumGetTimestamp(Datum X)
Definition: timestamp.h:28
#define strVal(v)
Definition: value.h:82
#define VARDATA(PTR)
Definition: varatt.h:278
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE(PTR)
Definition: varatt.h:279
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
static void appendStringInfoText(StringInfo str, const text *t)
Definition: varlena.c:3981
char * text_to_cstring(const text *t)
Definition: varlena.c:217
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:196
text * cstring_to_text(const char *s)
Definition: varlena.c:184
const char * type
const char * name
int pg_encoding_mblen(int encoding, const char *mbstr)
Definition: wchar.c:2130
Datum xml_in(PG_FUNCTION_ARGS)
Definition: xml.c:264
Datum cursor_to_xmlschema(PG_FUNCTION_ARGS)
Definition: xml.c:3022
#define NO_XML_SUPPORT()
Definition: xml.c:226
static char * _SPI_strdup(const char *s)
Definition: xml.c:2657
xmltype * xmlconcat(List *args)
Definition: xml.c:544
Datum table_to_xml(PG_FUNCTION_ARGS)
Definition: xml.c:2813
Datum query_to_xmlschema(PG_FUNCTION_ARGS)
Definition: xml.c:2993
Datum database_to_xml(PG_FUNCTION_ARGS)
Definition: xml.c:3327
static List * database_get_xml_visible_tables(void)
Definition: xml.c:2777
static const char * map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tableforest, const char *targetns)
Definition: xml.c:3622
static char * map_multipart_sql_identifier_to_xml_name(const char *a, const char *b, const char *c, const char *d)
Definition: xml.c:3413
static void XmlTableInitOpaque(struct TableFuncScanState *state, int natts)
Definition: xml.c:4606
static const char * map_sql_type_to_xml_name(Oid typeoid, int typmod)
Definition: xml.c:3679
static const char * map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
Definition: xml.c:3839
Datum texttoxml(PG_FUNCTION_ARGS)
Definition: xml.c:628
static void xsd_schema_element_start(StringInfo result, const char *targetns)
Definition: xml.c:3174
Datum query_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
Definition: xml.c:3073
Datum xmltotext(PG_FUNCTION_ARGS)
Definition: xml.c:637
Datum schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
Definition: xml.c:3256
Datum xmlexists(PG_FUNCTION_ARGS)
Definition: xml.c:4466
Datum xmltext(PG_FUNCTION_ARGS)
Definition: xml.c:518
#define NAMESPACE_XSI
Definition: xml.c:235
static List * query_to_oid_list(const char *query)
Definition: xml.c:2714
int xmlbinary
Definition: xml.c:100
static char * xml_out_internal(xmltype *x, pg_enc target_encoding)
Definition: xml.c:303
static xmltype * stringinfo_to_xmltype(StringInfo buf)
Definition: xml.c:458
static StringInfo database_to_xmlschema_internal(bool nulls, bool tableforest, const char *targetns)
Definition: xml.c:3339
Datum database_to_xmlschema(PG_FUNCTION_ARGS)
Definition: xml.c:3382
Datum schema_to_xmlschema(PG_FUNCTION_ARGS)
Definition: xml.c:3243
static void xmldata_root_element_start(StringInfo result, const char *eltname, const char *xmlschema, const char *targetns, bool top_level)
Definition: xml.c:2895
Datum xml_send(PG_FUNCTION_ARGS)
Definition: xml.c:429
static const char * map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool tableforest, const char *targetns)
Definition: xml.c:3549
const TableFuncRoutine XmlTableRoutine
Definition: xml.c:214
Datum xmlcomment(PG_FUNCTION_ARGS)
Definition: xml.c:482
static void XmlTableSetNamespace(struct TableFuncScanState *state, const char *name, const char *uri)
Definition: xml.c:4711
Datum xmlconcat2(PG_FUNCTION_ARGS)
Definition: xml.c:610
static void XmlTableSetRowFilter(struct TableFuncScanState *state, const char *path)
Definition: xml.c:4737
static void xmldata_root_element_end(StringInfo result, const char *eltname)
Definition: xml.c:2922
text * xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
Definition: xml.c:647
xmltype * xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace)
Definition: xml.c:951
static Datum XmlTableGetValue(struct TableFuncScanState *state, int colnum, Oid typid, int32 typmod, bool *isnull)
Definition: xml.c:4843
static xmltype * cstring_to_xmltype(const char *string)
Definition: xml.c:465
Datum xml_is_well_formed_document(PG_FUNCTION_ARGS)
Definition: xml.c:4544
Datum query_to_xml(PG_FUNCTION_ARGS)
Definition: xml.c:2827
char * map_sql_identifier_to_xml_name(const char *ident, bool fully_escaped, bool escape_period)
Definition: xml.c:2308
static StringInfo database_to_xml_internal(const char *xmlschema, bool nulls, bool tableforest, const char *targetns)
Definition: xml.c:3284
int xmloption
Definition: xml.c:101
Datum xml_is_well_formed_content(PG_FUNCTION_ARGS)
Definition: xml.c:4557
#define XML_VISIBLE_SCHEMAS
Definition: xml.c:2766
bool xml_is_document(xmltype *arg)
Definition: xml.c:1087
static StringInfo schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tableforest, const char *targetns)
Definition: xml.c:3198
static List * schema_get_xml_visible_tables(Oid nspid)
Definition: xml.c:2743
char * escape_xml(const char *str)
Definition: xml.c:2625
Datum table_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
Definition: xml.c:3052
Datum xmlvalidate(PG_FUNCTION_ARGS)
Definition: xml.c:1077
static void XmlTableSetDocument(struct TableFuncScanState *state, Datum value)
Definition: xml.c:4654
static void XmlTableDestroyOpaque(struct TableFuncScanState *state)
Definition: xml.c:4995
char * map_xml_name_to_sql_identifier(const char *name)
Definition: xml.c:2364
static const char * map_sql_typecoll_to_xmlschema_types(List *tupdesc_list)
Definition: xml.c:3784
#define NAMESPACE_XSD
Definition: xml.c:234
xmltype * xmlpi(const char *target, text *arg, bool arg_is_null, bool *result_is_null)
Definition: xml.c:969
#define PG_XML_DEFAULT_VERSION
Definition: xml.c:292
Datum table_to_xmlschema(PG_FUNCTION_ARGS)
Definition: xml.c:2974
static StringInfo query_to_xml_internal(const char *query, char *tablename, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
Definition: xml.c:2929
static void SPI_sql_row_to_xmlelement(uint64 rownum, StringInfo result, char *tablename, bool nulls, bool tableforest, const char *targetns, bool top_level)
Definition: xml.c:4014
static StringInfo schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
Definition: xml.c:3109
static StringInfo table_to_xml_internal(Oid relid, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
Definition: xml.c:2796
Datum schema_to_xml(PG_FUNCTION_ARGS)
Definition: xml.c:3152
Datum database_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
Definition: xml.c:3394
char * map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
Definition: xml.c:2406
static bool XmlTableFetchRow(struct TableFuncScanState *state)
Definition: xml.c:4798
Datum cursor_to_xml(PG_FUNCTION_ARGS)
Definition: xml.c:2841
Datum xpath_exists(PG_FUNCTION_ARGS)
Definition: xml.c:4489
Datum xml_is_well_formed(PG_FUNCTION_ARGS)
Definition: xml.c:4531
xmltype * xmlelement(XmlExpr *xexpr, Datum *named_argvalue, bool *named_argnull, Datum *argvalue, bool *argnull)
Definition: xml.c:827
static void XmlTableSetColumnFilter(struct TableFuncScanState *state, const char *path, int colnum)
Definition: xml.c:4766
static const char * map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tableforest, const char *targetns)
Definition: xml.c:3444
Datum xml_out(PG_FUNCTION_ARGS)
Definition: xml.c:347
Datum xml_recv(PG_FUNCTION_ARGS)
Definition: xml.c:362
xmltype * xmlroot(xmltype *data, text *version, int standalone)
Definition: xml.c:1021
Datum xpath(PG_FUNCTION_ARGS)
Definition: xml.c:4443
static void xsd_schema_element_end(StringInfo result)
Definition: xml.c:3191
static List * database_get_xml_visible_schemas(void)
Definition: xml.c:2770
@ XML_STANDALONE_OMITTED
Definition: xml.h:30
@ XML_STANDALONE_NO_VALUE
Definition: xml.h:29
@ XML_STANDALONE_YES
Definition: xml.h:27
@ XML_STANDALONE_NO
Definition: xml.h:28
struct PgXmlErrorContext PgXmlErrorContext
Definition: xml.h:48
static xmltype * DatumGetXmlP(Datum X)
Definition: xml.h:51
#define PG_RETURN_XML_P(x)
Definition: xml.h:63
void xml_ereport(PgXmlErrorContext *errcxt, int level, int sqlcode, const char *msg)
bool pg_xml_error_occurred(PgXmlErrorContext *errcxt)
void pg_xml_done(PgXmlErrorContext *errcxt, bool isError)
PgXmlErrorContext * pg_xml_init(PgXmlStrictness strictness)
#define PG_GETARG_XML_P(n)
Definition: xml.h:62
void pg_xml_init_library(void)
@ XMLBINARY_BASE64
Definition: xml.h:35
PgXmlStrictness
Definition: xml.h:40
@ PG_XML_STRICTNESS_LEGACY
Definition: xml.h:41
@ PG_XML_STRICTNESS_ALL
Definition: xml.h:44
@ PG_XML_STRICTNESS_WELLFORMED
Definition: xml.h:43