PostgreSQL Source Code git master
Loading...
Searching...
No Matches
xml.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/namespace.h"
#include "catalog/pg_class.h"
#include "catalog/pg_type.h"
#include "executor/spi.h"
#include "executor/tablefunc.h"
#include "fmgr.h"
#include "lib/stringinfo.h"
#include "libpq/pqformat.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/execnodes.h"
#include "nodes/miscnodes.h"
#include "nodes/nodeFuncs.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/xml.h"
Include dependency graph for xml.c:

Go to the source code of this file.

Macros

#define NO_XML_SUPPORT()
 
#define NAMESPACE_XSD   "http://www.w3.org/2001/XMLSchema"
 
#define NAMESPACE_XSI   "http://www.w3.org/2001/XMLSchema-instance"
 
#define NAMESPACE_SQLXML   "http://standards.iso.org/iso/9075/2003/sqlxml"
 
#define PG_XML_DEFAULT_VERSION   "1.0"
 
#define XML_VISIBLE_SCHEMAS_EXCLUDE   "(nspname ~ '^pg_' OR nspname = 'information_schema')"
 
#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
 

Functions

static void xmldata_root_element_start (StringInfo result, const char *eltname, const char *xmlschema, const char *targetns, bool top_level)
 
static void xmldata_root_element_end (StringInfo result, const char *eltname)
 
static StringInfo query_to_xml_internal (const char *query, char *tablename, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
 
static const charmap_sql_table_to_xmlschema (TupleDesc tupdesc, Oid relid, bool nulls, bool tableforest, const char *targetns)
 
static const charmap_sql_schema_to_xmlschema_types (Oid nspid, List *relid_list, bool nulls, bool tableforest, const char *targetns)
 
static const charmap_sql_catalog_to_xmlschema_types (List *nspid_list, bool nulls, bool tableforest, const char *targetns)
 
static const charmap_sql_type_to_xml_name (Oid typeoid, int typmod)
 
static const charmap_sql_typecoll_to_xmlschema_types (List *tupdesc_list)
 
static const charmap_sql_type_to_xmlschema_type (Oid typeoid, int typmod)
 
static void SPI_sql_row_to_xmlelement (uint64 rownum, StringInfo result, char *tablename, bool nulls, bool tableforest, const char *targetns, bool top_level)
 
static void XmlTableInitOpaque (struct TableFuncScanState *state, int natts)
 
static void XmlTableSetDocument (struct TableFuncScanState *state, Datum value)
 
static void XmlTableSetNamespace (struct TableFuncScanState *state, const char *name, const char *uri)
 
static void XmlTableSetRowFilter (struct TableFuncScanState *state, const char *path)
 
static void XmlTableSetColumnFilter (struct TableFuncScanState *state, const char *path, int colnum)
 
static bool XmlTableFetchRow (struct TableFuncScanState *state)
 
static Datum XmlTableGetValue (struct TableFuncScanState *state, int colnum, Oid typid, int32 typmod, bool *isnull)
 
static void XmlTableDestroyOpaque (struct TableFuncScanState *state)
 
Datum xml_in (PG_FUNCTION_ARGS)
 
static charxml_out_internal (xmltype *x, pg_enc target_encoding)
 
Datum xml_out (PG_FUNCTION_ARGS)
 
Datum xml_recv (PG_FUNCTION_ARGS)
 
Datum xml_send (PG_FUNCTION_ARGS)
 
static xmltypestringinfo_to_xmltype (StringInfo buf)
 
static xmltypecstring_to_xmltype (const char *string)
 
Datum xmlcomment (PG_FUNCTION_ARGS)
 
Datum xmltext (PG_FUNCTION_ARGS)
 
xmltypexmlconcat (List *args)
 
Datum xmlconcat2 (PG_FUNCTION_ARGS)
 
Datum texttoxml (PG_FUNCTION_ARGS)
 
Datum xmltotext (PG_FUNCTION_ARGS)
 
textxmltotext_with_options (xmltype *data, XmlOptionType xmloption_arg, bool indent)
 
xmltypexmlelement (XmlExpr *xexpr, const Datum *named_argvalue, const bool *named_argnull, const Datum *argvalue, const bool *argnull)
 
xmltypexmlparse (text *data, XmlOptionType xmloption_arg, bool preserve_whitespace)
 
xmltypexmlpi (const char *target, text *arg, bool arg_is_null, bool *result_is_null)
 
xmltypexmlroot (xmltype *data, text *version, int standalone)
 
Datum xmlvalidate (PG_FUNCTION_ARGS)
 
bool xml_is_document (xmltype *arg)
 
charmap_sql_identifier_to_xml_name (const char *ident, bool fully_escaped, bool escape_period)
 
charmap_xml_name_to_sql_identifier (const char *name)
 
charmap_sql_value_to_xml_value (Datum value, Oid type, bool xml_escape_strings)
 
charescape_xml (const char *str)
 
static char_SPI_strdup (const char *s)
 
static Listquery_to_oid_list (const char *query)
 
static Listschema_get_xml_visible_tables (Oid nspid)
 
static Listdatabase_get_xml_visible_schemas (void)
 
static Listdatabase_get_xml_visible_tables (void)
 
static StringInfo table_to_xml_internal (Oid relid, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
 
Datum table_to_xml (PG_FUNCTION_ARGS)
 
Datum query_to_xml (PG_FUNCTION_ARGS)
 
Datum cursor_to_xml (PG_FUNCTION_ARGS)
 
Datum table_to_xmlschema (PG_FUNCTION_ARGS)
 
Datum query_to_xmlschema (PG_FUNCTION_ARGS)
 
Datum cursor_to_xmlschema (PG_FUNCTION_ARGS)
 
Datum table_to_xml_and_xmlschema (PG_FUNCTION_ARGS)
 
Datum query_to_xml_and_xmlschema (PG_FUNCTION_ARGS)
 
static StringInfo schema_to_xml_internal (Oid nspid, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
 
Datum schema_to_xml (PG_FUNCTION_ARGS)
 
static void xsd_schema_element_start (StringInfo result, const char *targetns)
 
static void xsd_schema_element_end (StringInfo result)
 
static StringInfo schema_to_xmlschema_internal (const char *schemaname, bool nulls, bool tableforest, const char *targetns)
 
Datum schema_to_xmlschema (PG_FUNCTION_ARGS)
 
Datum schema_to_xml_and_xmlschema (PG_FUNCTION_ARGS)
 
static StringInfo database_to_xml_internal (const char *xmlschema, bool nulls, bool tableforest, const char *targetns)
 
Datum database_to_xml (PG_FUNCTION_ARGS)
 
static StringInfo database_to_xmlschema_internal (bool nulls, bool tableforest, const char *targetns)
 
Datum database_to_xmlschema (PG_FUNCTION_ARGS)
 
Datum database_to_xml_and_xmlschema (PG_FUNCTION_ARGS)
 
static charmap_multipart_sql_identifier_to_xml_name (const char *a, const char *b, const char *c, const char *d)
 
Datum xpath (PG_FUNCTION_ARGS)
 
Datum xmlexists (PG_FUNCTION_ARGS)
 
Datum xpath_exists (PG_FUNCTION_ARGS)
 
Datum xml_is_well_formed (PG_FUNCTION_ARGS)
 
Datum xml_is_well_formed_document (PG_FUNCTION_ARGS)
 
Datum xml_is_well_formed_content (PG_FUNCTION_ARGS)
 

Variables

int xmlbinary = XMLBINARY_BASE64
 
int xmloption = XMLOPTION_CONTENT
 
const TableFuncRoutine XmlTableRoutine
 

Macro Definition Documentation

◆ NAMESPACE_SQLXML

#define NAMESPACE_SQLXML   "http://standards.iso.org/iso/9075/2003/sqlxml"

Definition at line 244 of file xml.c.

◆ NAMESPACE_XSD

#define NAMESPACE_XSD   "http://www.w3.org/2001/XMLSchema"

Definition at line 242 of file xml.c.

◆ NAMESPACE_XSI

#define NAMESPACE_XSI   "http://www.w3.org/2001/XMLSchema-instance"

Definition at line 243 of file xml.c.

◆ NO_XML_SUPPORT

#define NO_XML_SUPPORT ( )
Value:
errmsg("unsupported XML feature"), \
errdetail("This functionality requires the server to be built with libxml support.")))
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
static int fb(int x)

Definition at line 234 of file xml.c.

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

◆ PG_XML_DEFAULT_VERSION

#define PG_XML_DEFAULT_VERSION   "1.0"

Definition at line 300 of file xml.c.

◆ XML_VISIBLE_SCHEMAS

#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

Definition at line 2875 of file xml.c.

◆ XML_VISIBLE_SCHEMAS_EXCLUDE

#define XML_VISIBLE_SCHEMAS_EXCLUDE   "(nspname ~ '^pg_' OR nspname = 'information_schema')"

Definition at line 2873 of file xml.c.

Function Documentation

◆ _SPI_strdup()

static char * _SPI_strdup ( const char s)
static

Definition at line 2766 of file xml.c.

2767{
2768 size_t len = strlen(s) + 1;
2769 char *ret = SPI_palloc(len);
2770
2771 memcpy(ret, s, len);
2772 return ret;
2773}

References fb(), len, and SPI_palloc().

Referenced by cursor_to_xmlschema(), query_to_xml_and_xmlschema(), and query_to_xmlschema().

◆ cstring_to_xmltype()

static xmltype * cstring_to_xmltype ( const char string)
static

Definition at line 473 of file xml.c.

474{
475 return (xmltype *) cstring_to_text(string);
476}

References cstring_to_text().

Referenced by cursor_to_xmlschema(), query_to_xmlschema(), and table_to_xmlschema().

◆ cursor_to_xml()

Datum cursor_to_xml ( PG_FUNCTION_ARGS  )

Definition at line 2950 of file xml.c.

2951{
2953 int32 count = PG_GETARG_INT32(1);
2954 bool nulls = PG_GETARG_BOOL(2);
2955 bool tableforest = PG_GETARG_BOOL(3);
2956 const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(4));
2957
2958 StringInfoData result;
2959 Portal portal;
2960 uint64 i;
2961
2962 initStringInfo(&result);
2963
2964 if (!tableforest)
2965 {
2966 xmldata_root_element_start(&result, "table", NULL, targetns, true);
2967 appendStringInfoChar(&result, '\n');
2968 }
2969
2970 SPI_connect();
2971 portal = SPI_cursor_find(name);
2972 if (portal == NULL)
2973 ereport(ERROR,
2975 errmsg("cursor \"%s\" does not exist", name)));
2976
2977 SPI_cursor_fetch(portal, true, count);
2978 for (i = 0; i < SPI_processed; i++)
2979 SPI_sql_row_to_xmlelement(i, &result, NULL, nulls,
2980 tableforest, targetns, true);
2981
2982 SPI_finish();
2983
2984 if (!tableforest)
2985 xmldata_root_element_end(&result, "table");
2986
2988}

References appendStringInfoChar(), ereport, errcode(), errmsg(), ERROR, fb(), i, initStringInfo(), name, PG_GETARG_BOOL, PG_GETARG_INT32, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, SPI_connect(), SPI_cursor_fetch(), SPI_cursor_find(), SPI_finish(), SPI_processed, SPI_sql_row_to_xmlelement(), stringinfo_to_xmltype(), text_to_cstring(), xmldata_root_element_end(), and xmldata_root_element_start().

◆ cursor_to_xmlschema()

Datum cursor_to_xmlschema ( PG_FUNCTION_ARGS  )

Definition at line 3131 of file xml.c.

3132{
3134 bool nulls = PG_GETARG_BOOL(1);
3135 bool tableforest = PG_GETARG_BOOL(2);
3136 const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3137 const char *xmlschema;
3138 Portal portal;
3139
3140 SPI_connect();
3141 portal = SPI_cursor_find(name);
3142 if (portal == NULL)
3143 ereport(ERROR,
3145 errmsg("cursor \"%s\" does not exist", name)));
3146 if (portal->tupDesc == NULL)
3147 ereport(ERROR,
3149 errmsg("portal \"%s\" does not return tuples", name)));
3150
3152 InvalidOid, nulls,
3154 SPI_finish();
3155
3157}

References _SPI_strdup(), cstring_to_xmltype(), ereport, errcode(), errmsg(), ERROR, fb(), InvalidOid, map_sql_table_to_xmlschema(), name, PG_GETARG_BOOL, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, SPI_connect(), SPI_cursor_find(), SPI_finish(), text_to_cstring(), and PortalData::tupDesc.

◆ database_get_xml_visible_schemas()

static List * database_get_xml_visible_schemas ( void  )
static

Definition at line 2879 of file xml.c.

2880{
2881 return query_to_oid_list(XML_VISIBLE_SCHEMAS " ORDER BY nspname;");
2882}

References query_to_oid_list(), and XML_VISIBLE_SCHEMAS.

Referenced by database_to_xml_internal(), and database_to_xmlschema_internal().

◆ database_get_xml_visible_tables()

static List * database_get_xml_visible_tables ( void  )
static

Definition at line 2886 of file xml.c.

