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