1 /*-------------------------------------------------------------------------
4 * XML data type support.
7 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.12 2007/01/07 00:13:55 petere Exp $
12 *-------------------------------------------------------------------------
16 * Generally, XML type support is only available when libxml use was
17 * configured during the build. But even if that is not done, the
18 * type and all the functions are available, but most of them will
19 * fail. For one thing, this avoids having to manage variant catalog
20 * installations. But it also has nice effects such as that you can
21 * dump a database containing XML type data even if the server is not
22 * linked with libxml. Thus, make sure xml_out() works even if nothing
29 #include <libxml/chvalid.h>
30 #include <libxml/parser.h>
31 #include <libxml/tree.h>
32 #include <libxml/uri.h>
33 #include <libxml/xmlerror.h>
34 #include <libxml/xmlsave.h>
35 #endif /* USE_LIBXML */
38 #include "libpq/pqformat.h"
39 #include "mb/pg_wchar.h"
40 #include "nodes/execnodes.h"
41 #include "utils/builtins.h"
42 #include "utils/memutils.h"
43 #include "utils/xml.h"
48 #define PG_XML_DEFAULT_URI "dummy.xml"
50 static StringInfo xml_err_buf = NULL;
52 static void xml_init(void);
54 static void *xml_palloc(size_t size);
55 static void *xml_repalloc(void *ptr, size_t size);
56 static void xml_pfree(void *ptr);
57 static char *xml_pstrdup(const char *string);
59 static void xml_ereport(int level, int sqlcode,
60 const char *msg, void *ctxt);
61 static void xml_errorHandler(void *ctxt, const char *msg, ...);
62 static void xml_ereport_by_code(int level, int sqlcode,
63 const char *msg, int errcode);
64 static xmlChar *xml_text2xmlChar(text *in);
65 static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespace);
67 #endif /* USE_LIBXML */
69 #define NO_XML_SUPPORT() \
71 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
72 errmsg("no XML support in this installation")))
76 xml_in(PG_FUNCTION_ARGS)
79 char *s = PG_GETARG_CSTRING(0);
85 vardata = palloc(len + VARHDRSZ);
86 VARATT_SIZEP(vardata) = len + VARHDRSZ;
87 memcpy(VARDATA(vardata), s, len);
90 * Parse the data to check if it is well-formed XML data. Assume
91 * that ERROR occurred if parsing failed.
93 doc = xml_parse(vardata, false, true);
96 PG_RETURN_XML_P(vardata);
105 xml_out(PG_FUNCTION_ARGS)
107 xmltype *s = PG_GETARG_XML_P(0);
111 len = VARSIZE(s) - VARHDRSZ;
112 result = palloc(len + 1);
113 memcpy(result, VARDATA(s), len);
116 PG_RETURN_CSTRING(result);
121 xml_recv(PG_FUNCTION_ARGS)
124 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
130 str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
132 result = (xmltype *) palloc(nbytes + VARHDRSZ);
133 VARATT_SIZEP(result) = nbytes + VARHDRSZ;
134 memcpy(VARDATA(result), str, nbytes);
138 * Parse the data to check if it is well-formed XML data. Assume
139 * that ERROR occurred if parsing failed.
141 doc = xml_parse(result, false, true);
144 PG_RETURN_XML_P(result);
153 xml_send(PG_FUNCTION_ARGS)
155 xmltype *x = PG_GETARG_XML_P(0);
158 pq_begintypsend(&buf);
159 pq_sendbytes(&buf, VARDATA(x), VARSIZE(x) - VARHDRSZ);
160 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
166 appendStringInfoText(StringInfo str, const text *t)
168 appendBinaryStringInfo(str, VARDATA(t), VARSIZE(t) - VARHDRSZ);
173 stringinfo_to_xmltype(StringInfo buf)
178 len = buf->len + VARHDRSZ;
179 result = palloc(len);
180 VARATT_SIZEP(result) = len;
181 memcpy(VARDATA(result), buf->data, buf->len);
188 xmlBuffer_to_xmltype(xmlBufferPtr buf)
193 len = xmlBufferLength(buf) + VARHDRSZ;
194 result = palloc(len);
195 VARATT_SIZEP(result) = len;
196 memcpy(VARDATA(result), xmlBufferContent(buf), len - VARHDRSZ);
204 xmlcomment(PG_FUNCTION_ARGS)
207 text *arg = PG_GETARG_TEXT_P(0);
208 int len = VARATT_SIZEP(arg) - VARHDRSZ;
212 /* check for "--" in string or "-" at the end */
213 for (i = 1; i < len; i++)
214 if ((VARDATA(arg)[i] == '-' && VARDATA(arg)[i - 1] == '-')
215 || (VARDATA(arg)[i] == '-' && i == len - 1))
217 (errcode(ERRCODE_INVALID_XML_COMMENT),
218 errmsg("invalid XML comment")));
220 initStringInfo(&buf);
221 appendStringInfo(&buf, "<!--");
222 appendStringInfoText(&buf, arg);
223 appendStringInfo(&buf, "-->");
225 PG_RETURN_XML_P(stringinfo_to_xmltype(&buf));
234 texttoxml(PG_FUNCTION_ARGS)
236 text *data = PG_GETARG_TEXT_P(0);
238 PG_RETURN_XML_P(xmlparse(data, false, true));
243 xmlparse(text *data, bool is_document, bool preserve_whitespace)
248 doc = xml_parse(data, is_document, preserve_whitespace);
251 return (xmltype *) data;
260 xmlpi(char *target, text *arg)
266 if (pg_strncasecmp(target, "xml", 3) == 0)
268 (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
269 errmsg("invalid XML processing instruction"),
270 errdetail("XML processing instruction target name cannot start with \"xml\".")));
272 initStringInfo(&buf);
274 appendStringInfo(&buf, "<?%s", target);
280 string = DatumGetCString(DirectFunctionCall1(textout,
281 PointerGetDatum(arg)));
282 if (strstr(string, "?>") != NULL)
284 (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
285 errmsg("invalid XML processing instruction"),
286 errdetail("XML processing instruction cannot contain \"?>\".")));
288 appendStringInfoChar(&buf, ' ');
289 appendStringInfoString(&buf, string);
292 appendStringInfoString(&buf, "?>");
294 result = stringinfo_to_xmltype(&buf);
305 xmlroot(xmltype *data, text *version, int standalone)
312 doc = xml_parse((text *) data, true, true);
315 doc->version = xmlStrdup(xml_text2xmlChar(version));
328 doc->standalone = -1;
332 buffer = xmlBufferCreate();
333 save = xmlSaveToBuffer(buffer, NULL, 0);
334 xmlSaveDoc(save, doc);
339 return xmlBuffer_to_xmltype(buffer);
348 * Validate document (given as string) against DTD (given as external link)
349 * TODO !!! use text instead of cstring for second arg
350 * TODO allow passing DTD as a string value (not only as an URI)
351 * TODO redesign (see comment with '!!!' below)
354 xmlvalidate(PG_FUNCTION_ARGS)
357 text *data = PG_GETARG_TEXT_P(0);
358 text *dtdOrUri = PG_GETARG_TEXT_P(1);
360 xmlParserCtxtPtr ctxt = NULL;
361 xmlDocPtr doc = NULL;
362 xmlDtdPtr dtd = NULL;
366 /* We use a PG_TRY block to ensure libxml is cleaned up on error */
369 ctxt = xmlNewParserCtxt();
371 xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
372 "could not allocate parser context", ctxt);
374 doc = xmlCtxtReadMemory(ctxt, (char *) VARDATA(data),
375 VARSIZE(data) - VARHDRSZ,
376 PG_XML_DEFAULT_URI, NULL, 0);
378 xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
379 "could not parse XML data", ctxt);
382 uri = xmlCreateURI();
383 elog(NOTICE, "dtd - %s", dtdOrUri);
384 dtd = palloc(sizeof(xmlDtdPtr));
385 uri = xmlParseURI(dtdOrUri);
387 xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
388 "not implemented yet... (TODO)", ctxt);
391 dtd = xmlParseDTD(NULL, xml_text2xmlChar(dtdOrUri));
394 xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
395 "could not load DTD", ctxt);
397 if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) == 1)
401 xml_ereport(NOTICE, ERRCODE_INVALID_XML_DOCUMENT,
402 "validation against DTD failed", ctxt);
413 xmlFreeParserCtxt(ctxt);
427 xmlFreeParserCtxt(ctxt);
434 PG_RETURN_BOOL(result);
435 #else /* not USE_LIBXML */
438 #endif /* not USE_LIBXML */
445 * Container for some init stuff (not good design!)
446 * TODO xmlChar is utf8-char, make proper tuning (initdb with enc!=utf8 and check)
452 * Currently, we have no pure UTF-8 support for internals -- check
455 if (sizeof (char) != sizeof (xmlChar))
457 (errmsg("could not initialize XML library"),
458 errdetail("libxml2 has incompatible char type: sizeof(char)=%u, sizeof(xmlChar)=%u.",
459 (int) sizeof(char), (int) sizeof(xmlChar))));
461 if (xml_err_buf == NULL)
463 /* First time through: create error buffer in permanent context */
464 MemoryContext oldcontext;
466 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
467 xml_err_buf = makeStringInfo();
468 MemoryContextSwitchTo(oldcontext);
472 /* Reset pre-existing buffer to empty */
473 xml_err_buf->data[0] = '\0';
474 xml_err_buf->len = 0;
476 /* Now that xml_err_buf exists, safe to call xml_errorHandler */
477 xmlSetGenericErrorFunc(NULL, xml_errorHandler);
481 * FIXME: This doesn't work because libxml assumes that whatever
482 * libxml allocates, only libxml will free, so we can't just drop
483 * memory contexts behind it. This needs to be refined.
485 xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
493 * SQL/XML allows storing "XML documents" or "XML content". "XML
494 * documents" are specified by the XML specification and are parsed
495 * easily by libxml. "XML content" is specified by SQL/XML as the
496 * production "XMLDecl? content". But libxml can only parse the
497 * "content" part, so we have to parse the XML declaration ourselves
501 #define CHECK_XML_SPACE(p) if (!xmlIsBlank_ch(*(p))) return XML_ERR_SPACE_REQUIRED
502 #define SKIP_XML_SPACE(p) while (xmlIsBlank_ch(*(p))) (p)++
505 parse_xml_decl(const xmlChar *str, size_t *len, xmlChar **encoding, int *standalone)
508 const xmlChar *save_p;
512 if (xmlStrncmp(p, (xmlChar *)"<?xml", 5) != 0)
520 if (xmlStrncmp(p, (xmlChar *)"version", 7) != 0)
521 return XML_ERR_VERSION_MISSING;
525 return XML_ERR_VERSION_MISSING;
528 if (xmlStrncmp(p, (xmlChar *)"'1.0'", 5) != 0 && xmlStrncmp(p, (xmlChar *)"\"1.0\"", 5) != 0)
529 return XML_ERR_VERSION_MISSING;
535 if (xmlStrncmp(p, (xmlChar *)"encoding", 8) == 0)
537 CHECK_XML_SPACE(save_p);
541 return XML_ERR_MISSING_ENCODING;
545 if (*p == '\'' || *p == '"')
549 q = xmlStrchr(p + 1, *p);
551 return XML_ERR_MISSING_ENCODING;
553 *encoding = xmlStrndup(p + 1, q - p - 1);
557 return XML_ERR_MISSING_ENCODING;
568 if (xmlStrncmp(p, (xmlChar *)"standalone", 10) == 0)
570 CHECK_XML_SPACE(save_p);
574 return XML_ERR_STANDALONE_VALUE;
577 if (xmlStrncmp(p, (xmlChar *)"'yes'", 5) == 0 || xmlStrncmp(p, (xmlChar *)"\"yes\"", 5) == 0)
582 else if (xmlStrncmp(p, (xmlChar *)"'no'", 4) == 0 || xmlStrncmp(p, (xmlChar *)"\"no\"", 4) == 0)
588 return XML_ERR_STANDALONE_VALUE;
597 if (xmlStrncmp(p, (xmlChar *)"?>", 2) != 0)
598 return XML_ERR_XMLDECL_NOT_FINISHED;
609 * Convert a C string to XML internal representation
611 * TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c)
612 * TODO what about internal URI for docs? (see PG_XML_DEFAULT_URI below)
615 xml_parse(text *data, bool is_document, bool preserve_whitespace)
620 xmlParserCtxtPtr ctxt = NULL;
621 xmlDocPtr doc = NULL;
623 len = VARSIZE(data) - VARHDRSZ; /* will be useful later */
624 string = xml_text2xmlChar(data);
628 /* We use a PG_TRY block to ensure libxml is cleaned up on error */
631 ctxt = xmlNewParserCtxt();
633 xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
634 "could not allocate parser context", ctxt);
639 * Note, that here we try to apply DTD defaults
640 * (XML_PARSE_DTDATTR) according to SQL/XML:10.16.7.d:
641 * 'Default valies defined by internal DTD are applied'.
642 * As for external DTDs, we try to support them too, (see
645 doc = xmlCtxtReadMemory(ctxt, (char *) string, len,
646 PG_XML_DEFAULT_URI, NULL,
647 XML_PARSE_NOENT | XML_PARSE_DTDATTR
648 | (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
650 xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
651 "invalid XML document", ctxt);
656 xmlChar *encoding = NULL;
659 doc = xmlNewDoc(NULL);
661 res_code = parse_xml_decl(string, &count, &encoding, &standalone);
663 /* TODO resolve: xmlParseBalancedChunkMemory assumes that string is UTF8 encoded! */
665 res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, string + count, NULL);
667 xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_CONTENT,
668 "invalid XML content", res_code);
670 doc->encoding = encoding;
671 doc->standalone = standalone;
674 /* TODO encoding issues
677 * - XML data has explicit encoding attribute in its prolog
678 * - if not, assume that enc. of XML data is the same as client's one
680 * The common rule is to accept the XML data only if its encoding
681 * is the same as encoding of the storage (server's). The other possible
682 * option is to accept all the docs, but DO TRANSFORMATION and, if needed,
685 * I think I'd stick the first way (for the 1st version),
686 * it's much simplier (less errors...)
691 xmlFreeParserCtxt(ctxt);
700 xmlFreeParserCtxt(ctxt);
712 * xmlChar<->text convertions
715 xml_text2xmlChar(text *in)
717 int32 len = VARSIZE(in) - VARHDRSZ;
720 res = palloc(len + 1);
721 memcpy(res, VARDATA(in), len);
730 * Wrappers for memory management functions
733 xml_palloc(size_t size)
740 xml_repalloc(void *ptr, size_t size)
742 return repalloc(ptr, size);
754 xml_pstrdup(const char *string)
756 return pstrdup(string);
758 #endif /* NOT_USED */
762 * Wrapper for "ereport" function.
763 * Adds detail - libxml's native error message, if any.
766 xml_ereport(int level, int sqlcode,
767 const char *msg, void *ctxt)
769 xmlErrorPtr libxmlErr = NULL;
771 if (xml_err_buf->len > 0)
774 (errmsg("%s", xml_err_buf->data)));
775 xml_err_buf->data[0] = '\0';
776 xml_err_buf->len = 0;
780 libxmlErr = xmlCtxtGetLastError(ctxt);
782 if (libxmlErr == NULL)
790 /* as usual, libxml error message contains '\n'; get rid of it */
794 xmlErrDetail = pstrdup(libxmlErr->message);
795 xmlErrLen = strlen(xmlErrDetail);
796 for (i = 0; i < xmlErrLen; i++)
798 if (xmlErrDetail[i] == '\n')
799 xmlErrDetail[i] = '.';
804 errdetail("%s", xmlErrDetail)));
810 * Error handler for libxml error messages
813 xml_errorHandler(void *ctxt, const char *msg,...)
815 /* Append the formatted text to xml_err_buf */
821 /* Try to format the data. */
823 success = appendStringInfoVA(xml_err_buf, msg, args);
829 /* Double the buffer size and try again. */
830 enlargeStringInfo(xml_err_buf, xml_err_buf->maxlen);
836 * Return error message by libxml error code
837 * TODO make them closer to recommendations from Postgres manual
840 xml_ereport_by_code(int level, int sqlcode,
841 const char *msg, int code)
845 if (xml_err_buf->len > 0)
848 (errmsg("%s", xml_err_buf->data)));
849 xml_err_buf->data[0] = '\0';
850 xml_err_buf->len = 0;
855 case XML_ERR_INTERNAL_ERROR:
856 det = "libxml internal error";
858 case XML_ERR_ENTITY_LOOP:
859 det = "Detected an entity reference loop";
861 case XML_ERR_ENTITY_NOT_STARTED:
862 det = "EntityValue: \" or ' expected";
864 case XML_ERR_ENTITY_NOT_FINISHED:
865 det = "EntityValue: \" or ' expected";
867 case XML_ERR_ATTRIBUTE_NOT_STARTED:
868 det = "AttValue: \" or ' expected";
870 case XML_ERR_LT_IN_ATTRIBUTE:
871 det = "Unescaped '<' not allowed in attributes values";
873 case XML_ERR_LITERAL_NOT_STARTED:
874 det = "SystemLiteral \" or ' expected";
876 case XML_ERR_LITERAL_NOT_FINISHED:
877 det = "Unfinished System or Public ID \" or ' expected";
879 case XML_ERR_MISPLACED_CDATA_END:
880 det = "Sequence ']]>' not allowed in content";
882 case XML_ERR_URI_REQUIRED:
883 det = "SYSTEM or PUBLIC, the URI is missing";
885 case XML_ERR_PUBID_REQUIRED:
886 det = "PUBLIC, the Public Identifier is missing";
888 case XML_ERR_HYPHEN_IN_COMMENT:
889 det = "Comment must not contain '--' (double-hyphen)";
891 case XML_ERR_PI_NOT_STARTED:
892 det = "xmlParsePI : no target name";
894 case XML_ERR_RESERVED_XML_NAME:
895 det = "Invalid PI name";
897 case XML_ERR_NOTATION_NOT_STARTED:
898 det = "NOTATION: Name expected here";
900 case XML_ERR_NOTATION_NOT_FINISHED:
901 det = "'>' required to close NOTATION declaration";
903 case XML_ERR_VALUE_REQUIRED:
904 det = "Entity value required";
906 case XML_ERR_URI_FRAGMENT:
907 det = "Fragment not allowed";
909 case XML_ERR_ATTLIST_NOT_STARTED:
910 det = "'(' required to start ATTLIST enumeration";
912 case XML_ERR_NMTOKEN_REQUIRED:
913 det = "NmToken expected in ATTLIST enumeration";
915 case XML_ERR_ATTLIST_NOT_FINISHED:
916 det = "')' required to finish ATTLIST enumeration";
918 case XML_ERR_MIXED_NOT_STARTED:
919 det = "MixedContentDecl : '|' or ')*' expected";
921 case XML_ERR_PCDATA_REQUIRED:
922 det = "MixedContentDecl : '#PCDATA' expected";
924 case XML_ERR_ELEMCONTENT_NOT_STARTED:
925 det = "ContentDecl : Name or '(' expected";
927 case XML_ERR_ELEMCONTENT_NOT_FINISHED:
928 det = "ContentDecl : ',' '|' or ')' expected";
930 case XML_ERR_PEREF_IN_INT_SUBSET:
931 det = "PEReference: forbidden within markup decl in internal subset";
933 case XML_ERR_GT_REQUIRED:
934 det = "Expected '>'";
936 case XML_ERR_CONDSEC_INVALID:
937 det = "XML conditional section '[' expected";
939 case XML_ERR_EXT_SUBSET_NOT_FINISHED:
940 det = "Content error in the external subset";
942 case XML_ERR_CONDSEC_INVALID_KEYWORD:
943 det = "conditional section INCLUDE or IGNORE keyword expected";
945 case XML_ERR_CONDSEC_NOT_FINISHED:
946 det = "XML conditional section not closed";
948 case XML_ERR_XMLDECL_NOT_STARTED:
949 det = "Text declaration '<?xml' required";
951 case XML_ERR_XMLDECL_NOT_FINISHED:
952 det = "parsing XML declaration: '?>' expected";
954 case XML_ERR_EXT_ENTITY_STANDALONE:
955 det = "external parsed entities cannot be standalone";
957 case XML_ERR_ENTITYREF_SEMICOL_MISSING:
958 det = "EntityRef: expecting ';'";
960 case XML_ERR_DOCTYPE_NOT_FINISHED:
961 det = "DOCTYPE improperly terminated";
963 case XML_ERR_LTSLASH_REQUIRED:
964 det = "EndTag: '</' not found";
966 case XML_ERR_EQUAL_REQUIRED:
967 det = "Expected '='";
969 case XML_ERR_STRING_NOT_CLOSED:
970 det = "String not closed expecting \" or '";
972 case XML_ERR_STRING_NOT_STARTED:
973 det = "String not started expecting ' or \"";
975 case XML_ERR_ENCODING_NAME:
976 det = "Invalid XML encoding name";
978 case XML_ERR_STANDALONE_VALUE:
979 det = "Standalone accepts only 'yes' or 'no'";
981 case XML_ERR_DOCUMENT_EMPTY:
982 det = "Document is empty";
984 case XML_ERR_DOCUMENT_END:
985 det = "Extra content at the end of the document";
987 case XML_ERR_NOT_WELL_BALANCED:
988 det = "Chunk is not well balanced";
990 case XML_ERR_EXTRA_CONTENT:
991 det = "Extra content at the end of well balanced chunk";
993 case XML_ERR_VERSION_MISSING:
994 det = "Malformed declaration expecting version";
996 /* more err codes... Please, keep the order! */
997 case XML_ERR_ATTRIBUTE_WITHOUT_VALUE: /* 41 */
998 det ="Attribute without value";
1000 case XML_ERR_ATTRIBUTE_REDEFINED:
1001 det ="Attribute defined more than once in the same element";
1003 case XML_ERR_COMMENT_NOT_FINISHED: /* 45 */
1004 det = "Comment is not finished";
1006 case XML_ERR_NAME_REQUIRED: /* 68 */
1007 det = "Element name not found";
1009 case XML_ERR_TAG_NOT_FINISHED: /* 77 */
1010 det = "Closing tag not found";
1013 det = "Unrecognized libxml error code: %d";
1020 errdetail(det, code)));
1025 * Convert one char in the current server encoding to a Unicode codepoint.
1028 sqlchar_to_unicode(char *s)
1031 pg_wchar ret[2]; /* need space for trailing zero */
1033 utf8string = (char *) pg_do_encoding_conversion((unsigned char *) s,
1035 GetDatabaseEncoding(),
1038 pg_encoding_mb2wchar_with_len(PG_UTF8, utf8string, ret, pg_mblen(s));
1045 is_valid_xml_namefirst(pg_wchar c)
1047 /* (Letter | '_' | ':') */
1048 return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)
1049 || c == '_' || c == ':');
1054 is_valid_xml_namechar(pg_wchar c)
1056 /* Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender */
1057 return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)
1059 || c == '.' || c == '-' || c == '_' || c == ':'
1060 || xmlIsCombiningQ(c)
1061 || xmlIsExtenderQ(c));
1063 #endif /* USE_LIBXML */
1067 * Map SQL identifier to XML name; see SQL/XML:2003 section 9.1.
1070 map_sql_identifier_to_xml_name(char *ident, bool fully_escaped)
1076 initStringInfo(&buf);
1078 for (p = ident; *p; p += pg_mblen(p))
1080 if (*p == ':' && (p == ident || fully_escaped))
1081 appendStringInfo(&buf, "_x003A_");
1082 else if (*p == '_' && *(p+1) == 'x')
1083 appendStringInfo(&buf, "_x005F_");
1084 else if (fully_escaped && p == ident &&
1085 pg_strncasecmp(p, "xml", 3) == 0)
1088 appendStringInfo(&buf, "_x0078_");
1090 appendStringInfo(&buf, "_x0058_");
1094 pg_wchar u = sqlchar_to_unicode(p);
1097 ? !is_valid_xml_namefirst(u)
1098 : !is_valid_xml_namechar(u))
1099 appendStringInfo(&buf, "_x%04X_", (unsigned int) u);
1101 appendBinaryStringInfo(&buf, p, pg_mblen(p));
1106 #else /* not USE_LIBXML */
1109 #endif /* not USE_LIBXML */
1114 * Map a Unicode codepoint into the current server encoding.
1117 unicode_to_sqlchar(pg_wchar c)
1119 static unsigned char utf8string[4];
1125 else if (c <= 0x7FF)
1127 utf8string[0] = 0xC0 | ((c >> 6) & 0x1F);
1128 utf8string[1] = 0x80 | (c & 0x3F);
1130 else if (c <= 0xFFFF)
1132 utf8string[0] = 0xE0 | ((c >> 12) & 0x0F);
1133 utf8string[1] = 0x80 | ((c >> 6) & 0x3F);
1134 utf8string[2] = 0x80 | (c & 0x3F);
1138 utf8string[0] = 0xF0 | ((c >> 18) & 0x07);
1139 utf8string[1] = 0x80 | ((c >> 12) & 0x3F);
1140 utf8string[2] = 0x80 | ((c >> 6) & 0x3F);
1141 utf8string[3] = 0x80 | (c & 0x3F);
1144 return (char *) pg_do_encoding_conversion(utf8string,
1145 pg_mblen((char *) utf8string),
1147 GetDatabaseEncoding());
1152 * Map XML name to SQL identifier; see SQL/XML:2003 section 9.17.
1155 map_xml_name_to_sql_identifier(char *name)
1160 initStringInfo(&buf);
1162 for (p = name; *p; p += pg_mblen(p))
1164 if (*p == '_' && *(p+1) == 'x'
1165 && isxdigit((unsigned char) *(p+2))
1166 && isxdigit((unsigned char) *(p+3))
1167 && isxdigit((unsigned char) *(p+4))
1168 && isxdigit((unsigned char) *(p+5))
1173 sscanf(p + 2, "%X", &u);
1174 appendStringInfoString(&buf, unicode_to_sqlchar(u));
1178 appendBinaryStringInfo(&buf, p, pg_mblen(p));