2887{
2888 /* At the moment there is no order required here. */
2889 return query_to_oid_list("SELECT oid FROM pg_catalog.pg_class"
2890 " WHERE relkind IN ("
2894 " AND pg_catalog.has_table_privilege(pg_class.oid, 'SELECT')"
2895 " AND relnamespace IN (" XML_VISIBLE_SCHEMAS ");");
2896}

References CppAsString2, fb(), query_to_oid_list(), and XML_VISIBLE_SCHEMAS.

Referenced by database_to_xmlschema_internal().

◆ database_to_xml()

◆ database_to_xml_and_xmlschema()

◆ database_to_xml_internal()

static StringInfo database_to_xml_internal ( const char xmlschema,
bool  nulls,
bool  tableforest,
const char targetns 
)
static

Definition at line 3393 of file xml.c.

3395{
3396 StringInfo result;
3398 ListCell *cell;
3399 char *xmlcn;
3400
3402 true, false);
3403 result = makeStringInfo();
3404
3406 appendStringInfoChar(result, '\n');
3407
3408 if (xmlschema)
3409 appendStringInfo(result, "%s\n\n", xmlschema);
3410
3411 SPI_connect();
3412
3414
3415 foreach(cell, nspid_list)
3416 {
3417 Oid nspid = lfirst_oid(cell);
3419
3421 tableforest, targetns, false);
3422
3423 appendBinaryStringInfo(result, subres->data, subres->len);
3424 appendStringInfoChar(result, '\n');
3425 }
3426
3427 SPI_finish();
3428
3430
3431 return result;
3432}

References appendBinaryStringInfo(), appendStringInfo(), appendStringInfoChar(), StringInfoData::data, database_get_xml_visible_schemas(), fb(), get_database_name(), lfirst_oid, makeStringInfo(), map_sql_identifier_to_xml_name(), MyDatabaseId, nspid, schema_to_xml_internal(), SPI_connect(), SPI_finish(), xmldata_root_element_end(), and xmldata_root_element_start().

Referenced by database_to_xml(), and database_to_xml_and_xmlschema().

◆ database_to_xmlschema()

◆ database_to_xmlschema_internal()

static StringInfo database_to_xmlschema_internal ( bool  nulls,
bool  tableforest,
const char targetns 
)
static

◆ escape_xml()

char * escape_xml ( const char str)

Definition at line 2734 of file xml.c.

2735{
2737 const char *p;
2738
2740 for (p = str; *p; p++)
2741 {
2742 switch (*p)
2743 {
2744 case '&':
2745 appendStringInfoString(&buf, "&amp;");
2746 break;
2747 case '<':
2748 appendStringInfoString(&buf, "&lt;");
2749 break;
2750 case '>':
2751 appendStringInfoString(&buf, "&gt;");
2752 break;
2753 case '\r':
2754 appendStringInfoString(&buf, "&#x0d;");
2755 break;
2756 default:
2758 break;
2759 }
2760 }
2761 return buf.data;
2762}

References appendStringInfoCharMacro, appendStringInfoString(), buf, initStringInfo(), and str.

Referenced by ExplainProperty(), ExplainPropertyList(), map_sql_value_to_xml_value(), and XmlTableGetValue().

◆ map_multipart_sql_identifier_to_xml_name()

static char * map_multipart_sql_identifier_to_xml_name ( const char a,
const char b,
const char c,
const char d 
)
static

Definition at line 3522 of file xml.c.

3523{
3524 StringInfoData result;
3525
3526 initStringInfo(&result);
3527
3528 if (a)
3529 appendStringInfoString(&result,
3530 map_sql_identifier_to_xml_name(a, true, true));
3531 if (b)
3532 appendStringInfo(&result, ".%s",
3533 map_sql_identifier_to_xml_name(b, true, true));
3534 if (c)
3535 appendStringInfo(&result, ".%s",
3536 map_sql_identifier_to_xml_name(c, true, true));
3537 if (d)
3538 appendStringInfo(&result, ".%s",
3539 map_sql_identifier_to_xml_name(d, true, true));
3540
3541 return result.data;
3542}

References a, appendStringInfo(), appendStringInfoString(), b, StringInfoData::data, initStringInfo(), and map_sql_identifier_to_xml_name().

Referenced by map_sql_catalog_to_xmlschema_types(), map_sql_schema_to_xmlschema_types(), map_sql_table_to_xmlschema(), and map_sql_type_to_xml_name().

◆ map_sql_catalog_to_xmlschema_types()

static const char * map_sql_catalog_to_xmlschema_types ( List nspid_list,
bool  nulls,
bool  tableforest,
const char targetns 
)
static

Definition at line 3731 of file xml.c.

3733{
3734 char *dbname;
3735 char *xmlcn;
3736 char *catalogtypename;
3737 StringInfoData result;
3738 ListCell *cell;
3739
3741
3742 initStringInfo(&result);
3743
3745
3747 dbname,
3748 NULL,
3749 NULL);
3750
3751 appendStringInfo(&result,
3752 "<xsd:complexType name=\"%s\">\n", catalogtypename);
3753 appendStringInfoString(&result,
3754 " <xsd:all>\n");
3755
3756 foreach(cell, nspid_list)
3757 {
3758 Oid nspid = lfirst_oid(cell);
3759 char *nspname = get_namespace_name(nspid);
3760 char *xmlsn = map_sql_identifier_to_xml_name(nspname, true, false);
3762 dbname,
3763 nspname,
3764 NULL);
3765
3766 appendStringInfo(&result,
3767 " <xsd:element name=\"%s\" type=\"%s\"/>\n",
3769 }
3770
3771 appendStringInfoString(&result,
3772 " </xsd:all>\n");
3773 appendStringInfoString(&result,
3774 "</xsd:complexType>\n\n");
3775
3776 appendStringInfo(&result,
3777 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3779
3780 return result.data;
3781}

References appendStringInfo(), appendStringInfoString(), StringInfoData::data, dbname, fb(), get_database_name(), get_namespace_name(), initStringInfo(), lfirst_oid, map_multipart_sql_identifier_to_xml_name(), map_sql_identifier_to_xml_name(), MyDatabaseId, and nspid.

Referenced by database_to_xmlschema_internal().

◆ map_sql_identifier_to_xml_name()

char * map_sql_identifier_to_xml_name ( const char ident,
bool  fully_escaped,
bool  escape_period 
)

Definition at line 2417 of file xml.c.

