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