2419{
2420#ifdef USE_LIBXML
2422 const char *p;
2423
2424 /*
2425 * SQL/XML doesn't make use of this case anywhere, so it's probably a
2426 * mistake.
2427 */
2429
2431
2432 for (p = ident; *p; p += pg_mblen_cstr(p))
2433 {
2434 if (*p == ':' && (p == ident || fully_escaped))
2435 appendStringInfoString(&buf, "_x003A_");
2436 else if (*p == '_' && *(p + 1) == 'x')
2437 appendStringInfoString(&buf, "_x005F_");
2438 else if (fully_escaped && p == ident &&
2439 pg_strncasecmp(p, "xml", 3) == 0)
2440 {
2441 if (*p == 'x')
2442 appendStringInfoString(&buf, "_x0078_");
2443 else
2444 appendStringInfoString(&buf, "_x0058_");
2445 }
2446 else if (escape_period && *p == '.')
2447 appendStringInfoString(&buf, "_x002E_");
2448 else
2449 {
2451
2452 if ((p == ident)
2455 appendStringInfo(&buf, "_x%04X_", (unsigned int) u);
2456 else
2458 }
2459 }
2460
2461 return buf.data;
2462#else /* not USE_LIBXML */
2464 return NULL;
2465#endif /* not USE_LIBXML */
2466}

References appendBinaryStringInfo(), appendStringInfo(), appendStringInfoString(), Assert, buf, fb(), ident, initStringInfo(), NO_XML_SUPPORT, pg_mblen_cstr(), and pg_strncasecmp().

Referenced by database_to_xml_internal(), map_multipart_sql_identifier_to_xml_name(), map_sql_catalog_to_xmlschema_types(), map_sql_schema_to_xmlschema_types(), map_sql_table_to_xmlschema(), query_to_xml_internal(), schema_to_xml_internal(), SPI_sql_row_to_xmlelement(), and transformXmlExpr().

◆ map_sql_schema_to_xmlschema_types()

static const char * map_sql_schema_to_xmlschema_types ( Oid  nspid,
List relid_list,
bool  nulls,
bool  tableforest,
const char targetns 
)
static

Definition at line 3658 of file xml.c.

3660{
3661 char *dbname;
3662 char *nspname;
3663 char *xmlsn;
3664 char *schematypename;
3665 StringInfoData result;
3666 ListCell *cell;
3667
3669 nspname = get_namespace_name(nspid);
3670
3671 initStringInfo(&result);
3672
3673 xmlsn = map_sql_identifier_to_xml_name(nspname, true, false);
3674
3676 dbname,
3677 nspname,
3678 NULL);
3679
3680 appendStringInfo(&result,
3681 "<xsd:complexType name=\"%s\">\n", schematypename);
3682 if (!tableforest)
3683 appendStringInfoString(&result,
3684 " <xsd:all>\n");
3685 else
3686 appendStringInfoString(&result,
3687 " <xsd:sequence>\n");
3688
3689 foreach(cell, relid_list)
3690 {
3691 Oid relid = lfirst_oid(cell);
3692 char *relname = get_rel_name(relid);
3693 char *xmltn = map_sql_identifier_to_xml_name(relname, true, false);
3694 char *tabletypename = map_multipart_sql_identifier_to_xml_name(tableforest ? "RowType" : "TableType",
3695 dbname,
3696 nspname,
3697 relname);
3698
3699 if (!tableforest)
3700 appendStringInfo(&result,
3701 " <xsd:element name=\"%s\" type=\"%s\"/>\n",
3703 else
3704 appendStringInfo(&result,
3705 " <xsd:element name=\"%s\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n",
3707 }
3708
3709 if (!tableforest)
3710 appendStringInfoString(&result,
3711 " </xsd:all>\n");
3712 else
3713 appendStringInfoString(&result,
3714 " </xsd:sequence>\n");
3715 appendStringInfoString(&result,
3716 "</xsd:complexType>\n\n");
3717
3718 appendStringInfo(&result,
3719 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3721
3722 return result.data;
3723}

References appendStringInfo(), appendStringInfoString(), StringInfoData::data, dbname, fb(), get_database_name(), get_namespace_name(), get_rel_name(), initStringInfo(), lfirst_oid, map_multipart_sql_identifier_to_xml_name(), map_sql_identifier_to_xml_name(), MyDatabaseId, nspid, and relname.

Referenced by schema_to_xmlschema_internal().

◆ map_sql_table_to_xmlschema()

static const char * map_sql_table_to_xmlschema ( TupleDesc  tupdesc,
Oid  relid,
bool  nulls,
bool  tableforest,
const char targetns 
)
static

Definition at line 3553 of file xml.c.

3555{
3556 int i;
3557 char *xmltn;
3558 char *tabletypename;
3559 char *rowtypename;
3560 StringInfoData result;
3561
3562 initStringInfo(&result);
3563
3564 if (OidIsValid(relid))
3565 {
3566 HeapTuple tuple;
3568
3569 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
3570 if (!HeapTupleIsValid(tuple))
3571 elog(ERROR, "cache lookup failed for relation %u", relid);
3572 reltuple = (Form_pg_class) GETSTRUCT(tuple);
3573
3575 true, false);
3576
3579 get_namespace_name(reltuple->relnamespace),
3580 NameStr(reltuple->relname));
3581
3584 get_namespace_name(reltuple->relnamespace),
3585 NameStr(reltuple->relname));
3586
3587 ReleaseSysCache(tuple);
3588 }
3589 else
3590 {
3591 if (tableforest)
3592 xmltn = "row";
3593 else
3594 xmltn = "table";
3595
3596 tabletypename = "TableType";
3597 rowtypename = "RowType";
3598 }
3599
3601
3602 appendStringInfoString(&result,
3604
3605 appendStringInfo(&result,
3606 "<xsd:complexType name=\"%s\">\n"
3607 " <xsd:sequence>\n",
3608 rowtypename);
3609
3610 for (i = 0; i < tupdesc->natts; i++)
3611 {
3613
3614 if (att->attisdropped)
3615 continue;
3616 appendStringInfo(&result,
3617 " <xsd:element name=\"%s\" type=\"%s\"%s></xsd:element>\n",
3619 true, false),
3620 map_sql_type_to_xml_name(att->atttypid, -1),
3621 nulls ? " nillable=\"true\"" : " minOccurs=\"0\"");
3622 }
3623
3624 appendStringInfoString(&result,
3625 " </xsd:sequence>\n"
3626 "</xsd:complexType>\n\n");
3627
3628 if (!tableforest)
3629 {
3630 appendStringInfo(&result,
3631 "<xsd:complexType name=\"%s\">\n"
3632 " <xsd:sequence>\n"
3633 " <xsd:element name=\"row\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n"
3634 " </xsd:sequence>\n"
3635 "</xsd:complexType>\n\n",
3637
3638 appendStringInfo(&result,
3639 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3641 }
3642 else
3643 appendStringInfo(&result,
3644 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3646
3647 xsd_schema_element_end(&result);
3648
3649 return result.data;
3650}

References appendStringInfo(), appendStringInfoString(), StringInfoData::data, elog, ERROR, fb(), get_database_name(), get_namespace_name(), GETSTRUCT(), HeapTupleIsValid, i, initStringInfo(), list_make1, map_multipart_sql_identifier_to_xml_name(), map_sql_identifier_to_xml_name(), map_sql_type_to_xml_name(), map_sql_typecoll_to_xmlschema_types(), MyDatabaseId, NameStr, TupleDescData::natts, ObjectIdGetDatum(), OidIsValid, ReleaseSysCache(), SearchSysCache1(), TupleDescAttr(), xsd_schema_element_end(), and xsd_schema_element_start().

Referenced by cursor_to_xmlschema(), query_to_xml_and_xmlschema(), query_to_xmlschema(), table_to_xml_and_xmlschema(), and table_to_xmlschema().

◆ map_sql_type_to_xml_name()

static const char * map_sql_type_to_xml_name ( Oid  typeoid,
int  typmod 
)
static

Definition at line 3788 of file xml.c.

3789{
3790 StringInfoData result;
3791
3792 initStringInfo(&result);
3793
3794 switch (typeoid)
3795 {
3796 case BPCHAROID:
3797 if (typmod == -1)
3798 appendStringInfoString(&result, "CHAR");
3799 else
3800 appendStringInfo(&result, "CHAR_%d", typmod - VARHDRSZ);
3801 break;
3802 case VARCHAROID:
3803 if (typmod == -1)
3804 appendStringInfoString(&result, "VARCHAR");
3805 else
3806 appendStringInfo(&result, "VARCHAR_%d", typmod - VARHDRSZ);
3807 break;
3808 case NUMERICOID:
3809 if (typmod == -1)
3810 appendStringInfoString(&result, "NUMERIC");
3811 else
3812 appendStringInfo(&result, "NUMERIC_%d_%d",
3813 ((typmod - VARHDRSZ) >> 16) & 0xffff,
3814 (typmod - VARHDRSZ) & 0xffff);
3815 break;
3816 case INT4OID:
3817 appendStringInfoString(&result, "INTEGER");
3818 break;
3819 case INT2OID:
3820 appendStringInfoString(&result, "SMALLINT");
3821 break;
3822 case INT8OID:
3823 appendStringInfoString(&result, "BIGINT");
3824 break;
3825 case FLOAT4OID:
3826 appendStringInfoString(&result, "REAL");
3827 break;
3828 case FLOAT8OID:
3829 appendStringInfoString(&result, "DOUBLE");
3830 break;
3831 case BOOLOID:
3832 appendStringInfoString(&result, "BOOLEAN");
3833 break;
3834 case TIMEOID:
3835 if (typmod == -1)
3836 appendStringInfoString(&result, "TIME");
3837 else
3838 appendStringInfo(&result, "TIME_%d", typmod);
3839 break;
3840 case TIMETZOID:
3841 if (typmod == -1)
3842 appendStringInfoString(&result, "TIME_WTZ");
3843 else
3844 appendStringInfo(&result, "TIME_WTZ_%d", typmod);
3845 break;
3846 case TIMESTAMPOID:
3847 if (typmod == -1)
3848 appendStringInfoString(&result, "TIMESTAMP");
3849 else
3850 appendStringInfo(&result, "TIMESTAMP_%d", typmod);
3851 break;
3852 case TIMESTAMPTZOID:
3853 if (typmod == -1)
3854 appendStringInfoString(&result, "TIMESTAMP_WTZ");
3855 else
3856 appendStringInfo(&result, "TIMESTAMP_WTZ_%d", typmod);
3857 break;
3858 case DATEOID:
3859 appendStringInfoString(&result, "DATE");
3860 break;
3861 case XMLOID:
3862 appendStringInfoString(&result, "XML");
3863 break;
3864 default:
3865 {
3866 HeapTuple tuple;
3868
3870 if (!HeapTupleIsValid(tuple))
3871 elog(ERROR, "cache lookup failed for type %u", typeoid);
3872 typtuple = (Form_pg_type) GETSTRUCT(tuple);
3873
3874 appendStringInfoString(&result,
3875 map_multipart_sql_identifier_to_xml_name((typtuple->typtype == TYPTYPE_DOMAIN) ? "Domain" : "UDT",
3879
3880 ReleaseSysCache(tuple);
3881 }
3882 }
3883
3884 return result.data;
3885}

References appendStringInfo(), appendStringInfoString(), StringInfoData::data, elog, ERROR, fb(), get_database_name(), get_namespace_name(), GETSTRUCT(), HeapTupleIsValid, initStringInfo(), map_multipart_sql_identifier_to_xml_name(), MyDatabaseId, NameStr, ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache1(), and VARHDRSZ.

Referenced by map_sql_table_to_xmlschema(), and map_sql_type_to_xmlschema_type().

◆ map_sql_type_to_xmlschema_type()

static const char * map_sql_type_to_xmlschema_type ( Oid  typeoid,
int  typmod 
)
static

Definition at line 3948 of file xml.c.

3949{
3950 StringInfoData result;
3951 const char *typename = map_sql_type_to_xml_name(typeoid, typmod);
3952
3953 initStringInfo(&result);
3954
3955 if (typeoid == XMLOID)
3956 {
3957 appendStringInfoString(&result,
3958 "<xsd:complexType mixed=\"true\">\n"
3959 " <xsd:sequence>\n"
3960 " <xsd:any name=\"element\" minOccurs=\"0\" maxOccurs=\"unbounded\" processContents=\"skip\"/>\n"
3961 " </xsd:sequence>\n"
3962 "</xsd:complexType>\n");
3963 }
3964 else
3965 {
3966 appendStringInfo(&result,
3967 "<xsd:simpleType name=\"%s\">\n", typename);
3968
3969 switch (typeoid)
3970 {
3971 case BPCHAROID:
3972 case VARCHAROID:
3973 case TEXTOID:
3974 appendStringInfoString(&result,
3975 " <xsd:restriction base=\"xsd:string\">\n");
3976 if (typmod != -1)
3977 appendStringInfo(&result,
3978 " <xsd:maxLength value=\"%d\"/>\n",
3979 typmod - VARHDRSZ);
3980 appendStringInfoString(&result, " </xsd:restriction>\n");
3981 break;
3982
3983 case BYTEAOID:
3984 appendStringInfo(&result,
3985 " <xsd:restriction base=\"xsd:%s\">\n"
3986 " </xsd:restriction>\n",
3987 xmlbinary == XMLBINARY_BASE64 ? "base64Binary" : "hexBinary");
3988 break;
3989
3990 case NUMERICOID:
3991 if (typmod != -1)
3992 appendStringInfo(&result,
3993 " <xsd:restriction base=\"xsd:decimal\">\n"
3994 " <xsd:totalDigits value=\"%d\"/>\n"
3995 " <xsd:fractionDigits value=\"%d\"/>\n"
3996 " </xsd:restriction>\n",
3997 ((typmod - VARHDRSZ) >> 16) & 0xffff,
3998 (typmod - VARHDRSZ) & 0xffff);
3999 break;
4000
4001 case INT2OID:
4002 appendStringInfo(&result,
4003 " <xsd:restriction base=\"xsd:short\">\n"
4004 " <xsd:maxInclusive value=\"%d\"/>\n"
4005 " <xsd:minInclusive value=\"%d\"/>\n"
4006 " </xsd:restriction>\n",
4008 break;
4009
4010 case INT4OID:
4011 appendStringInfo(&result,
4012 " <xsd:restriction base=\"xsd:int\">\n"
4013 " <xsd:maxInclusive value=\"%d\"/>\n"
4014 " <xsd:minInclusive value=\"%d\"/>\n"
4015 " </xsd:restriction>\n",
4016 INT_MAX, INT_MIN);
4017 break;
4018
4019 case INT8OID:
4020 appendStringInfo(&result,
4021 " <xsd:restriction base=\"xsd:long\">\n"
4022 " <xsd:maxInclusive value=\"" INT64_FORMAT "\"/>\n"
4023 " <xsd:minInclusive value=\"" INT64_FORMAT "\"/>\n"
4024 " </xsd:restriction>\n",
4026 PG_INT64_MIN);
4027 break;
4028
4029 case FLOAT4OID:
4030 appendStringInfoString(&result,
4031 " <xsd:restriction base=\"xsd:float\"></xsd:restriction>\n");
4032 break;
4033
4034 case FLOAT8OID:
4035 appendStringInfoString(&result,
4036 " <xsd:restriction base=\"xsd:double\"></xsd:restriction>\n");
4037 break;
4038
4039 case BOOLOID:
4040 appendStringInfoString(&result,
4041 " <xsd:restriction base=\"xsd:boolean\"></xsd:restriction>\n");
4042 break;
4043
4044 case TIMEOID:
4045 case TIMETZOID:
4046 {
4047 const char *tz = (typeoid == TIMETZOID ? "(\\+|-)\\p{Nd}{2}:\\p{Nd}{2}" : "");
4048
4049 if (typmod == -1)
4050 appendStringInfo(&result,
4051 " <xsd:restriction base=\"xsd:time\">\n"
4052 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}(.\\p{Nd}+)?%s\"/>\n"
4053 " </xsd:restriction>\n", tz);
4054 else if (typmod == 0)
4055 appendStringInfo(&result,
4056 " <xsd:restriction base=\"xsd:time\">\n"
4057 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"
4058 " </xsd:restriction>\n", tz);
4059 else
4060 appendStringInfo(&result,
4061 " <xsd:restriction base=\"xsd:time\">\n"
4062 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}.\\p{Nd}{%d}%s\"/>\n"
4063 " </xsd:restriction>\n", typmod - VARHDRSZ, tz);
4064 break;
4065 }
4066
4067 case TIMESTAMPOID:
4068 case TIMESTAMPTZOID:
4069 {
4070 const char *tz = (typeoid == TIMESTAMPTZOID ? "(\\+|-)\\p{Nd}{2}:\\p{Nd}{2}" : "");
4071
4072 if (typmod == -1)
4073 appendStringInfo(&result,
4074 " <xsd:restriction base=\"xsd:dateTime\">\n"
4075 " <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"
4076 " </xsd:restriction>\n", tz);
4077 else if (typmod == 0)
4078 appendStringInfo(&result,
4079 " <xsd:restriction base=\"xsd:dateTime\">\n"
4080 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"
4081 " </xsd:restriction>\n", tz);
4082 else
4083 appendStringInfo(&result,
4084 " <xsd:restriction base=\"xsd:dateTime\">\n"
4085 " <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"
4086 " </xsd:restriction>\n", typmod - VARHDRSZ, tz);
4087 break;
4088 }
4089
4090 case DATEOID:
4091 appendStringInfoString(&result,
4092 " <xsd:restriction base=\"xsd:date\">\n"
4093 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}\"/>\n"
4094 " </xsd:restriction>\n");
4095 break;
4096
4097 default:
4099 {
4101 int32 base_typmod = -1;
4102
4103 base_typeoid = getBaseTypeAndTypmod(typeoid, &base_typmod);
4104
4105 appendStringInfo(&result,
4106 " <xsd:restriction base=\"%s\"/>\n",
4108 }
4109 break;
4110 }
4111 appendStringInfoString(&result, "</xsd:simpleType>\n");
4112 }
4113
4114 return result.data;
4115}

References appendStringInfo(), appendStringInfoString(), StringInfoData::data, fb(), get_typtype(), getBaseTypeAndTypmod(), initStringInfo(), INT64_FORMAT, map_sql_type_to_xml_name(), PG_INT64_MAX, PG_INT64_MIN, VARHDRSZ, xmlbinary, and XMLBINARY_BASE64.

Referenced by map_sql_typecoll_to_xmlschema_types().

◆ map_sql_typecoll_to_xmlschema_types()

static const char * map_sql_typecoll_to_xmlschema_types ( List tupdesc_list)
static

Definition at line 3893 of file xml.c.

3894{
3895 List *uniquetypes = NIL;
3896 int i;
3897 StringInfoData result;
3898 ListCell *cell0;
3899
3900 /* extract all column types used in the set of TupleDescs */
3901 foreach(cell0, tupdesc_list)
3902 {
3903 TupleDesc tupdesc = (TupleDesc) lfirst(cell0);
3904
3905 for (i = 0; i < tupdesc->natts; i++)
3906 {
3908
3909 if (att->attisdropped)
3910 continue;
3912 }
3913 }
3914
3915 /* add base types of domains */
3916 foreach(cell0, uniquetypes)
3917 {
3918 Oid typid = lfirst_oid(cell0);
3919 Oid basetypid = getBaseType(typid);
3920
3921 if (basetypid != typid)
3923 }
3924
3925 /* Convert to textual form */
3926 initStringInfo(&result);
3927
3928 foreach(cell0, uniquetypes)
3929 {
3930 appendStringInfo(&result, "%s\n",
3932 -1));
3933 }
3934
3935 return result.data;
3936}

References appendStringInfo(), StringInfoData::data, fb(), getBaseType(), i, initStringInfo(), lfirst, lfirst_oid, list_append_unique_oid(), map_sql_type_to_xmlschema_type(), TupleDescData::natts, NIL, and TupleDescAttr().

Referenced by database_to_xmlschema_internal(), map_sql_table_to_xmlschema(), and schema_to_xmlschema_internal().

◆ map_sql_value_to_xml_value()

char * map_sql_value_to_xml_value ( Datum  value,
Oid  type,
bool  xml_escape_strings 
)

Definition at line 2515 of file xml.c.

2516{
2518 {
2519 ArrayType *array;
2520 Oid elmtype;
2521 int16 elmlen;
2522 bool elmbyval;
2523 char elmalign;
2524 int num_elems;
2525 Datum *elem_values;
2526 bool *elem_nulls;
2528 int i;
2529
2530 array = DatumGetArrayTypeP(value);
2531 elmtype = ARR_ELEMTYPE(array);
2532 get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign);
2533
2535 elmlen, elmbyval, elmalign,
2536 &elem_values, &elem_nulls,
2537 &num_elems);
2538
2540
2541 for (i = 0; i < num_elems; i++)
2542 {
2543 if (elem_nulls[i])
2544 continue;
2545 appendStringInfoString(&buf, "<element>");
2547 map_sql_value_to_xml_value(elem_values[i],
2548 elmtype, true));
2549 appendStringInfoString(&buf, "</element>");
2550 }
2551
2552 pfree(elem_values);
2553 pfree(elem_nulls);
2554
2555 return buf.data;
2556 }
2557 else
2558 {
2559 Oid typeOut;
2560 bool isvarlena;
2561 char *str;
2562
2563 /*
2564 * Flatten domains; the special-case treatments below should apply to,
2565 * eg, domains over boolean not just boolean.
2566 */
2568
2569 /*
2570 * Special XSD formatting for some data types
2571 */
2572 switch (type)
2573 {
2574 case BOOLOID:
2575 if (DatumGetBool(value))
2576 return "true";
2577 else
2578 return "false";
2579
2580 case DATEOID:
2581 {
2582 DateADT date;
2583 struct pg_tm tm;
2584 char buf[MAXDATELEN + 1];
2585
2587 /* XSD doesn't support infinite values */
2588 if (DATE_NOT_FINITE(date))
2589 ereport(ERROR,
2591 errmsg("date out of range"),
2592 errdetail("XML does not support infinite date values.")));
2594 &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
2596
2597 return pstrdup(buf);
2598 }
2599
2600 case TIMESTAMPOID:
2601 {
2603 struct pg_tm tm;
2604 fsec_t fsec;
2605 char buf[MAXDATELEN + 1];
2606
2608
2609 /* XSD doesn't support infinite values */
2611 ereport(ERROR,
2613 errmsg("timestamp out of range"),
2614 errdetail("XML does not support infinite timestamp values.")));
2615 else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
2616 EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
2617 else
2618 ereport(ERROR,
2620 errmsg("timestamp out of range")));
2621
2622 return pstrdup(buf);
2623 }
2624
2625 case TIMESTAMPTZOID:
2626 {
2628 struct pg_tm tm;
2629 int tz;
2630 fsec_t fsec;
2631 const char *tzn = NULL;
2632 char buf[MAXDATELEN + 1];
2633
2635
2636 /* XSD doesn't support infinite values */
2638 ereport(ERROR,
2640 errmsg("timestamp out of range"),
2641 errdetail("XML does not support infinite timestamp values.")));
2642 else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
2643 EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
2644 else
2645 ereport(ERROR,
2647 errmsg("timestamp out of range")));
2648
2649 return pstrdup(buf);
2650 }
2651
2652#ifdef USE_LIBXML
2653 case BYTEAOID:
2654 {
2657 volatile xmlBufferPtr buf = NULL;
2658 volatile xmlTextWriterPtr writer = NULL;
2659 char *result;
2660
2662
2663 PG_TRY();
2664 {
2665 buf = xmlBufferCreate();
2666 if (buf == NULL || xmlerrcxt->err_occurred)
2668 "could not allocate xmlBuffer");
2670 if (writer == NULL || xmlerrcxt->err_occurred)
2672 "could not allocate xmlTextWriter");
2673
2677 else
2680
2681 /* we MUST do this now to flush data out to the buffer */
2683 writer = NULL;
2684
2685 result = pstrdup((const char *) xmlBufferContent(buf));
2686 }
2687 PG_CATCH();
2688 {
2689 if (writer)
2691 if (buf)
2693
2694 pg_xml_done(xmlerrcxt, true);
2695
2696 PG_RE_THROW();
2697 }
2698 PG_END_TRY();
2699
2701
2702 pg_xml_done(xmlerrcxt, false);
2703
2704 return result;
2705 }
2706#endif /* USE_LIBXML */
2707
2708 }
2709
2710 /*
2711 * otherwise, just use the type's native text representation
2712 */
2715
2716 /* ... exactly as-is for XML, and when escaping is not wanted */
2717 if (type == XMLOID || !xml_escape_strings)
2718 return str;
2719
2720 /* otherwise, translate special characters as needed */
2721 return escape_xml(str);
2722 }
2723}

References appendStringInfoString(), ARR_ELEMTYPE, buf, DATE_NOT_FINITE, DatumGetArrayTypeP, DatumGetBool(), DatumGetByteaPP, DatumGetDateADT(), DatumGetTimestamp(), deconstruct_array(), EncodeDateOnly(), EncodeDateTime(), ereport, errcode(), errdetail(), errmsg(), ERROR, escape_xml(), fb(), get_typlenbyvalalign(), getBaseType(), getTypeOutputInfo(), i, initStringInfo(), j2date(), map_sql_value_to_xml_value(), MAXDATELEN, OidOutputFunctionCall(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pg_xml_done(), pg_xml_init(), PG_XML_STRICTNESS_ALL, POSTGRES_EPOCH_JDATE, pstrdup(), str, timestamp2tm(), TIMESTAMP_NOT_FINITE, tm, pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_year, type, type_is_array_domain, USE_XSD_DATES, value, VARDATA_ANY(), VARSIZE_ANY_EXHDR(), xml_ereport(), xmlbinary, and XMLBINARY_BASE64.

Referenced by ExecEvalXmlExpr(), map_sql_value_to_xml_value(), SPI_sql_row_to_xmlelement(), and xmlelement().

◆ map_xml_name_to_sql_identifier()

char * map_xml_name_to_sql_identifier ( const char name)

Definition at line 2473 of file xml.c.

2474{
2476 const char *p;
2477
2479
2480 for (p = name; *p; p += pg_mblen_cstr(p))
2481 {
2482 if (*p == '_' && *(p + 1) == 'x'
2483 && isxdigit((unsigned char) *(p + 2))
2484 && isxdigit((unsigned char) *(p + 3))
2485 && isxdigit((unsigned char) *(p + 4))
2486 && isxdigit((unsigned char) *(p + 5))
2487 && *(p + 6) == '_')
2488 {
2490 unsigned int u;
2491
2492 sscanf(p + 2, "%X", &u);
2493 pg_unicode_to_server(u, (unsigned char *) cbuf);
2495 p += 6;
2496 }
2497 else
2499 }
2500
2501 return buf.data;
2502}

References appendBinaryStringInfo(), appendStringInfoString(), buf, fb(), initStringInfo(), MAX_UNICODE_EQUIVALENT_STRING, name, pg_mblen_cstr(), and pg_unicode_to_server().

Referenced by get_rule_expr().

◆ query_to_oid_list()

static List * query_to_oid_list ( const char query)
static

Definition at line 2823 of file xml.c.

2824{
2825 uint64 i;
2826 List *list = NIL;
2827 int spi_result;
2828
2829 spi_result = SPI_execute(query, true, 0);
2831 elog(ERROR, "SPI_execute returned %s for %s",
2833
2834 for (i = 0; i < SPI_processed; i++)
2835 {
2836 Datum oid;
2837 bool isnull;
2838
2841 1,
2842 &isnull);
2843 if (!isnull)
2844 list = lappend_oid(list, DatumGetObjectId(oid));
2845 }
2846
2847 return list;
2848}

References DatumGetObjectId(), elog, ERROR, fb(), i, lappend_oid(), NIL, SPI_execute(), SPI_getbinval(), SPI_OK_SELECT, SPI_processed, SPI_result_code_string(), SPI_tuptable, SPITupleTable::tupdesc, and SPITupleTable::vals.

Referenced by database_get_xml_visible_schemas(), database_get_xml_visible_tables(), and schema_get_xml_visible_tables().

◆ query_to_xml()

Datum query_to_xml ( PG_FUNCTION_ARGS  )

Definition at line 2936 of file xml.c.

2937{
2938 char *query = text_to_cstring(PG_GETARG_TEXT_PP(0));
2939 bool nulls = PG_GETARG_BOOL(1);
2940 bool tableforest = PG_GETARG_BOOL(2);
2941 const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
2942
2944 NULL, nulls, tableforest,
2945 targetns, true)));
2946}

References fb(), PG_GETARG_BOOL, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, query_to_xml_internal(), stringinfo_to_xmltype(), and text_to_cstring().

◆ query_to_xml_and_xmlschema()

Datum query_to_xml_and_xmlschema ( PG_FUNCTION_ARGS  )

Definition at line 3182 of file xml.c.

3183{
3184 char *query = text_to_cstring(PG_GETARG_TEXT_PP(0));
3185 bool nulls = PG_GETARG_BOOL(1);
3186 bool tableforest = PG_GETARG_BOOL(2);
3187 const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3188
3189 const char *xmlschema;
3191 Portal portal;
3192
3193 SPI_connect();
3194
3195 if ((plan = SPI_prepare(query, 0, NULL)) == NULL)
3196 elog(ERROR, "SPI_prepare(\"%s\") failed", query);
3197
3198 if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL)
3199 elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
3200
3202 InvalidOid, nulls, tableforest, targetns));
3203 SPI_cursor_close(portal);
3204 SPI_finish();
3205
3207 xmlschema, nulls, tableforest,
3208 targetns, true)));
3209}

References _SPI_strdup(), elog, ERROR, fb(), InvalidOid, map_sql_table_to_xmlschema(), PG_GETARG_BOOL, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, plan, query_to_xml_internal(), SPI_connect(), SPI_cursor_close(), SPI_cursor_open(), SPI_finish(), SPI_prepare(), stringinfo_to_xmltype(), text_to_cstring(), and PortalData::tupDesc.

◆ query_to_xml_internal()

static StringInfo query_to_xml_internal ( const char query,
char tablename,
const char xmlschema,
bool  nulls,
bool  tableforest,
const char targetns,
bool  top_level 
)
static

Definition at line 3038 of file xml.c.

3041{
3042 StringInfo result;
3043 char *xmltn;
3044 uint64 i;
3045
3046 if (tablename)
3047 xmltn = map_sql_identifier_to_xml_name(tablename, true, false);
3048 else
3049 xmltn = "table";
3050
3051 result = makeStringInfo();
3052
3053 SPI_connect();
3054 if (SPI_execute(query, true, 0) != SPI_OK_SELECT)
3055 ereport(ERROR,
3057 errmsg("invalid query")));
3058
3059 if (!tableforest)
3060 {
3062 targetns, top_level);
3063 appendStringInfoChar(result, '\n');
3064 }
3065
3066 if (xmlschema)
3067 appendStringInfo(result, "%s\n\n", xmlschema);
3068
3069 for (i = 0; i < SPI_processed; i++)
3070 SPI_sql_row_to_xmlelement(i, result, tablename, nulls,
3071 tableforest, targetns, top_level);
3072
3073 if (!tableforest)
3075
3076 SPI_finish();
3077
3078 return result;
3079}

References appendStringInfo(), appendStringInfoChar(), ereport, errcode(), errmsg(), ERROR, fb(), i, makeStringInfo(), map_sql_identifier_to_xml_name(), SPI_connect(), SPI_execute(), SPI_finish(), SPI_OK_SELECT, SPI_processed, SPI_sql_row_to_xmlelement(), xmldata_root_element_end(), and xmldata_root_element_start().

Referenced by query_to_xml(), query_to_xml_and_xmlschema(), and table_to_xml_internal().

◆ query_to_xmlschema()

Datum query_to_xmlschema ( PG_FUNCTION_ARGS  )

Definition at line 3102 of file xml.c.

3103{
3104 char *query = text_to_cstring(PG_GETARG_TEXT_PP(0));
3105 bool nulls = PG_GETARG_BOOL(1);
3106 bool tableforest = PG_GETARG_BOOL(2);
3107 const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3108 const char *result;
3110 Portal portal;
3111
3112 SPI_connect();
3113
3114 if ((plan = SPI_prepare(query, 0, NULL)) == NULL)
3115 elog(ERROR, "SPI_prepare(\"%s\") failed", query);
3116
3117 if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL)
3118 elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
3119
3121 InvalidOid, nulls,
3123 SPI_cursor_close(portal);
3124 SPI_finish();
3125
3127}

References _SPI_strdup(), cstring_to_xmltype(), elog, ERROR, fb(), InvalidOid, map_sql_table_to_xmlschema(), PG_GETARG_BOOL, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, plan, SPI_connect(), SPI_cursor_close(), SPI_cursor_open(), SPI_finish(), SPI_prepare(), text_to_cstring(), and PortalData::tupDesc.

◆ schema_get_xml_visible_tables()

static List * schema_get_xml_visible_tables ( Oid  nspid)
static

Definition at line 2852 of file xml.c.

2853{
2854 StringInfoData query;
2855
2856 initStringInfo(&query);
2857 appendStringInfo(&query, "SELECT oid FROM pg_catalog.pg_class"
2858 " WHERE relnamespace = %u AND relkind IN ("
2862 " AND pg_catalog.has_table_privilege (oid, 'SELECT')"
2863 " ORDER BY relname;", nspid);
2864
2865 return query_to_oid_list(query.data);
2866}

References appendStringInfo(), CppAsString2, StringInfoData::data, fb(), initStringInfo(), nspid, and query_to_oid_list().

Referenced by schema_to_xml_internal(), and schema_to_xmlschema_internal().

◆ schema_to_xml()

Datum schema_to_xml ( PG_FUNCTION_ARGS  )

Definition at line 3261 of file xml.c.

3262{
3264 bool nulls = PG_GETARG_BOOL(1);
3265 bool tableforest = PG_GETARG_BOOL(2);
3266 const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3267
3268 char *schemaname;
3269 Oid nspid;
3270
3271 schemaname = NameStr(*name);
3272 nspid = LookupExplicitNamespace(schemaname, false);
3273
3275 nulls, tableforest, targetns, true)));
3276}

References fb(), LookupExplicitNamespace(), name, NameStr, nspid, PG_GETARG_BOOL, PG_GETARG_NAME, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, schema_to_xml_internal(), stringinfo_to_xmltype(), and text_to_cstring().

◆ schema_to_xml_and_xmlschema()

Datum schema_to_xml_and_xmlschema ( PG_FUNCTION_ARGS  )

Definition at line 3365 of file xml.c.

3366{
3368 bool nulls = PG_GETARG_BOOL(1);
3369 bool tableforest = PG_GETARG_BOOL(2);
3370 const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3371 char *schemaname;
3372 Oid nspid;
3374
3375 schemaname = NameStr(*name);
3376 nspid = LookupExplicitNamespace(schemaname, false);
3377
3378 xmlschema = schema_to_xmlschema_internal(schemaname, nulls,
3380
3382 xmlschema->data, nulls,
3383 tableforest, targetns, true)));
3384}

References fb(), LookupExplicitNamespace(), name, NameStr, nspid, PG_GETARG_BOOL, PG_GETARG_NAME, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, schema_to_xml_internal(), schema_to_xmlschema_internal(), stringinfo_to_xmltype(), and text_to_cstring().

◆ schema_to_xml_internal()

static StringInfo schema_to_xml_internal ( Oid  nspid,
const char xmlschema,
bool  nulls,
bool  tableforest,
const char targetns,
bool  top_level 
)
static

Definition at line 3218 of file xml.c.

3220{
3221 StringInfo result;
3222 char *xmlsn;
3224 ListCell *cell;
3225
3227 true, false);
3228 result = makeStringInfo();
3229
3230 xmldata_root_element_start(result, xmlsn, xmlschema, targetns, top_level);
3231 appendStringInfoChar(result, '\n');
3232
3233 if (xmlschema)
3234 appendStringInfo(result, "%s\n\n", xmlschema);
3235
3236 SPI_connect();
3237
3239
3240 foreach(cell, relid_list)
3241 {
3242 Oid relid = lfirst_oid(cell);
3244
3246 targetns, false);
3247
3248 appendBinaryStringInfo(result, subres->data, subres->len);
3249 appendStringInfoChar(result, '\n');
3250 }
3251
3252 SPI_finish();
3253
3255
3256 return result;
3257}

References appendBinaryStringInfo(), appendStringInfo(), appendStringInfoChar(), StringInfoData::data, fb(), get_namespace_name(), lfirst_oid, makeStringInfo(), map_sql_identifier_to_xml_name(), nspid, schema_get_xml_visible_tables(), SPI_connect(), SPI_finish(), table_to_xml_internal(), xmldata_root_element_end(), and xmldata_root_element_start().

Referenced by database_to_xml_internal(), schema_to_xml(), and schema_to_xml_and_xmlschema().

◆ schema_to_xmlschema()

◆ schema_to_xmlschema_internal()

static StringInfo schema_to_xmlschema_internal ( const char schemaname,
bool  nulls,
bool  tableforest,
const char targetns 
)
static

◆ SPI_sql_row_to_xmlelement()

static void SPI_sql_row_to_xmlelement ( uint64  rownum,
StringInfo  result,
char tablename,
bool  nulls,
bool  tableforest,
const char targetns,
bool  top_level 
)
static

Definition at line 4123 of file xml.c.

4126{
4127 int i;
4128 char *xmltn;
4129
4130 if (tablename)
4131 xmltn = map_sql_identifier_to_xml_name(tablename, true, false);
4132 else
4133 {
4134 if (tableforest)
4135 xmltn = "row";
4136 else
4137 xmltn = "table";
4138 }
4139
4140 if (tableforest)
4141 xmldata_root_element_start(result, xmltn, NULL, targetns, top_level);
4142 else
4143 appendStringInfoString(result, "<row>\n");
4144
4145 for (i = 1; i <= SPI_tuptable->tupdesc->natts; i++)
4146 {
4147 char *colname;
4148 Datum colval;
4149 bool isnull;
4150
4152 true, false);
4155 i,
4156 &isnull);
4157 if (isnull)
4158 {
4159 if (nulls)
4160 appendStringInfo(result, " <%s xsi:nil=\"true\"/>\n", colname);
4161 }
4162 else
4163 appendStringInfo(result, " <%s>%s</%s>\n",
4164 colname,
4167 colname);
4168 }
4169
4170 if (tableforest)
4171 {
4173 appendStringInfoChar(result, '\n');
4174 }
4175 else
4176 appendStringInfoString(result, "</row>\n\n");
4177}

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), fb(), i, map_sql_identifier_to_xml_name(), map_sql_value_to_xml_value(), TupleDescData::natts, SPI_fname(), SPI_getbinval(), SPI_gettypeid(), SPI_tuptable, SPITupleTable::tupdesc, SPITupleTable::vals, xmldata_root_element_end(), and xmldata_root_element_start().

Referenced by cursor_to_xml(), and query_to_xml_internal().

◆ stringinfo_to_xmltype()

◆ table_to_xml()

Datum table_to_xml ( PG_FUNCTION_ARGS  )

Definition at line 2922 of file xml.c.

2923{
2924 Oid relid = PG_GETARG_OID(0);
2925 bool nulls = PG_GETARG_BOOL(1);
2926 bool tableforest = PG_GETARG_BOOL(2);
2927 const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
2928
2930 nulls, tableforest,
2931 targetns, true)));
2932}

References fb(), PG_GETARG_BOOL, PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, stringinfo_to_xmltype(), table_to_xml_internal(), and text_to_cstring().

◆ table_to_xml_and_xmlschema()

Datum table_to_xml_and_xmlschema ( PG_FUNCTION_ARGS  )

◆ table_to_xml_internal()

static StringInfo table_to_xml_internal ( Oid  relid,
const char xmlschema,
bool  nulls,
bool  tableforest,
const char targetns,
bool  top_level 
)
static

◆ table_to_xmlschema()

Datum table_to_xmlschema ( PG_FUNCTION_ARGS  )

Definition at line 3083 of file xml.c.

3084{
3085 Oid relid = PG_GETARG_OID(0);
3086 bool nulls = PG_GETARG_BOOL(1);
3087 bool tableforest = PG_GETARG_BOOL(2);
3088 const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
3089 const char *result;
3090 Relation rel;
3091
3092 rel = table_open(relid, AccessShareLock);
3093 result = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls,
3095 table_close(rel, NoLock);
3096
3098}

References AccessShareLock, cstring_to_xmltype(), fb(), map_sql_table_to_xmlschema(), NoLock, PG_GETARG_BOOL, PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, RelationData::rd_att, table_close(), table_open(), and text_to_cstring().

◆ texttoxml()

Datum texttoxml ( PG_FUNCTION_ARGS  )

Definition at line 658 of file xml.c.

659{
661
663}

References data, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, xmloption, and xmlparse().

◆ xml_in()

Datum xml_in ( PG_FUNCTION_ARGS  )

Definition at line 272 of file xml.c.

273{
274#ifdef USE_LIBXML
275 char *s = PG_GETARG_CSTRING(0);
278
279 /* Build the result object. */
281
282 /*
283 * Parse the data to check if it is well-formed XML data.
284 *
285 * Note: we don't need to worry about whether a soft error is detected.
286 */
288 NULL, NULL, fcinfo->context);
289 if (doc != NULL)
291
293#else
295 return 0;
296#endif
297}

References cstring_to_text(), fb(), GetDatabaseEncoding(), NO_XML_SUPPORT, PG_GETARG_CSTRING, PG_RETURN_XML_P, and xmloption.

◆ xml_is_document()

bool xml_is_document ( xmltype arg)

Definition at line 1167 of file xml.c.

1168{
1169#ifdef USE_LIBXML
1170 xmlDocPtr doc;
1172
1173 /*
1174 * We'll report "true" if no soft error is reported by xml_parse().
1175 */
1177 GetDatabaseEncoding(), NULL, NULL, (Node *) &escontext);
1178 if (doc)
1179 xmlFreeDoc(doc);
1180
1181 return !escontext.error_occurred;
1182#else /* not USE_LIBXML */
1184 return false;
1185#endif /* not USE_LIBXML */
1186}

References arg, ErrorSaveContext::error_occurred, fb(), GetDatabaseEncoding(), NO_XML_SUPPORT, and XMLOPTION_DOCUMENT.

Referenced by ExecEvalXmlExpr().

◆ xml_is_well_formed()

Datum xml_is_well_formed ( PG_FUNCTION_ARGS  )

Definition at line 4653 of file xml.c.

4654{
4655#ifdef USE_LIBXML
4657
4659#else
4661 return 0;
4662#endif /* not USE_LIBXML */
4663}

References data, fb(), NO_XML_SUPPORT, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, and xmloption.

◆ xml_is_well_formed_content()

Datum xml_is_well_formed_content ( PG_FUNCTION_ARGS  )

Definition at line 4679 of file xml.c.

4680{
4681#ifdef USE_LIBXML
4683
4685#else
4687 return 0;
4688#endif /* not USE_LIBXML */
4689}

References data, fb(), NO_XML_SUPPORT, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, and XMLOPTION_CONTENT.

◆ xml_is_well_formed_document()

Datum xml_is_well_formed_document ( PG_FUNCTION_ARGS  )

Definition at line 4666 of file xml.c.

4667{
4668#ifdef USE_LIBXML
4670
4672#else
4674 return 0;
4675#endif /* not USE_LIBXML */
4676}

References data, fb(), NO_XML_SUPPORT, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, and XMLOPTION_DOCUMENT.

◆ xml_out()

Datum xml_out ( PG_FUNCTION_ARGS  )

Definition at line 355 of file xml.c.

356{
358
359 /*
360 * xml_out removes the encoding property in all cases. This is because we
361 * cannot control from here whether the datum will be converted to a
362 * different client encoding, so we'd do more harm than good by including
363 * it.
364 */
366}

References PG_GETARG_XML_P, PG_RETURN_CSTRING, x, and xml_out_internal().

◆ xml_out_internal()

static char * xml_out_internal ( xmltype x,
pg_enc  target_encoding 
)
static

Definition at line 311 of file xml.c.

312{
313 char *str = text_to_cstring((text *) x);
314
315#ifdef USE_LIBXML
316 size_t len = strlen(str);
317 xmlChar *version;
318 int standalone;
319 int res_code;
320
322 &len, &version, NULL, &standalone)) == 0)
323 {
325
327
329 {
330 /*
331 * If we are not going to produce an XML declaration, eat a single
332 * newline in the original string to prevent empty first lines in
333 * the output.
334 */
335 if (*(str + len) == '\n')
336 len += 1;
337 }
339
340 pfree(str);
341
342 return buf.data;
343 }
344
347 errmsg_internal("could not parse XML declaration in stored value"),
349#endif
350 return str;
351}

References appendStringInfoString(), buf, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), fb(), initStringInfo(), len, pfree(), str, text_to_cstring(), WARNING, and x.

Referenced by xml_out(), xml_send(), and XmlTableSetDocument().

◆ xml_recv()

Datum xml_recv ( PG_FUNCTION_ARGS  )

Definition at line 370 of file xml.c.

371{
372#ifdef USE_LIBXML
374 xmltype *result;
375 char *str;
376 char *newstr;
377 int nbytes;
380 int encoding;
381
382 /*
383 * Read the data in raw format. We don't know yet what the encoding is, as
384 * that information is embedded in the xml declaration; so we have to
385 * parse that before converting to server encoding.
386 */
387 nbytes = buf->len - buf->cursor;
388 str = (char *) pq_getmsgbytes(buf, nbytes);
389
390 /*
391 * We need a null-terminated string to pass to parse_xml_decl(). Rather
392 * than make a separate copy, make the temporary result one byte bigger
393 * than it needs to be.
394 */
395 result = palloc(nbytes + 1 + VARHDRSZ);
396 SET_VARSIZE(result, nbytes + VARHDRSZ);
397 memcpy(VARDATA(result), str, nbytes);
398 str = VARDATA(result);
399 str[nbytes] = '\0';
400
402
403 /*
404 * If encoding wasn't explicitly specified in the XML header, treat it as
405 * UTF-8, as that's the default in XML. This is different from xml_in(),
406 * where the input has to go through the normal client to server encoding
407 * conversion.
408 */
410
411 /*
412 * Parse the data to check if it is well-formed XML data. Assume that
413 * xml_parse will throw ERROR if not.
414 */
415 doc = xml_parse(result, xmloption, true, encoding, NULL, NULL, NULL);
417
418 /* Now that we know what we're dealing with, convert to server encoding */
420
421 if (newstr != str)
422 {
423 pfree(result);
424 result = (xmltype *) cstring_to_text(newstr);
425 pfree(newstr);
426 }
427
428 PG_RETURN_XML_P(result);
429#else
431 return 0;
432#endif
433}

References buf, cstring_to_text(), encoding, fb(), NO_XML_SUPPORT, palloc(), pfree(), pg_any_to_server(), PG_GETARG_POINTER, PG_RETURN_XML_P, PG_UTF8, pq_getmsgbytes(), SET_VARSIZE(), str, VARDATA(), VARHDRSZ, and xmloption.

◆ xml_send()

Datum xml_send ( PG_FUNCTION_ARGS  )

Definition at line 437 of file xml.c.

438{
440 char *outval;
442
443 /*
444 * xml_out_internal doesn't convert the encoding, it just prints the right
445 * declaration. pq_sendtext will do the conversion.
446 */
448
451 pfree(outval);
453}

References buf, fb(), pfree(), pg_get_client_encoding(), PG_GETARG_XML_P, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendtext(), x, and xml_out_internal().

◆ xmlcomment()

Datum xmlcomment ( PG_FUNCTION_ARGS  )

Definition at line 490 of file xml.c.

491{
492#ifdef USE_LIBXML
494 char *argdata = VARDATA_ANY(arg);
497 int i;
498
499 /* check for "--" in string or "-" at the end */
500 for (i = 1; i < len; i++)
501 {
502 if (argdata[i] == '-' && argdata[i - 1] == '-')
505 errmsg("invalid XML comment")));
506 }
507 if (len > 0 && argdata[len - 1] == '-')
510 errmsg("invalid XML comment")));
511
513 appendStringInfoString(&buf, "<!--");
516
518#else
520 return 0;
521#endif
522}

References appendStringInfoString(), appendStringInfoText(), arg, buf, ereport, errcode(), errmsg(), ERROR, fb(), i, initStringInfo(), len, NO_XML_SUPPORT, PG_GETARG_TEXT_PP, PG_RETURN_XML_P, stringinfo_to_xmltype(), VARDATA_ANY(), and VARSIZE_ANY_EXHDR().

◆ xmlconcat()

xmltype * xmlconcat ( List args)

Definition at line 574 of file xml.c.

575{
576#ifdef USE_LIBXML
577 int global_standalone = 1;
579 bool global_version_no_value = false;
581 ListCell *v;
582
584 foreach(v, args)
585 {
587 size_t len;
588 xmlChar *version;
589 int standalone;
590 char *str;
591
592 len = VARSIZE(x) - VARHDRSZ;
593 str = text_to_cstring((text *) x);
594
595 parse_xml_decl((xmlChar *) str, &len, &version, NULL, &standalone);
596
597 if (standalone == 0 && global_standalone == 1)
599 if (standalone < 0)
601
602 if (!version)
604 else if (!global_version)
605 global_version = version;
606 else if (xmlStrcmp(version, global_version) != 0)
608
610 pfree(str);
611 }
612
614 {
615 StringInfoData buf2;
616
617 initStringInfo(&buf2);
618
619 print_xml_decl(&buf2,
621 0,
623
624 appendBinaryStringInfo(&buf2, buf.data, buf.len);
625 buf = buf2;
626 }
627
628 return stringinfo_to_xmltype(&buf);
629#else
631 return NULL;
632#endif
633}

References appendBinaryStringInfo(), appendStringInfoString(), buf, StringInfoData::data, DatumGetXmlP(), fb(), initStringInfo(), len, lfirst, NO_XML_SUPPORT, pfree(), PointerGetDatum(), str, stringinfo_to_xmltype(), text_to_cstring(), VARHDRSZ, VARSIZE(), and x.

Referenced by ExecEvalXmlExpr(), and xmlconcat2().

◆ xmlconcat2()

Datum xmlconcat2 ( PG_FUNCTION_ARGS  )

Definition at line 640 of file xml.c.

641{
642 if (PG_ARGISNULL(0))
643 {
644 if (PG_ARGISNULL(1))
646 else
648 }
649 else if (PG_ARGISNULL(1))
651 else
653 PG_GETARG_XML_P(1))));
654}

References list_make2, PG_ARGISNULL, PG_GETARG_XML_P, PG_RETURN_NULL, PG_RETURN_XML_P, and xmlconcat().

◆ xmldata_root_element_end()

static void xmldata_root_element_end ( StringInfo  result,
const char eltname 
)
static

Definition at line 3031 of file xml.c.

3032{
3033 appendStringInfo(result, "</%s>\n", eltname);
3034}

References appendStringInfo(), and fb().

Referenced by cursor_to_xml(), database_to_xml_internal(), query_to_xml_internal(), schema_to_xml_internal(), and SPI_sql_row_to_xmlelement().

◆ xmldata_root_element_start()

static void xmldata_root_element_start ( StringInfo  result,
const char eltname,
const char xmlschema,
const char targetns,
bool  top_level 
)
static

Definition at line 3004 of file xml.c.

3007{
3008 /* This isn't really wrong but currently makes no sense. */
3009 Assert(top_level || !xmlschema);
3010
3011 appendStringInfo(result, "<%s", eltname);
3012 if (top_level)
3013 {
3014 appendStringInfoString(result, " xmlns:xsi=\"" NAMESPACE_XSI "\"");
3015 if (strlen(targetns) > 0)
3016 appendStringInfo(result, " xmlns=\"%s\"", targetns);
3017 }
3018 if (xmlschema)
3019 {
3020 /* FIXME: better targets */
3021 if (strlen(targetns) > 0)
3022 appendStringInfo(result, " xsi:schemaLocation=\"%s #\"", targetns);
3023 else
3024 appendStringInfoString(result, " xsi:noNamespaceSchemaLocation=\"#\"");
3025 }
3026 appendStringInfoString(result, ">\n");
3027}

References appendStringInfo(), appendStringInfoString(), Assert, fb(), and NAMESPACE_XSI.

Referenced by cursor_to_xml(), database_to_xml_internal(), query_to_xml_internal(), schema_to_xml_internal(), and SPI_sql_row_to_xmlelement().

◆ xmlelement()

xmltype * xmlelement ( XmlExpr xexpr,
const Datum named_argvalue,
const bool named_argnull,
const Datum argvalue,
const bool argnull 
)

Definition at line 893 of file xml.c.

896{
897#ifdef USE_LIBXML
898 xmltype *result;
901 int i;
902 ListCell *arg;
903 ListCell *narg;
905 volatile xmlBufferPtr buf = NULL;
906 volatile xmlTextWriterPtr writer = NULL;
907
908 /*
909 * All arguments are already evaluated, and their values are passed in the
910 * named_argvalue/named_argnull or argvalue/argnull arrays. This avoids
911 * issues if one of the arguments involves a call to some other function
912 * or subsystem that wants to use libxml on its own terms. We examine the
913 * original XmlExpr to identify the numbers and types of the arguments.
914 */
916 i = 0;
917 foreach(arg, xexpr->named_args)
918 {
919 Expr *e = (Expr *) lfirst(arg);
920 char *str;
921
922 if (named_argnull[i])
923 str = NULL;
924 else
925 str = map_sql_value_to_xml_value(named_argvalue[i],
926 exprType((Node *) e),
927 false);
929 i++;
930 }
931
933 i = 0;
934 foreach(arg, xexpr->args)
935 {
936 Expr *e = (Expr *) lfirst(arg);
937 char *str;
938
939 /* here we can just forget NULL elements immediately */
940 if (!argnull[i])
941 {
942 str = map_sql_value_to_xml_value(argvalue[i],
943 exprType((Node *) e),
944 true);
946 }
947 i++;
948 }
949
951
952 PG_TRY();
953 {
955 if (buf == NULL || xmlerrcxt->err_occurred)
957 "could not allocate xmlBuffer");
959 if (writer == NULL || xmlerrcxt->err_occurred)
961 "could not allocate xmlTextWriter");
962
963 if (xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name) < 0 ||
964 xmlerrcxt->err_occurred)
966 "could not start xml element");
967
968 forboth(arg, named_arg_strings, narg, xexpr->arg_names)
969 {
970 char *str = (char *) lfirst(arg);
971 char *argname = strVal(lfirst(narg));
972
973 if (str)
974 {
976 (xmlChar *) argname,
977 (xmlChar *) str) < 0 ||
978 xmlerrcxt->err_occurred)
980 "could not write xml attribute");
981 }
982 }
983
984 foreach(arg, arg_strings)
985 {
986 char *str = (char *) lfirst(arg);
987
988 if (xmlTextWriterWriteRaw(writer, (xmlChar *) str) < 0 ||
989 xmlerrcxt->err_occurred)
991 "could not write raw xml text");
992 }
993
995 xmlerrcxt->err_occurred)
997 "could not end xml element");
998
999 /* we MUST do this now to flush data out to the buffer ... */
1001 writer = NULL;
1002
1003 result = xmlBuffer_to_xmltype(buf);
1004 }
1005 PG_CATCH();
1006 {
1007 if (writer)
1009 if (buf)
1011
1012 pg_xml_done(xmlerrcxt, true);
1013
1014 PG_RE_THROW();
1015 }
1016 PG_END_TRY();
1017
1019
1020 pg_xml_done(xmlerrcxt, false);
1021
1022 return result;
1023#else
1025 return NULL;
1026#endif
1027}

References arg, XmlExpr::args, buf, ERROR, exprType(), fb(), forboth, i, lappend(), lfirst, map_sql_value_to_xml_value(), XmlExpr::named_args, NIL, NO_XML_SUPPORT, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pg_xml_done(), pg_xml_init(), PG_XML_STRICTNESS_ALL, str, strVal, and xml_ereport().

Referenced by ExecEvalXmlExpr().

◆ xmlexists()

Datum xmlexists ( PG_FUNCTION_ARGS  )

Definition at line 4588 of file xml.c.

4589{
4590#ifdef USE_LIBXML
4593 int res_nitems;
4594
4596 &res_nitems, NULL);
4597
4599#else
4601 return 0;
4602#endif
4603}

References data, fb(), NO_XML_SUPPORT, PG_GETARG_TEXT_PP, PG_GETARG_XML_P, and PG_RETURN_BOOL.

◆ xmlparse()

xmltype * xmlparse ( text data,
XmlOptionType  xmloption_arg,
bool  preserve_whitespace 
)

Definition at line 1031 of file xml.c.

1032{
1033#ifdef USE_LIBXML
1034 xmlDocPtr doc;
1035
1038 xmlFreeDoc(doc);
1039
1040 return (xmltype *) data;
1041#else
1043 return NULL;
1044#endif
1045}

References data, fb(), GetDatabaseEncoding(), and NO_XML_SUPPORT.

Referenced by ExecEvalXmlExpr(), and texttoxml().

◆ xmlpi()

xmltype * xmlpi ( const char target,
text arg,
bool  arg_is_null,
bool result_is_null 
)

Definition at line 1049 of file xml.c.

1050{
1051#ifdef USE_LIBXML
1052 xmltype *result;
1054
1055 if (pg_strcasecmp(target, "xml") == 0)
1056 ereport(ERROR,
1058 errmsg("invalid XML processing instruction"),
1059 errdetail("XML processing instruction target name cannot be \"%s\".", target)));
1060
1061 /*
1062 * Following the SQL standard, the null check comes after the syntax check
1063 * above.
1064 */
1066 if (*result_is_null)
1067 return NULL;
1068
1070
1071 appendStringInfo(&buf, "<?%s", target);
1072
1073 if (arg != NULL)
1074 {
1075 char *string;
1076
1077 string = text_to_cstring(arg);
1078 if (strstr(string, "?>") != NULL)
1079 ereport(ERROR,
1081 errmsg("invalid XML processing instruction"),
1082 errdetail("XML processing instruction cannot contain \"?>\".")));
1083
1085 appendStringInfoString(&buf, string + strspn(string, " "));
1086 pfree(string);
1087 }
1089
1090 result = stringinfo_to_xmltype(&buf);
1091 pfree(buf.data);
1092 return result;
1093#else
1095 return NULL;
1096#endif
1097}

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, buf, ereport, errcode(), errdetail(), errmsg(), ERROR, fb(), initStringInfo(), NO_XML_SUPPORT, pfree(), pg_strcasecmp(), stringinfo_to_xmltype(), and text_to_cstring().

Referenced by ExecEvalXmlExpr().

◆ xmlroot()

xmltype * xmlroot ( xmltype data,
text version,
int  standalone 
)

Definition at line 1101 of file xml.c.

1102{
1103#ifdef USE_LIBXML
1104 char *str;
1105 size_t len;
1107 int orig_standalone;
1109
1110 len = VARSIZE(data) - VARHDRSZ;
1112
1114
1115 if (version)
1116 orig_version = xml_text2xmlChar(version);
1117 else
1119
1120 switch (standalone)
1121 {
1122 case XML_STANDALONE_YES:
1123 orig_standalone = 1;
1124 break;
1125 case XML_STANDALONE_NO:
1126 orig_standalone = 0;
1127 break;
1129 orig_standalone = -1;
1130 break;
1132 /* leave original value */
1133 break;
1134 }
1135
1139
1140 return stringinfo_to_xmltype(&buf);
1141#else
1143 return NULL;
1144#endif
1145}

References appendStringInfoString(), buf, data, fb(), initStringInfo(), len, NO_XML_SUPPORT, str, stringinfo_to_xmltype(), text_to_cstring(), VARHDRSZ, VARSIZE(), XML_STANDALONE_NO, XML_STANDALONE_NO_VALUE, XML_STANDALONE_OMITTED, and XML_STANDALONE_YES.

Referenced by ExecEvalXmlExpr().

◆ XmlTableDestroyOpaque()

static void XmlTableDestroyOpaque ( struct TableFuncScanState state)
static

Definition at line 5123 of file xml.c.

5124{
5125#ifdef USE_LIBXML
5127
5128 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableDestroyOpaque");
5129
5130 /* Propagate our own error context to libxml2 */
5132
5133 if (xtCxt->xpathscomp != NULL)
5134 {
5135 int i;
5136
5137 for (i = 0; i < xtCxt->natts; i++)
5138 if (xtCxt->xpathscomp[i] != NULL)
5139 xmlXPathFreeCompExpr(xtCxt->xpathscomp[i]);
5140 }
5141
5142 if (xtCxt->xpathobj != NULL)
5143 xmlXPathFreeObject(xtCxt->xpathobj);
5144 if (xtCxt->xpathcomp != NULL)
5145 xmlXPathFreeCompExpr(xtCxt->xpathcomp);
5146 if (xtCxt->xpathcxt != NULL)
5147 xmlXPathFreeContext(xtCxt->xpathcxt);
5148 if (xtCxt->doc != NULL)
5149 xmlFreeDoc(xtCxt->doc);
5150 if (xtCxt->ctxt != NULL)
5151 xmlFreeParserCtxt(xtCxt->ctxt);
5152
5153 pg_xml_done(xtCxt->xmlerrcxt, true);
5154
5155 /* not valid anymore */
5156 xtCxt->magic = 0;
5157 state->opaque = NULL;
5158
5159#else
5161#endif /* not USE_LIBXML */
5162}

References fb(), i, NO_XML_SUPPORT, and pg_xml_done().

◆ XmlTableFetchRow()

static bool XmlTableFetchRow ( struct TableFuncScanState state)
static

Definition at line 4926 of file xml.c.

4927{
4928#ifdef USE_LIBXML
4930
4931 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableFetchRow");
4932
4933 /* Propagate our own error context to libxml2 */
4935
4936 if (xtCxt->xpathobj == NULL)
4937 {
4938 xtCxt->xpathobj = xmlXPathCompiledEval(xtCxt->xpathcomp, xtCxt->xpathcxt);
4939 if (xtCxt->xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)
4941 "could not create XPath object");
4942
4943 xtCxt->row_count = 0;
4944 }
4945
4946 if (xtCxt->xpathobj->type == XPATH_NODESET)
4947 {
4948 if (xtCxt->xpathobj->nodesetval != NULL)
4949 {
4950 if (xtCxt->row_count++ < xtCxt->xpathobj->nodesetval->nodeNr)
4951 return true;
4952 }
4953 }
4954
4955 return false;
4956#else
4958 return false;
4959#endif /* not USE_LIBXML */
4960}

References ERROR, fb(), NO_XML_SUPPORT, and xml_ereport().

◆ XmlTableGetValue()

static Datum XmlTableGetValue ( struct TableFuncScanState state,
int  colnum,
Oid  typid,
int32  typmod,
bool isnull 
)
static

Definition at line 4971 of file xml.c.

4973{
4974#ifdef USE_LIBXML
4975 Datum result = (Datum) 0;
4977 volatile xmlXPathObjectPtr xpathobj = NULL;
4978
4979 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableGetValue");
4980
4981 Assert(xtCxt->xpathobj &&
4982 xtCxt->xpathobj->type == XPATH_NODESET &&
4983 xtCxt->xpathobj->nodesetval != NULL);
4984
4985 /* Propagate our own error context to libxml2 */
4987
4988 *isnull = false;
4989
4990 Assert(xtCxt->xpathscomp[colnum] != NULL);
4991
4992 PG_TRY();
4993 {
4995 char *cstr = NULL;
4996
4997 /* Set current node as entry point for XPath evaluation */
4998 cur = xtCxt->xpathobj->nodesetval->nodeTab[xtCxt->row_count - 1];
4999 xtCxt->xpathcxt->node = cur;
5000
5001 /* Evaluate column path */
5002 xpathobj = xmlXPathCompiledEval(xtCxt->xpathscomp[colnum], xtCxt->xpathcxt);
5003 if (xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)
5005 "could not create XPath object");
5006
5007 /*
5008 * There are four possible cases, depending on the number of nodes
5009 * returned by the XPath expression and the type of the target column:
5010 * a) XPath returns no nodes. b) The target type is XML (return all
5011 * as XML). For non-XML return types: c) One node (return content).
5012 * d) Multiple nodes (error).
5013 */
5014 if (xpathobj->type == XPATH_NODESET)
5015 {
5016 int count = 0;
5017
5018 if (xpathobj->nodesetval != NULL)
5019 count = xpathobj->nodesetval->nodeNr;
5020
5021 if (xpathobj->nodesetval == NULL || count == 0)
5022 {
5023 *isnull = true;
5024 }
5025 else
5026 {
5027 if (typid == XMLOID)
5028 {
5029 text *textstr;
5031
5032 /* Concatenate serialized values */
5034 for (int i = 0; i < count; i++)
5035 {
5036 textstr =
5037 xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],
5038 xtCxt->xmlerrcxt);
5039
5041 }
5042 cstr = str.data;
5043 }
5044 else
5045 {
5046 xmlChar *str;
5047
5048 if (count > 1)
5049 ereport(ERROR,
5051 errmsg("more than one value returned by column XPath expression")));
5052
5054 cstr = str ? xml_pstrdup_and_free(str) : "";
5055 }
5056 }
5057 }
5058 else if (xpathobj->type == XPATH_STRING)
5059 {
5060 /* Content should be escaped when target will be XML */
5061 if (typid == XMLOID)
5062 cstr = escape_xml((char *) xpathobj->stringval);
5063 else
5064 cstr = (char *) xpathobj->stringval;
5065 }
5066 else if (xpathobj->type == XPATH_BOOLEAN)
5067 {
5068 char typcategory;
5069 bool typispreferred;
5070 xmlChar *str;
5071
5072 /* Allow implicit casting from boolean to numbers */
5074
5077 else
5079
5081 }
5082 else if (xpathobj->type == XPATH_NUMBER)
5083 {
5084 xmlChar *str;
5085
5088 }
5089 else
5090 elog(ERROR, "unexpected XPath object type %u", xpathobj->type);
5091
5092 /*
5093 * By here, either cstr contains the result value, or the isnull flag
5094 * has been set.
5095 */
5096 Assert(cstr || *isnull);
5097
5098 if (!*isnull)
5099 result = InputFunctionCall(&state->in_functions[colnum],
5100 cstr,
5101 state->typioparams[colnum],
5102 typmod);
5103 }
5104 PG_FINALLY();
5105 {
5106 if (xpathobj != NULL)
5108 }
5109 PG_END_TRY();
5110
5111 return result;
5112#else
5114 return 0;
5115#endif /* not USE_LIBXML */
5116}

References appendStringInfoText(), Assert, cur, elog, ereport, errcode(), errmsg(), ERROR, escape_xml(), fb(), get_type_category_preferred(), i, initStringInfo(), InputFunctionCall(), NO_XML_SUPPORT, PG_END_TRY, PG_FINALLY, PG_TRY, str, and xml_ereport().

◆ XmlTableInitOpaque()

static void XmlTableInitOpaque ( struct TableFuncScanState state,
int  natts 
)
static

Definition at line 4728 of file xml.c.

4729{
4730#ifdef USE_LIBXML
4731 volatile xmlParserCtxtPtr ctxt = NULL;
4734
4737 xtCxt->natts = natts;
4738 xtCxt->xpathscomp = palloc0_array(xmlXPathCompExprPtr, natts);
4739
4741
4742 PG_TRY();
4743 {
4744 xmlInitParser();
4745
4746 ctxt = xmlNewParserCtxt();
4747 if (ctxt == NULL || xmlerrcxt->err_occurred)
4749 "could not allocate parser context");
4750 }
4751 PG_CATCH();
4752 {
4753 if (ctxt != NULL)
4754 xmlFreeParserCtxt(ctxt);
4755
4756 pg_xml_done(xmlerrcxt, true);
4757
4758 PG_RE_THROW();
4759 }
4760 PG_END_TRY();
4761
4762 xtCxt->xmlerrcxt = xmlerrcxt;
4763 xtCxt->ctxt = ctxt;
4764
4765 state->opaque = xtCxt;
4766#else
4768#endif /* not USE_LIBXML */
4769}

References ERROR, fb(), NO_XML_SUPPORT, palloc0_array, palloc0_object, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pg_xml_done(), pg_xml_init(), PG_XML_STRICTNESS_ALL, and xml_ereport().

◆ XmlTableSetColumnFilter()

static void XmlTableSetColumnFilter ( struct TableFuncScanState state,
const char path,
int  colnum 
)
static

Definition at line 4891 of file xml.c.

4892{
4893#ifdef USE_LIBXML
4895 xmlChar *xstr;
4896
4897 Assert(path);
4898
4899 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetColumnFilter");
4900
4901 if (*path == '\0')
4902 ereport(ERROR,
4904 errmsg("column path filter must not be empty string")));
4905
4906 xstr = pg_xmlCharStrndup(path, strlen(path));
4907
4908 /* We require XmlTableSetDocument to have been done already */
4909 Assert(xtCxt->xpathcxt != NULL);
4910
4911 xtCxt->xpathscomp[colnum] = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);
4912 if (xtCxt->xpathscomp[colnum] == NULL || xtCxt->xmlerrcxt->err_occurred)
4914 "invalid XPath expression");
4915#else
4917#endif /* not USE_LIBXML */
4918}

References Assert, ereport, errcode(), errmsg(), ERROR, fb(), NO_XML_SUPPORT, and xml_ereport().

◆ XmlTableSetDocument()

static void XmlTableSetDocument ( struct TableFuncScanState state,
Datum  value 
)
static

Definition at line 4776 of file xml.c.

4777{
4778#ifdef USE_LIBXML
4781 char *str;
4782 xmlChar *xstr;
4783 int length;
4784 volatile xmlDocPtr doc = NULL;
4785 volatile xmlXPathContextPtr xpathcxt = NULL;
4786
4787 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetDocument");
4788
4789 /*
4790 * Use out function for casting to string (remove encoding property). See
4791 * comment in xml_out.
4792 */
4794
4795 length = strlen(str);
4796 xstr = pg_xmlCharStrndup(str, length);
4797
4798 PG_TRY();
4799 {
4800 doc = xmlCtxtReadMemory(xtCxt->ctxt, (char *) xstr, length, NULL, NULL, 0);
4801 if (doc == NULL || xtCxt->xmlerrcxt->err_occurred)
4803 "could not parse XML document");
4805 if (xpathcxt == NULL || xtCxt->xmlerrcxt->err_occurred)
4807 "could not allocate XPath context");
4808 xpathcxt->node = (xmlNodePtr) doc;
4809 }
4810 PG_CATCH();
4811 {
4812 if (xpathcxt != NULL)
4814 if (doc != NULL)
4815 xmlFreeDoc(doc);
4816
4817 PG_RE_THROW();
4818 }
4819 PG_END_TRY();
4820
4821 xtCxt->doc = doc;
4822 xtCxt->xpathcxt = xpathcxt;
4823#else
4825#endif /* not USE_LIBXML */
4826}

References DatumGetXmlP(), ERROR, fb(), NO_XML_SUPPORT, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, str, value, xml_ereport(), and xml_out_internal().

◆ XmlTableSetNamespace()

static void XmlTableSetNamespace ( struct TableFuncScanState state,
const char name,
const char uri 
)
static

Definition at line 4833 of file xml.c.

4834{
4835#ifdef USE_LIBXML
4837
4838 if (name == NULL)
4839 ereport(ERROR,
4841 errmsg("DEFAULT namespace is not supported")));
4842 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetNamespace");
4843
4844 if (xmlXPathRegisterNs(xtCxt->xpathcxt,
4848 "could not set XML namespace");
4849#else
4851#endif /* not USE_LIBXML */
4852}

References ereport, errcode(), errmsg(), ERROR, fb(), name, NO_XML_SUPPORT, and xml_ereport().

◆ XmlTableSetRowFilter()

static void XmlTableSetRowFilter ( struct TableFuncScanState state,
const char path 
)
static

Definition at line 4859 of file xml.c.

4860{
4861#ifdef USE_LIBXML
4863 xmlChar *xstr;
4864
4865 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetRowFilter");
4866
4867 if (*path == '\0')
4868 ereport(ERROR,
4870 errmsg("row path filter must not be empty string")));
4871
4872 xstr = pg_xmlCharStrndup(path, strlen(path));
4873
4874 /* We require XmlTableSetDocument to have been done already */
4875 Assert(xtCxt->xpathcxt != NULL);
4876
4877 xtCxt->xpathcomp = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);
4878 if (xtCxt->xpathcomp == NULL || xtCxt->xmlerrcxt->err_occurred)
4880 "invalid XPath expression");
4881#else
4883#endif /* not USE_LIBXML */
4884}

References Assert, ereport, errcode(), errmsg(), ERROR, fb(), NO_XML_SUPPORT, and xml_ereport().

◆ xmltext()

Datum xmltext ( PG_FUNCTION_ARGS  )

Definition at line 526 of file xml.c.

527{
528#ifdef USE_LIBXML
530 text *result;
531 volatile xmlChar *xmlbuf = NULL;
533
534 /* First we gotta spin up some error handling. */
536
537 PG_TRY();
538 {
540
541 if (xmlbuf == NULL || xmlerrcxt->err_occurred)
543 "could not allocate xmlChar");
544
545 result = cstring_to_text_with_len((const char *) xmlbuf,
546 xmlStrlen((const xmlChar *) xmlbuf));
547 }
548 PG_CATCH();
549 {
550 if (xmlbuf)
552
553 pg_xml_done(xmlerrcxt, true);
554 PG_RE_THROW();
555 }
556 PG_END_TRY();
557
559 pg_xml_done(xmlerrcxt, false);
560
561 PG_RETURN_XML_P(result);
562#else
564 return 0;
565#endif /* not USE_LIBXML */
566}

References arg, cstring_to_text_with_len(), ERROR, fb(), NO_XML_SUPPORT, PG_CATCH, PG_END_TRY, PG_GETARG_TEXT_PP, PG_RE_THROW, PG_RETURN_XML_P, PG_TRY, pg_xml_done(), pg_xml_init(), PG_XML_STRICTNESS_ALL, and xml_ereport().

◆ xmltotext()

Datum xmltotext ( PG_FUNCTION_ARGS  )

Definition at line 667 of file xml.c.

668{
670
671 /* It's actually binary compatible. */
673}

References data, PG_GETARG_XML_P, and PG_RETURN_TEXT_P.

◆ xmltotext_with_options()

text * xmltotext_with_options ( xmltype data,
XmlOptionType  xmloption_arg,
bool  indent 
)

Definition at line 677 of file xml.c.

678{
679#ifdef USE_LIBXML
680 text *volatile result;
684 volatile xmlBufferPtr buf = NULL;
685 volatile xmlSaveCtxtPtr ctxt = NULL;
687 PgXmlErrorContext *volatile xmlerrcxt = NULL;
688#endif
689
690 if (xmloption_arg != XMLOPTION_DOCUMENT && !indent)
691 {
692 /*
693 * We don't actually need to do anything, so just return the
694 * binary-compatible input. For backwards-compatibility reasons,
695 * allow such cases to succeed even without USE_LIBXML.
696 */
697 return (text *) data;
698 }
699
700#ifdef USE_LIBXML
701
702 /*
703 * Parse the input according to the xmloption.
704 *
705 * preserve_whitespace is set to false in case we are indenting, otherwise
706 * libxml2 will fail to indent elements that have whitespace between them.
707 */
710 (Node *) &escontext);
711 if (doc == NULL || escontext.error_occurred)
712 {
713 if (doc)
715 /* A soft error must be failure to conform to XMLOPTION_DOCUMENT */
718 errmsg("not an XML document")));
719 }
720
721 /* If we weren't asked to indent, we're done. */
722 if (!indent)
723 {
725 return (text *) data;
726 }
727
728 /*
729 * Otherwise, we gotta spin up some error handling. Unlike most other
730 * routines in this module, we already have a libxml "doc" structure to
731 * free, so we need to call pg_xml_init() inside the PG_TRY and be
732 * prepared for it to fail (typically due to palloc OOM).
733 */
734 PG_TRY();
735 {
736 size_t decl_len = 0;
737
739
740 /* The serialized data will go into this buffer. */
742
743 if (buf == NULL || xmlerrcxt->err_occurred)
745 "could not allocate xmlBuffer");
746
747 /* Detect whether there's an XML declaration */
749
750 /*
751 * Emit declaration only if the input had one. Note: some versions of
752 * xmlSaveToBuffer leak memory if a non-null encoding argument is
753 * passed, so don't do that. We don't want any encoding conversion
754 * anyway.
755 */
756 if (decl_len == 0)
757 ctxt = xmlSaveToBuffer(buf, NULL,
759 else
760 ctxt = xmlSaveToBuffer(buf, NULL,
762
763 if (ctxt == NULL || xmlerrcxt->err_occurred)
765 "could not allocate xmlSaveCtxt");
766
768 {
769 /* If it's a document, saving is easy. */
770 if (xmlSaveDoc(ctxt, doc) == -1 || xmlerrcxt->err_occurred)
772 "could not save document to xmlBuffer");
773 }
774 else if (content_nodes != NULL)
775 {
776 /*
777 * Deal with the case where we have non-singly-rooted XML.
778 * libxml's dump functions don't work well for that without help.
779 * We build a fake root node that serves as a container for the
780 * content nodes, and then iterate over the nodes.
781 */
785
786 root = xmlNewNode(NULL, (const xmlChar *) "content-root");
787 if (root == NULL || xmlerrcxt->err_occurred)
789 "could not allocate xml node");
790
791 /*
792 * This attaches root to doc, so we need not free it separately...
793 * but instead, we have to free the old root if there was one.
794 */
796 if (oldroot != NULL)
798
800 xmlerrcxt->err_occurred)
802 "could not append xml node list");
803
804 /*
805 * We use this node to insert newlines in the dump. Note: in at
806 * least some libxml versions, xmlNewDocText would not attach the
807 * node to the document even if we passed it. Therefore, manage
808 * freeing of this node manually, and pass NULL here to make sure
809 * there's not a dangling link.
810 */
811 newline = xmlNewDocText(NULL, (const xmlChar *) "\n");
812 if (newline == NULL || xmlerrcxt->err_occurred)
814 "could not allocate xml node");
815
816 for (xmlNodePtr node = root->children; node; node = node->next)
817 {
818 /* insert newlines between nodes */
819 if (node->type != XML_TEXT_NODE && node->prev != NULL)
820 {
821 if (xmlSaveTree(ctxt, newline) == -1 || xmlerrcxt->err_occurred)
822 {
825 "could not save newline to xmlBuffer");
826 }
827 }
828
829 if (xmlSaveTree(ctxt, node) == -1 || xmlerrcxt->err_occurred)
830 {
833 "could not save content to xmlBuffer");
834 }
835 }
836
838 }
839
840 if (xmlSaveClose(ctxt) == -1 || xmlerrcxt->err_occurred)
841 {
842 ctxt = NULL; /* don't try to close it again */
844 "could not close xmlSaveCtxtPtr");
845 }
846
847 /*
848 * xmlDocContentDumpOutput may add a trailing newline, so remove that.
849 */
851 {
852 const char *str = (const char *) xmlBufferContent(buf);
853 int len = xmlBufferLength(buf);
854
855 while (len > 0 && (str[len - 1] == '\n' ||
856 str[len - 1] == '\r'))
857 len--;
858
860 }
861 else
862 result = (text *) xmlBuffer_to_xmltype(buf);
863 }
864 PG_CATCH();
865 {
866 if (ctxt)
867 xmlSaveClose(ctxt);
868 if (buf)
871
872 if (xmlerrcxt)
873 pg_xml_done(xmlerrcxt, true);
874
875 PG_RE_THROW();
876 }
877 PG_END_TRY();
878
881
882 pg_xml_done(xmlerrcxt, false);
883
884 return result;
885#else
887 return NULL;
888#endif
889}

References buf, cstring_to_text_with_len(), data, ereport, errcode(), errmsg(), ERROR, ErrorSaveContext::error_occurred, fb(), GetDatabaseEncoding(), len, newline, NO_XML_SUPPORT, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pg_xml_done(), pg_xml_init(), PG_XML_STRICTNESS_ALL, root, str, xml_ereport(), and XMLOPTION_DOCUMENT.

Referenced by ExecEvalXmlExpr().

◆ xmlvalidate()

Datum xmlvalidate ( PG_FUNCTION_ARGS  )

Definition at line 1157 of file xml.c.

1158{
1159 ereport(ERROR,
1161 errmsg("xmlvalidate is not implemented")));
1162 return 0;
1163}

References ereport, errcode(), errmsg(), ERROR, and fb().

◆ xpath()

Datum xpath ( PG_FUNCTION_ARGS  )

Definition at line 4565 of file xml.c.

4566{
4567#ifdef USE_LIBXML
4570 ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
4571 ArrayBuildState *astate;
4572
4574 xpath_internal(xpath_expr_text, data, namespaces,
4575 NULL, astate);
4577#else
4579 return 0;
4580#endif
4581}

References CurrentMemoryContext, data, fb(), initArrayResult(), makeArrayResult(), NO_XML_SUPPORT, PG_GETARG_ARRAYTYPE_P, PG_GETARG_TEXT_PP, PG_GETARG_XML_P, and PG_RETURN_DATUM.

Referenced by pgxml_xpath(), xpath_bool(), xpath_list(), xpath_nodeset(), xpath_number(), and xpath_string().

◆ xpath_exists()

Datum xpath_exists ( PG_FUNCTION_ARGS  )

Definition at line 4611 of file xml.c.

4612{
4613#ifdef USE_LIBXML
4616 ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
4617 int res_nitems;
4618
4619 xpath_internal(xpath_expr_text, data, namespaces,
4620 &res_nitems, NULL);
4621
4623#else
4625 return 0;
4626#endif
4627}

References data, fb(), NO_XML_SUPPORT, PG_GETARG_ARRAYTYPE_P, PG_GETARG_TEXT_PP, PG_GETARG_XML_P, and PG_RETURN_BOOL.

◆ xsd_schema_element_end()

static void xsd_schema_element_end ( StringInfo  result)
static

Definition at line 3300 of file xml.c.

3301{
3302 appendStringInfoString(result, "</xsd:schema>");
3303}

References appendStringInfoString().

Referenced by database_to_xmlschema_internal(), map_sql_table_to_xmlschema(), and schema_to_xmlschema_internal().

◆ xsd_schema_element_start()

static void xsd_schema_element_start ( StringInfo  result,
const char targetns 
)
static

Definition at line 3283 of file xml.c.

3284{
3286 "<xsd:schema\n"
3287 " xmlns:xsd=\"" NAMESPACE_XSD "\"");
3288 if (strlen(targetns) > 0)
3289 appendStringInfo(result,
3290 "\n"
3291 " targetNamespace=\"%s\"\n"
3292 " elementFormDefault=\"qualified\"",
3293 targetns);
3295 ">\n\n");
3296}

References appendStringInfo(), appendStringInfoString(), fb(), and NAMESPACE_XSD.

Referenced by database_to_xmlschema_internal(), map_sql_table_to_xmlschema(), and schema_to_xmlschema_internal().

Variable Documentation

◆ xmlbinary

int xmlbinary = XMLBINARY_BASE64

Definition at line 108 of file xml.c.

Referenced by map_sql_type_to_xmlschema_type(), and map_sql_value_to_xml_value().

◆ xmloption

int xmloption = XMLOPTION_CONTENT

Definition at line 109 of file xml.c.

Referenced by texttoxml(), xml_in(), xml_is_well_formed(), and xml_recv().

◆ XmlTableRoutine

const TableFuncRoutine XmlTableRoutine
Initial value:
=
{
.InitOpaque = XmlTableInitOpaque,
.SetDocument = XmlTableSetDocument,
.SetNamespace = XmlTableSetNamespace,
.SetRowFilter = XmlTableSetRowFilter,
.SetColumnFilter = XmlTableSetColumnFilter,
.FetchRow = XmlTableFetchRow,
.GetValue = XmlTableGetValue,
.DestroyOpaque = XmlTableDestroyOpaque
}

Definition at line 222 of file xml.c.

223{
224 .InitOpaque = XmlTableInitOpaque,
225 .SetDocument = XmlTableSetDocument,
226 .SetNamespace = XmlTableSetNamespace,
227 .SetRowFilter = XmlTableSetRowFilter,
228 .SetColumnFilter = XmlTableSetColumnFilter,
229 .FetchRow = XmlTableFetchRow,
230 .GetValue = XmlTableGetValue,
231 .DestroyOpaque = XmlTableDestroyOpaque
232};

Referenced by ExecInitTableFuncScan().