PostgreSQL Source Code: src/backend/utils/adt/xml.c Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
47
48#ifdef USE_LIBXML
49#include <libxml/chvalid.h>
50#include <libxml/entities.h>
51#include <libxml/parser.h>
52#include <libxml/parserInternals.h>
53#include <libxml/tree.h>
54#include <libxml/uri.h>
55#include <libxml/xmlerror.h>
56#include <libxml/xmlsave.h>
57#include <libxml/xmlversion.h>
58#include <libxml/xmlwriter.h>
59#include <libxml/xpath.h>
60#include <libxml/xpathInternals.h>
61
62
63
64
65
66
67#if LIBXML_VERSION >= 20704
68#define HAVE_XMLSTRUCTUREDERRORCONTEXT 1
69#endif
70
71
72
73
74#if LIBXML_VERSION >= 21200
75#define PgXmlErrorPtr const xmlError *
76#else
77#define PgXmlErrorPtr xmlErrorPtr
78#endif
79
80#endif
81
106
107
108
111
112#ifdef USE_LIBXML
113
114
115#define ERRCXT_MAGIC 68275028
116
118{
119 int magic;
120
122
123 bool err_occurred;
125
126 xmlStructuredErrorFunc saved_errfunc;
127 void *saved_errcxt;
128
129 xmlExternalEntityLoader saved_entityfunc;
130};
131
132static xmlParserInputPtr xmlPgEntityLoader(const char *URL, const char *ID,
133 xmlParserCtxtPtr ctxt);
135 int sqlcode, const char *msg);
136static void xml_errorHandler(void *data, PgXmlErrorPtr error);
137static int errdetail_for_xml_code(int code);
138static void chopStringInfoNewlines(StringInfo str);
139static void appendStringInfoLineSeparator(StringInfo str);
140
141#ifdef USE_LIBXMLCONTEXT
142
144
145static void xml_memory_init(void);
146static void *xml_palloc(size_t size);
147static void *xml_repalloc(void *ptr, size_t size);
148static void xml_pfree(void *ptr);
149static char *xml_pstrdup(const char *string);
150#endif
151
152static xmlChar *xml_text2xmlChar(text *in);
153static int parse_xml_decl(const xmlChar *str, size_t *lenp,
154 xmlChar **version, xmlChar **encoding, int *standalone);
155static bool print_xml_decl(StringInfo buf, const xmlChar *version,
157static bool xml_doctype_in_content(const xmlChar *str);
159 bool preserve_whitespace, int encoding,
161 xmlNodePtr *parsed_nodes,
162 Node *escontext);
164static int xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
167static xmlChar *pg_xmlCharStrndup(const char *str, size_t len);
168#endif
169
171 const char *xmlschema, const char *targetns,
172 bool top_level);
175 const char *xmlschema, bool nulls, bool tableforest,
176 const char *targetns, bool top_level);
178 bool nulls, bool tableforest, const char *targetns);
180 List *relid_list, bool nulls,
181 bool tableforest, const char *targetns);
183 bool nulls, bool tableforest,
184 const char *targetns);
189 char *tablename, bool nulls, bool tableforest,
190 const char *targetns, bool top_level);
191
192
193#ifdef USE_LIBXML
194
195#define XMLTABLE_CONTEXT_MAGIC 46922182
196typedef struct XmlTableBuilderData
197{
198 int magic;
199 int natts;
200 long int row_count;
202 xmlParserCtxtPtr ctxt;
203 xmlDocPtr doc;
204 xmlXPathContextPtr xpathcxt;
205 xmlXPathCompExprPtr xpathcomp;
206 xmlXPathObjectPtr xpathobj;
207 xmlXPathCompExprPtr *xpathscomp;
208} XmlTableBuilderData;
209#endif
210
214 const char *uri);
217 const char *path, int colnum);
220 Oid typid, int32 typmod, bool *isnull);
222
224{
233};
234
235#define NO_XML_SUPPORT() \
236 ereport(ERROR, \
237 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
238 errmsg("unsupported XML feature"), \
239 errdetail("This functionality requires the server to be built with libxml support.")))
240
241
242
243#define NAMESPACE_XSD "http://www.w3.org/2001/XMLSchema"
244#define NAMESPACE_XSI "http://www.w3.org/2001/XMLSchema-instance"
245#define NAMESPACE_SQLXML "http://standards.iso.org/iso/9075/2003/sqlxml"
246
247
248#ifdef USE_LIBXML
249
250static int
251xmlChar_to_encoding(const xmlChar *encoding_name)
252{
254
257 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
258 errmsg("invalid encoding name \"%s\"",
259 (const char *) encoding_name)));
261}
262#endif
263
264
265
266
267
268
269
270
271
274{
275#ifdef USE_LIBXML
278 xmlDocPtr doc;
279
280
282
283
284
285
286
287
289 NULL, NULL, fcinfo->context);
290 if (doc != NULL)
291 xmlFreeDoc(doc);
292
294#else
296 return 0;
297#endif
298}
299
300
301#define PG_XML_DEFAULT_VERSION "1.0"
302
303
304
305
306
307
308
309
310
311static char *
313{
315
316#ifdef USE_LIBXML
318 xmlChar *version;
319 int standalone;
320 int res_code;
321
322 if ((res_code = parse_xml_decl((xmlChar *) str,
323 &len, &version, NULL, &standalone)) == 0)
324 {
326
328
329 if (!print_xml_decl(&buf, version, target_encoding, standalone))
330 {
331
332
333
334
335
337 len += 1;
338 }
340
342
343 return buf.data;
344 }
345
348 errmsg_internal("could not parse XML declaration in stored value"),
349 errdetail_for_xml_code(res_code));
350#endif
351 return str;
352}
353
354
357{
359
360
361
362
363
364
365
367}
368
369
372{
373#ifdef USE_LIBXML
376 char *str;
377 char *newstr;
378 int nbytes;
379 xmlDocPtr doc;
380 xmlChar *encodingStr = NULL;
382
383
384
385
386
387
388 nbytes = buf->len - buf->cursor;
390
391
392
393
394
395
398 memcpy(VARDATA(result), str, nbytes);
400 str[nbytes] = '\0';
401
402 parse_xml_decl((const xmlChar *) str, NULL, NULL, &encodingStr, NULL);
403
404
405
406
407
408
409
410 encoding = encodingStr ? xmlChar_to_encoding(encodingStr) : PG_UTF8;
411
412
413
414
415
416 doc = xml_parse(result, xmloption, true, encoding, NULL, NULL, NULL);
417 xmlFreeDoc(doc);
418
419
421
422 if (newstr != str)
423 {
427 }
428
430#else
432 return 0;
433#endif
434}
435
436
439{
441 char *outval;
443
444
445
446
447
449
454}
455
456
457#ifdef USE_LIBXML
458static void
460{
462}
463#endif
464
465
468{
470}
471
472
475{
477}
478
479
480#ifdef USE_LIBXML
482xmlBuffer_to_xmltype(xmlBufferPtr buf)
483{
485 xmlBufferLength(buf));
486}
487#endif
488
489
492{
493#ifdef USE_LIBXML
498 int i;
499
500
502 {
503 if (argdata[i] == '-' && argdata[i - 1] == '-')
505 (errcode(ERRCODE_INVALID_XML_COMMENT),
506 errmsg("invalid XML comment")));
507 }
508 if (len > 0 && argdata[len - 1] == '-')
510 (errcode(ERRCODE_INVALID_XML_COMMENT),
511 errmsg("invalid XML comment")));
512
517
519#else
521 return 0;
522#endif
523}
524
525
528{
529#ifdef USE_LIBXML
531 text *result;
532 xmlChar *xmlbuf = NULL;
533
534 xmlbuf = xmlEncodeSpecialChars(NULL, xml_text2xmlChar(arg));
535
537
539 xmlFree(xmlbuf);
541#else
543 return 0;
544#endif
545}
546
547
548
549
550
551
554{
555#ifdef USE_LIBXML
556 int global_standalone = 1;
557 xmlChar *global_version = NULL;
558 bool global_version_no_value = false;
561
563 foreach(v, args)
564 {
566 size_t len;
567 xmlChar *version;
568 int standalone;
569 char *str;
570
573
574 parse_xml_decl((xmlChar *) str, &len, &version, NULL, &standalone);
575
576 if (standalone == 0 && global_standalone == 1)
577 global_standalone = 0;
578 if (standalone < 0)
579 global_standalone = -1;
580
581 if (!version)
582 global_version_no_value = true;
583 else if (!global_version)
584 global_version = version;
585 else if (xmlStrcmp(version, global_version) != 0)
586 global_version_no_value = true;
587
590 }
591
592 if (!global_version_no_value || global_standalone >= 0)
593 {
595
597
598 print_xml_decl(&buf2,
599 (!global_version_no_value) ? global_version : NULL,
600 0,
601 global_standalone);
602
604 buf = buf2;
605 }
606
608#else
610 return NULL;
611#endif
612}
613
614
615
616
617
620{
622 {
625 else
627 }
630 else
633}
634
635
638{
640
642}
643
644
647{
649
650
652}
653
654
657{
658#ifdef USE_LIBXML
659 text *volatile result;
660 xmlDocPtr doc;
662 xmlNodePtr content_nodes;
663 volatile xmlBufferPtr buf = NULL;
664 volatile xmlSaveCtxtPtr ctxt = NULL;
667#endif
668
670 {
671
672
673
674
675
677 }
678
679#ifdef USE_LIBXML
680
681
682
683
684
685
686
688 &parsed_xmloptiontype, &content_nodes,
689 (Node *) &escontext);
691 {
692 if (doc)
693 xmlFreeDoc(doc);
694
696 (errcode(ERRCODE_NOT_AN_XML_DOCUMENT),
697 errmsg("not an XML document")));
698 }
699
700
701 if (!indent)
702 {
703 xmlFreeDoc(doc);
705 }
706
707
709
711 {
712 size_t decl_len = 0;
713
714
715 buf = xmlBufferCreate();
716
717 if (buf == NULL || xmlerrcxt->err_occurred)
719 "could not allocate xmlBuffer");
720
721
722 parse_xml_decl(xml_text2xmlChar(data), &decl_len, NULL, NULL, NULL);
723
724
725
726
727
728
729
730 if (decl_len == 0)
731 ctxt = xmlSaveToBuffer(buf, NULL,
732 XML_SAVE_NO_DECL | XML_SAVE_FORMAT);
733 else
734 ctxt = xmlSaveToBuffer(buf, NULL,
735 XML_SAVE_FORMAT);
736
737 if (ctxt == NULL || xmlerrcxt->err_occurred)
739 "could not allocate xmlSaveCtxt");
740
742 {
743
744 if (xmlSaveDoc(ctxt, doc) == -1 || xmlerrcxt->err_occurred)
746 "could not save document to xmlBuffer");
747 }
748 else if (content_nodes != NULL)
749 {
750
751
752
753
754
755
756 xmlNodePtr root;
758
759 root = xmlNewNode(NULL, (const xmlChar *) "content-root");
760 if (root == NULL || xmlerrcxt->err_occurred)
762 "could not allocate xml node");
763
764
765 xmlDocSetRootElement(doc, root);
766 xmlAddChildList(root, content_nodes);
767
768
769
770
771
772
773
774
775 newline = xmlNewDocText(NULL, (const xmlChar *) "\n");
776 if (newline == NULL || xmlerrcxt->err_occurred)
778 "could not allocate xml node");
779
780 for (xmlNodePtr node = root->children; node; node = node->next)
781 {
782
783 if (node->type != XML_TEXT_NODE && node->prev != NULL)
784 {
785 if (xmlSaveTree(ctxt, newline) == -1 || xmlerrcxt->err_occurred)
786 {
789 "could not save newline to xmlBuffer");
790 }
791 }
792
793 if (xmlSaveTree(ctxt, node) == -1 || xmlerrcxt->err_occurred)
794 {
797 "could not save content to xmlBuffer");
798 }
799 }
800
802 }
803
804 if (xmlSaveClose(ctxt) == -1 || xmlerrcxt->err_occurred)
805 {
806 ctxt = NULL;
808 "could not close xmlSaveCtxtPtr");
809 }
810
811
812
813
815 {
816 const char *str = (const char *) xmlBufferContent(buf);
817 int len = xmlBufferLength(buf);
818
819 while (len > 0 && (str[len - 1] == '\n' ||
822
824 }
825 else
826 result = (text *) xmlBuffer_to_xmltype(buf);
827 }
829 {
830 if (ctxt)
831 xmlSaveClose(ctxt);
833 xmlBufferFree(buf);
834 if (doc)
835 xmlFreeDoc(doc);
836
838
840 }
842
843 xmlBufferFree(buf);
844 xmlFreeDoc(doc);
845
847
848 return result;
849#else
851 return NULL;
852#endif
853}
854
855
858 Datum *named_argvalue, bool *named_argnull,
859 Datum *argvalue, bool *argnull)
860{
861#ifdef USE_LIBXML
863 List *named_arg_strings;
864 List *arg_strings;
865 int i;
869 volatile xmlBufferPtr buf = NULL;
870 volatile xmlTextWriterPtr writer = NULL;
871
872
873
874
875
876
877
878
879 named_arg_strings = NIL;
880 i = 0;
882 {
884 char *str;
885
886 if (named_argnull[i])
887 str = NULL;
888 else
891 false);
892 named_arg_strings = lappend(named_arg_strings, str);
893 i++;
894 }
895
896 arg_strings = NIL;
897 i = 0;
899 {
901 char *str;
902
903
904 if (!argnull[i])
905 {
908 true);
909 arg_strings = lappend(arg_strings, str);
910 }
911 i++;
912 }
913
915
917 {
918 buf = xmlBufferCreate();
919 if (buf == NULL || xmlerrcxt->err_occurred)
921 "could not allocate xmlBuffer");
922 writer = xmlNewTextWriterMemory(buf, 0);
923 if (writer == NULL || xmlerrcxt->err_occurred)
925 "could not allocate xmlTextWriter");
926
927 xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name);
928
929 forboth(arg, named_arg_strings, narg, xexpr->arg_names)
930 {
933
935 xmlTextWriterWriteAttribute(writer,
936 (xmlChar *) argname,
937 (xmlChar *) str);
938 }
939
940 foreach(arg, arg_strings)
941 {
943
944 xmlTextWriterWriteRaw(writer, (xmlChar *) str);
945 }
946
947 xmlTextWriterEndElement(writer);
948
949
950 xmlFreeTextWriter(writer);
951 writer = NULL;
952
953 result = xmlBuffer_to_xmltype(buf);
954 }
956 {
957 if (writer)
958 xmlFreeTextWriter(writer);
960 xmlBufferFree(buf);
961
963
965 }
967
968 xmlBufferFree(buf);
969
971
972 return result;
973#else
975 return NULL;
976#endif
977}
978
979
982{
983#ifdef USE_LIBXML
984 xmlDocPtr doc;
985
986 doc = xml_parse(data, xmloption_arg, preserve_whitespace,
988 xmlFreeDoc(doc);
989
991#else
993 return NULL;
994#endif
995}
996
997
999xmlpi(const char *target, text *arg, bool arg_is_null, bool *result_is_null)
1000{
1001#ifdef USE_LIBXML
1004
1007 (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
1008 errmsg("invalid XML processing instruction"),
1009 errdetail("XML processing instruction target name cannot be \"%s\".", target)));
1010
1011
1012
1013
1014
1015 *result_is_null = arg_is_null;
1016 if (*result_is_null)
1017 return NULL;
1018
1020
1022
1023 if (arg != NULL)
1024 {
1026
1028 if (strstr(string, "?>") != NULL)
1030 (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
1031 errmsg("invalid XML processing instruction"),
1032 errdetail("XML processing instruction cannot contain \"?>\".")));
1033
1037 }
1039
1042 return result;
1043#else
1045 return NULL;
1046#endif
1047}
1048
1049
1052{
1053#ifdef USE_LIBXML
1054 char *str;
1055 size_t len;
1056 xmlChar *orig_version;
1057 int orig_standalone;
1059
1062
1063 parse_xml_decl((xmlChar *) str, &len, &orig_version, NULL, &orig_standalone);
1064
1065 if (version)
1066 orig_version = xml_text2xmlChar(version);
1067 else
1068 orig_version = NULL;
1069
1070 switch (standalone)
1071 {
1073 orig_standalone = 1;
1074 break;
1076 orig_standalone = 0;
1077 break;
1079 orig_standalone = -1;
1080 break;
1082
1083 break;
1084 }
1085
1087 print_xml_decl(&buf, orig_version, 0, orig_standalone);
1089
1091#else
1093 return NULL;
1094#endif
1095}
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1108{
1110 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1111 errmsg("xmlvalidate is not implemented")));
1112 return 0;
1113}
1114
1115
1116bool
1118{
1119#ifdef USE_LIBXML
1120 xmlDocPtr doc;
1122
1123
1124
1125
1128 if (doc)
1129 xmlFreeDoc(doc);
1130
1132#else
1134 return false;
1135#endif
1136}
1137
1138
1139#ifdef USE_LIBXML
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152void
1154{
1155 static bool first_time = true;
1156
1157 if (first_time)
1158 {
1159
1160
1161
1162
1163
1164
1165 if (sizeof(char) != sizeof(xmlChar))
1167 (errmsg("could not initialize XML library"),
1168 errdetail("libxml2 has incompatible char type: sizeof(char)=%zu, sizeof(xmlChar)=%zu.",
1169 sizeof(char), sizeof(xmlChar))));
1170
1171#ifdef USE_LIBXMLCONTEXT
1172
1173 xml_memory_init();
1174#endif
1175
1176
1177 LIBXML_TEST_VERSION;
1178
1179 first_time = false;
1180 }
1181}
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1200{
1202 void *new_errcxt;
1203
1204
1206
1207
1209 errcxt->magic = ERRCXT_MAGIC;
1210 errcxt->strictness = strictness;
1211 errcxt->err_occurred = false;
1213
1214
1215
1216
1217
1218
1219
1220
1221 errcxt->saved_errfunc = xmlStructuredError;
1222
1223#ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
1224 errcxt->saved_errcxt = xmlStructuredErrorContext;
1225#else
1226 errcxt->saved_errcxt = xmlGenericErrorContext;
1227#endif
1228
1229 xmlSetStructuredErrorFunc(errcxt, xml_errorHandler);
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245#ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
1246 new_errcxt = xmlStructuredErrorContext;
1247#else
1248 new_errcxt = xmlGenericErrorContext;
1249#endif
1250
1251 if (new_errcxt != errcxt)
1253 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1254 errmsg("could not set up XML error handler"),
1255 errhint("This probably indicates that the version of libxml2"
1256 " being used is not compatible with the libxml2"
1257 " header files that PostgreSQL was built with.")));
1258
1259
1260
1261
1262
1263 errcxt->saved_entityfunc = xmlGetExternalEntityLoader();
1264 xmlSetExternalEntityLoader(xmlPgEntityLoader);
1265
1266 return errcxt;
1267}
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279void
1281{
1282 void *cur_errcxt;
1283
1284
1285 Assert(errcxt->magic == ERRCXT_MAGIC);
1286
1287
1288
1289
1290
1291
1292 Assert(!errcxt->err_occurred || isError);
1293
1294
1295
1296
1297
1298
1299#ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
1300 cur_errcxt = xmlStructuredErrorContext;
1301#else
1302 cur_errcxt = xmlGenericErrorContext;
1303#endif
1304
1305 if (cur_errcxt != errcxt)
1306 elog(WARNING, "libxml error handling state is out of sync with xml.c");
1307
1308
1309 xmlSetStructuredErrorFunc(errcxt->saved_errcxt, errcxt->saved_errfunc);
1310 xmlSetExternalEntityLoader(errcxt->saved_entityfunc);
1311
1312
1313
1314
1315
1316 errcxt->magic = 0;
1317
1318
1319 pfree(errcxt->err_buf.data);
1321}
1322
1323
1324
1325
1326
1327bool
1329{
1330 return errcxt->err_occurred;
1331}
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343#define CHECK_XML_SPACE(p) \
1344 do { \
1345 if (!xmlIsBlank_ch(*(p))) \
1346 return XML_ERR_SPACE_REQUIRED; \
1347 } while (0)
1348
1349#define SKIP_XML_SPACE(p) \
1350 while (xmlIsBlank_ch(*(p))) (p)++
1351
1352
1353
1354#define PG_XMLISNAMECHAR(c) \
1355 (xmlIsBaseChar_ch(c) || xmlIsIdeographicQ(c) \
1356 || xmlIsDigit_ch(c) \
1357 || c == '.' || c == '-' || c == '_' || c == ':' \
1358 || xmlIsCombiningQ(c) \
1359 || xmlIsExtender_ch(c))
1360
1361
1362static xmlChar *
1363xml_pnstrdup(const xmlChar *str, size_t len)
1364{
1365 xmlChar *result;
1366
1367 result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));
1368 memcpy(result, str, len * sizeof(xmlChar));
1369 result[len] = 0;
1370 return result;
1371}
1372
1373
1374static xmlChar *
1375pg_xmlCharStrndup(const char *str, size_t len)
1376{
1377 xmlChar *result;
1378
1379 result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));
1380 memcpy(result, str, len);
1381 result[len] = '\0';
1382
1383 return result;
1384}
1385
1386
1387
1388
1389
1390
1391static char *
1392xml_pstrdup_and_free(xmlChar *str)
1393{
1394 char *result;
1395
1396 if (str)
1397 {
1399 {
1401 }
1403 {
1404 xmlFree(str);
1405 }
1407 }
1408 else
1409 result = NULL;
1410
1411 return result;
1412}
1413
1414
1415
1416
1417
1418
1419
1420static int
1421parse_xml_decl(const xmlChar *str, size_t *lenp,
1422 xmlChar **version, xmlChar **encoding, int *standalone)
1423{
1424 const xmlChar *p;
1425 const xmlChar *save_p;
1426 size_t len;
1427 int utf8char;
1428 int utf8len;
1429
1430
1431
1432
1433
1434
1435
1437
1438
1439 if (version)
1440 *version = NULL;
1443 if (standalone)
1444 *standalone = -1;
1445
1446 p = str;
1447
1448 if (xmlStrncmp(p, (xmlChar *) "<?xml", 5) != 0)
1449 goto finished;
1450
1451
1452
1453
1454
1455
1456
1457
1458
1460 utf8char = xmlGetUTF8Char(p + 5, &utf8len);
1461 if (PG_XMLISNAMECHAR(utf8char))
1462 goto finished;
1463
1464 p += 5;
1465
1466
1467 CHECK_XML_SPACE(p);
1468 SKIP_XML_SPACE(p);
1469 if (xmlStrncmp(p, (xmlChar *) "version", 7) != 0)
1470 return XML_ERR_VERSION_MISSING;
1471 p += 7;
1472 SKIP_XML_SPACE(p);
1473 if (*p != '=')
1474 return XML_ERR_VERSION_MISSING;
1475 p += 1;
1476 SKIP_XML_SPACE(p);
1477
1478 if (*p == '\'' || *p == '"')
1479 {
1480 const xmlChar *q;
1481
1482 q = xmlStrchr(p + 1, *p);
1483 if (!q)
1484 return XML_ERR_VERSION_MISSING;
1485
1486 if (version)
1487 *version = xml_pnstrdup(p + 1, q - p - 1);
1488 p = q + 1;
1489 }
1490 else
1491 return XML_ERR_VERSION_MISSING;
1492
1493
1494 save_p = p;
1495 SKIP_XML_SPACE(p);
1496 if (xmlStrncmp(p, (xmlChar *) "encoding", 8) == 0)
1497 {
1498 CHECK_XML_SPACE(save_p);
1499 p += 8;
1500 SKIP_XML_SPACE(p);
1501 if (*p != '=')
1502 return XML_ERR_MISSING_ENCODING;
1503 p += 1;
1504 SKIP_XML_SPACE(p);
1505
1506 if (*p == '\'' || *p == '"')
1507 {
1508 const xmlChar *q;
1509
1510 q = xmlStrchr(p + 1, *p);
1511 if (!q)
1512 return XML_ERR_MISSING_ENCODING;
1513
1515 *encoding = xml_pnstrdup(p + 1, q - p - 1);
1516 p = q + 1;
1517 }
1518 else
1519 return XML_ERR_MISSING_ENCODING;
1520 }
1521 else
1522 {
1523 p = save_p;
1524 }
1525
1526
1527 save_p = p;
1528 SKIP_XML_SPACE(p);
1529 if (xmlStrncmp(p, (xmlChar *) "standalone", 10) == 0)
1530 {
1531 CHECK_XML_SPACE(save_p);
1532 p += 10;
1533 SKIP_XML_SPACE(p);
1534 if (*p != '=')
1535 return XML_ERR_STANDALONE_VALUE;
1536 p += 1;
1537 SKIP_XML_SPACE(p);
1538 if (xmlStrncmp(p, (xmlChar *) "'yes'", 5) == 0 ||
1539 xmlStrncmp(p, (xmlChar *) "\"yes\"", 5) == 0)
1540 {
1541 if (standalone)
1542 *standalone = 1;
1543 p += 5;
1544 }
1545 else if (xmlStrncmp(p, (xmlChar *) "'no'", 4) == 0 ||
1546 xmlStrncmp(p, (xmlChar *) "\"no\"", 4) == 0)
1547 {
1548 if (standalone)
1549 *standalone = 0;
1550 p += 4;
1551 }
1552 else
1553 return XML_ERR_STANDALONE_VALUE;
1554 }
1555 else
1556 {
1557 p = save_p;
1558 }
1559
1560 SKIP_XML_SPACE(p);
1561 if (xmlStrncmp(p, (xmlChar *) "?>", 2) != 0)
1562 return XML_ERR_XMLDECL_NOT_FINISHED;
1563 p += 2;
1564
1565finished:
1567
1568 for (p = str; p < str + len; p++)
1569 if (*p > 127)
1570 return XML_ERR_INVALID_CHAR;
1571
1572 if (lenp)
1573 *lenp = len;
1574
1575 return XML_ERR_OK;
1576}
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593static bool
1594print_xml_decl(StringInfo buf, const xmlChar *version,
1596{
1599 || standalone != -1)
1600 {
1602
1603 if (version)
1605 else
1607
1609 {
1610
1611
1612
1613
1616 }
1617
1618 if (standalone == 1)
1620 else if (standalone == 0)
1623
1624 return true;
1625 }
1626 else
1627 return false;
1628}
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659static bool
1660xml_doctype_in_content(const xmlChar *str)
1661{
1662 const xmlChar *p = str;
1663
1664 for (;;)
1665 {
1666 const xmlChar *e;
1667
1668 SKIP_XML_SPACE(p);
1669 if (*p != '<')
1670 return false;
1671 p++;
1672
1673 if (*p == '!')
1674 {
1675 p++;
1676
1677
1678 if (xmlStrncmp(p, (xmlChar *) "DOCTYPE", 7) == 0)
1679 return true;
1680
1681
1682 if (xmlStrncmp(p, (xmlChar *) "--", 2) != 0)
1683 return false;
1684
1685 p = xmlStrstr(p + 2, (xmlChar *) "--");
1686 if (!p || p[2] != '>')
1687 return false;
1688
1689 p += 3;
1690 continue;
1691 }
1692
1693
1694 if (*p != '?')
1695 return false;
1696 p++;
1697
1698
1699 e = xmlStrstr(p, (xmlChar *) "?>");
1700 if ()
1701 return false;
1702
1703
1704 p = e + 2;
1705 }
1706}
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735static xmlDocPtr
1737 bool preserve_whitespace, int encoding,
1738 XmlOptionType *parsed_xmloptiontype, xmlNodePtr *parsed_nodes,
1739 Node *escontext)
1740{
1743 xmlChar *utf8string;
1745 volatile xmlParserCtxtPtr ctxt = NULL;
1746 volatile xmlDocPtr doc = NULL;
1747
1748
1749
1750
1751
1753 string = xml_text2xmlChar(data);
1754
1755
1756
1757
1758
1759
1760
1761
1766
1767
1769
1770
1772 {
1773 bool parse_as_document = false;
1775 int res_code;
1776 size_t count = 0;
1777 xmlChar *version = NULL;
1778 int standalone = 0;
1779
1780
1781 xmlInitParser();
1782
1783
1785 parse_as_document = true;
1786 else
1787 {
1788
1789 res_code = parse_xml_decl(utf8string,
1790 &count, &version, NULL, &standalone);
1791 if (res_code != 0)
1792 {
1794 errcode(ERRCODE_INVALID_XML_CONTENT),
1795 errmsg_internal("invalid XML content: invalid XML declaration"),
1796 errdetail_for_xml_code(res_code));
1797 goto fail;
1798 }
1799
1800
1801 if (xml_doctype_in_content(utf8string + count))
1802 parse_as_document = true;
1803 }
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814 options = XML_PARSE_NOENT | XML_PARSE_DTDATTR
1815 | (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS);
1816
1817
1818 if (parsed_xmloptiontype != NULL)
1821 if (parsed_nodes != NULL)
1822 *parsed_nodes = NULL;
1823
1824 if (parse_as_document)
1825 {
1826 ctxt = xmlNewParserCtxt();
1827 if (ctxt == NULL || xmlerrcxt->err_occurred)
1829 "could not allocate parser context");
1830
1831 doc = xmlCtxtReadDoc(ctxt, utf8string,
1832 NULL,
1833 "UTF-8",
1835
1836 if (doc == NULL || xmlerrcxt->err_occurred)
1837 {
1838
1840 xml_errsave(escontext, xmlerrcxt,
1841 ERRCODE_INVALID_XML_DOCUMENT,
1842 "invalid XML document");
1843 else
1844 xml_errsave(escontext, xmlerrcxt,
1845 ERRCODE_INVALID_XML_CONTENT,
1846 "invalid XML content");
1847 goto fail;
1848 }
1849 }
1850 else
1851 {
1852 xmlNodePtr root;
1853
1854
1855 doc = xmlNewDoc(version);
1856 if (doc == NULL || xmlerrcxt->err_occurred)
1858 "could not allocate XML document");
1859
1860 Assert(doc->encoding == NULL);
1861 doc->encoding = xmlStrdup((const xmlChar *) "UTF-8");
1862 if (doc->encoding == NULL || xmlerrcxt->err_occurred)
1864 "could not allocate XML document");
1865 doc->standalone = standalone;
1866
1867 root = xmlNewNode(NULL, (const xmlChar *) "content-root");
1868 if (root == NULL || xmlerrcxt->err_occurred)
1870 "could not allocate xml node");
1871
1872 xmlDocSetRootElement(doc, root);
1873
1874
1875 if (*(utf8string + count))
1876 {
1877 xmlNodePtr node_list = NULL;
1878 xmlParserErrors res;
1879
1880 res = xmlParseInNodeContext(root,
1881 (char *) utf8string + count,
1882 strlen((char *) utf8string + count),
1884 &node_list);
1885
1886 if (res != XML_ERR_OK || xmlerrcxt->err_occurred)
1887 {
1888 xmlFreeNodeList(node_list);
1889 xml_errsave(escontext, xmlerrcxt,
1890 ERRCODE_INVALID_XML_CONTENT,
1891 "invalid XML content");
1892 goto fail;
1893 }
1894
1895 if (parsed_nodes != NULL)
1896 *parsed_nodes = node_list;
1897 else
1898 xmlFreeNodeList(node_list);
1899 }
1900 }
1901
1902fail:
1903 ;
1904 }
1906 {
1907 if (doc != NULL)
1908 xmlFreeDoc(doc);
1909 if (ctxt != NULL)
1910 xmlFreeParserCtxt(ctxt);
1911
1913
1915 }
1917
1918 if (ctxt != NULL)
1919 xmlFreeParserCtxt(ctxt);
1920
1922
1923 return doc;
1924}
1925
1926
1927
1928
1929
1930static xmlChar *
1931xml_text2xmlChar(text *in)
1932{
1934}
1935
1936
1937#ifdef USE_LIBXMLCONTEXT
1938
1939
1940
1941
1942
1943static void
1944xml_memory_init(void)
1945{
1946
1947 if (LibxmlContext == NULL)
1949 "Libxml context",
1951
1952
1953 xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
1954}
1955
1956
1957
1958
1959static void *
1960xml_palloc(size_t size)
1961{
1963}
1964
1965
1966static void *
1967xml_repalloc(void *ptr, size_t size)
1968{
1970}
1971
1972
1973static void
1974xml_pfree(void *ptr)
1975{
1976
1977 if (ptr)
1979}
1980
1981
1982static char *
1983xml_pstrdup(const char *string)
1984{
1986}
1987#endif
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001static xmlParserInputPtr
2002xmlPgEntityLoader(const char *URL, const char *ID,
2003 xmlParserCtxtPtr ctxt)
2004{
2005 return xmlNewStringInputStream(ctxt, (const xmlChar *) "");
2006}
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019void
2021{
2022 char *detail;
2023
2024
2025 if (errcxt->magic != ERRCXT_MAGIC)
2026 elog(ERROR, "xml_ereport called with invalid PgXmlErrorContext");
2027
2028
2029 errcxt->err_occurred = false;
2030
2031
2032 if (errcxt->err_buf.len > 0)
2033 detail = errcxt->err_buf.data;
2034 else
2035 detail = NULL;
2036
2041}
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056static void
2058 int sqlcode, const char *msg)
2059{
2060 char *detail;
2061
2062
2063 if (errcxt->magic != ERRCXT_MAGIC)
2064 elog(ERROR, "xml_errsave called with invalid PgXmlErrorContext");
2065
2066
2067 errcxt->err_occurred = false;
2068
2069
2070 if (errcxt->err_buf.len > 0)
2071 detail = errcxt->err_buf.data;
2072 else
2073 detail = NULL;
2074
2079}
2080
2081
2082
2083
2084
2085static void
2086xml_errorHandler(void *data, PgXmlErrorPtr error)
2087{
2089 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) error->ctxt;
2090 xmlParserInputPtr input = (ctxt != NULL) ? ctxt->input : NULL;
2091 xmlNodePtr node = error->node;
2092 const xmlChar *name = (node != NULL &&
2093 node->type == XML_ELEMENT_NODE) ? node->name : NULL;
2094 int domain = error->domain;
2095 int level = error->level;
2097
2098
2099
2100
2101
2102
2103
2104 if (xmlerrcxt->magic != ERRCXT_MAGIC)
2105 elog(FATAL, "xml_errorHandler called with invalid PgXmlErrorContext");
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115 switch (error->code)
2116 {
2117 case XML_WAR_NS_URI:
2118 level = XML_ERR_ERROR;
2119 domain = XML_FROM_NAMESPACE;
2120 break;
2121
2122 case XML_ERR_NS_DECL_ERROR:
2123 case XML_WAR_NS_URI_RELATIVE:
2124 case XML_WAR_NS_COLUMN:
2125 case XML_NS_ERR_XML_NAMESPACE:
2126 case XML_NS_ERR_UNDEFINED_NAMESPACE:
2127 case XML_NS_ERR_QNAME:
2128 case XML_NS_ERR_ATTRIBUTE_REDEFINED:
2129 case XML_NS_ERR_EMPTY:
2130 domain = XML_FROM_NAMESPACE;
2131 break;
2132 }
2133
2134
2135 switch (domain)
2136 {
2137 case XML_FROM_PARSER:
2138
2139
2140
2141
2142
2143
2144
2145
2146 if (error->code == XML_ERR_NOT_WELL_BALANCED &&
2147 xmlerrcxt->err_occurred)
2148 return;
2149
2150
2151 case XML_FROM_NONE:
2152 case XML_FROM_MEMORY:
2153 case XML_FROM_IO:
2154
2155
2156
2157
2158
2159 if (error->code == XML_WAR_UNDECLARED_ENTITY)
2160 return;
2161
2162
2163 break;
2164
2165 default:
2166
2168 return;
2169 break;
2170 }
2171
2172
2174
2175 if (error->line > 0)
2177 if (name != NULL)
2179 if (error->message != NULL)
2181 else
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195 if (input != NULL)
2196 {
2197 xmlGenericErrorFunc errFuncSaved = xmlGenericError;
2198 void *errCtxSaved = xmlGenericErrorContext;
2199
2200 xmlSetGenericErrorFunc(errorBuf,
2202
2203
2204 appendStringInfoLineSeparator(errorBuf);
2205
2206 xmlParserPrintFileContext(input);
2207
2208
2209 xmlSetGenericErrorFunc(errCtxSaved, errFuncSaved);
2210 }
2211
2212
2213 chopStringInfoNewlines(errorBuf);
2214
2215
2216
2217
2218
2219
2220
2221
2222
2224 {
2225 appendStringInfoLineSeparator(&xmlerrcxt->err_buf);
2227 errorBuf->len);
2228
2230 return;
2231 }
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241 if (level >= XML_ERR_ERROR)
2242 {
2243 appendStringInfoLineSeparator(&xmlerrcxt->err_buf);
2245 errorBuf->len);
2246
2247 xmlerrcxt->err_occurred = true;
2248 }
2249 else if (level >= XML_ERR_WARNING)
2250 {
2253 }
2254 else
2255 {
2258 }
2259
2261}
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273static int
2274errdetail_for_xml_code(int code)
2275{
2276 const char *det;
2277
2278 switch (code)
2279 {
2280 case XML_ERR_INVALID_CHAR:
2281 det = gettext_noop("Invalid character value.");
2282 break;
2283 case XML_ERR_SPACE_REQUIRED:
2285 break;
2286 case XML_ERR_STANDALONE_VALUE:
2287 det = gettext_noop("standalone accepts only 'yes' or 'no'.");
2288 break;
2289 case XML_ERR_VERSION_MISSING:
2290 det = gettext_noop("Malformed declaration: missing version.");
2291 break;
2292 case XML_ERR_MISSING_ENCODING:
2293 det = gettext_noop("Missing encoding in text declaration.");
2294 break;
2295 case XML_ERR_XMLDECL_NOT_FINISHED:
2296 det = gettext_noop("Parsing XML declaration: '?>' expected.");
2297 break;
2298 default:
2299 det = gettext_noop("Unrecognized libxml error code: %d.");
2300 break;
2301 }
2302
2304}
2305
2306
2307
2308
2309
2310static void
2312{
2313 while (str->len > 0 && str->data[str->len - 1] == '\n')
2314 str->data[--str->len] = '\0';
2315}
2316
2317
2318
2319
2320
2321static void
2323{
2324 chopStringInfoNewlines(str);
2325 if (str->len > 0)
2327}
2328
2329
2330
2331
2332
2334sqlchar_to_unicode(const char *s)
2335{
2336 char *utf8string;
2337 pg_wchar ret[2];
2338
2339
2341
2344
2345 if (utf8string != s)
2346 pfree(utf8string);
2347
2348 return ret[0];
2349}
2350
2351
2352static bool
2353is_valid_xml_namefirst(pg_wchar c)
2354{
2355
2356 return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)
2357 || c == '_' || c == ':');
2358}
2359
2360
2361static bool
2362is_valid_xml_namechar(pg_wchar c)
2363{
2364
2365 return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)
2366 || xmlIsDigitQ(c)
2367 || c == '.' || c == '-' || c == '_' || c == ':'
2368 || xmlIsCombiningQ(c)
2369 || xmlIsExtenderQ(c));
2370}
2371#endif
2372
2373
2374
2375
2376
2377char *
2379 bool escape_period)
2380{
2381#ifdef USE_LIBXML
2383 const char *p;
2384
2385
2386
2387
2388
2389 Assert(fully_escaped || !escape_period);
2390
2392
2394 {
2395 if (*p == ':' && (p == ident || fully_escaped))
2397 else if (*p == '_' && *(p + 1) == 'x')
2399 else if (fully_escaped && p == ident &&
2401 {
2402 if (*p == 'x')
2404 else
2406 }
2407 else if (escape_period && *p == '.')
2409 else
2410 {
2411 pg_wchar u = sqlchar_to_unicode(p);
2412
2413 if ((p == ident)
2414 ? !is_valid_xml_namefirst(u)
2415 : !is_valid_xml_namechar(u))
2417 else
2419 }
2420 }
2421
2422 return buf.data;
2423#else
2425 return NULL;
2426#endif
2427}
2428
2429
2430
2431
2432
2433char *
2435{
2437 const char *p;
2438
2440
2442 {
2443 if (*p == '_' && *(p + 1) == 'x'
2444 && isxdigit((unsigned char) *(p + 2))
2445 && isxdigit((unsigned char) *(p + 3))
2446 && isxdigit((unsigned char) *(p + 4))
2447 && isxdigit((unsigned char) *(p + 5))
2448 && *(p + 6) == '_')
2449 {
2451 unsigned int u;
2452
2453 sscanf(p + 2, "%X", &u);
2456 p += 6;
2457 }
2458 else
2460 }
2461
2462 return buf.data;
2463}
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475char *
2477{
2479 {
2481 Oid elmtype;
2483 bool elmbyval;
2484 char elmalign;
2485 int num_elems;
2486 Datum *elem_values;
2487 bool *elem_nulls;
2489 int i;
2490
2494
2496 elmlen, elmbyval, elmalign,
2497 &elem_values, &elem_nulls,
2498 &num_elems);
2499
2501
2502 for (i = 0; i < num_elems; i++)
2503 {
2504 if (elem_nulls[i])
2505 continue;
2509 elmtype, true));
2511 }
2512
2513 pfree(elem_values);
2514 pfree(elem_nulls);
2515
2516 return buf.data;
2517 }
2518 else
2519 {
2520 Oid typeOut;
2521 bool isvarlena;
2522 char *str;
2523
2524
2525
2526
2527
2529
2530
2531
2532
2533 switch (type)
2534 {
2535 case BOOLOID:
2537 return "true";
2538 else
2539 return "false";
2540
2541 case DATEOID:
2542 {
2546
2548
2551 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2552 errmsg("date out of range"),
2553 errdetail("XML does not support infinite date values.")));
2557
2559 }
2560
2561 case TIMESTAMPOID:
2562 {
2567
2569
2570
2573 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2574 errmsg("timestamp out of range"),
2575 errdetail("XML does not support infinite timestamp values.")));
2578 else
2580 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2581 errmsg("timestamp out of range")));
2582
2584 }
2585
2586 case TIMESTAMPTZOID:
2587 {
2590 int tz;
2592 const char *tzn = NULL;
2594
2596
2597
2600 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2601 errmsg("timestamp out of range"),
2602 errdetail("XML does not support infinite timestamp values.")));
2605 else
2607 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2608 errmsg("timestamp out of range")));
2609
2611 }
2612
2613#ifdef USE_LIBXML
2614 case BYTEAOID:
2615 {
2618 volatile xmlBufferPtr buf = NULL;
2619 volatile xmlTextWriterPtr writer = NULL;
2620 char *result;
2621
2623
2625 {
2626 buf = xmlBufferCreate();
2627 if (buf == NULL || xmlerrcxt->err_occurred)
2629 "could not allocate xmlBuffer");
2630 writer = xmlNewTextWriterMemory(buf, 0);
2631 if (writer == NULL || xmlerrcxt->err_occurred)
2633 "could not allocate xmlTextWriter");
2634
2636 xmlTextWriterWriteBase64(writer, VARDATA_ANY(bstr),
2638 else
2639 xmlTextWriterWriteBinHex(writer, VARDATA_ANY(bstr),
2641
2642
2643 xmlFreeTextWriter(writer);
2644 writer = NULL;
2645
2646 result = pstrdup((const char *) xmlBufferContent(buf));
2647 }
2649 {
2650 if (writer)
2651 xmlFreeTextWriter(writer);
2652 if (buf)
2653 xmlBufferFree(buf);
2654
2656
2658 }
2660
2661 xmlBufferFree(buf);
2662
2664
2665 return result;
2666 }
2667#endif
2668
2669 }
2670
2671
2672
2673
2676
2677
2678 if (type == XMLOID || !xml_escape_strings)
2679 return str;
2680
2681
2683 }
2684}
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694char *
2696{
2698 const char *p;
2699
2701 for (p = str; *p; p++)
2702 {
2703 switch (*p)
2704 {
2705 case '&':
2707 break;
2708 case '<':
2710 break;
2711 case '>':
2713 break;
2714 case '\r':
2716 break;
2717 default:
2719 break;
2720 }
2721 }
2722 return buf.data;
2723}
2724
2725
2726static char *
2728{
2729 size_t len = strlen(s) + 1;
2731
2732 memcpy(ret, s, len);
2733 return ret;
2734}
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783static List *
2785{
2788 int spi_result;
2789
2790 spi_result = SPI_execute(query, true, 0);
2792 elog(ERROR, "SPI_execute returned %s for %s",
2794
2796 {
2798 bool isnull;
2799
2802 1,
2803 &isnull);
2804 if (!isnull)
2806 }
2807
2808 return list;
2809}
2810
2811
2812static List *
2814{
2816
2818 appendStringInfo(&query, "SELECT oid FROM pg_catalog.pg_class"
2819 " WHERE relnamespace = %u AND relkind IN ("
2823 " AND pg_catalog.has_table_privilege (oid, 'SELECT')"
2824 " ORDER BY relname;", nspid);
2825
2827}
2828
2829
2830
2831
2832
2833
2834#define XML_VISIBLE_SCHEMAS_EXCLUDE "(nspname ~ '^pg_' OR nspname = 'information_schema')"
2835
2836#define XML_VISIBLE_SCHEMAS "SELECT oid FROM pg_catalog.pg_namespace WHERE pg_catalog.has_schema_privilege (oid, 'USAGE') AND NOT " XML_VISIBLE_SCHEMAS_EXCLUDE
2837
2838
2839static List *
2841{
2843}
2844
2845
2846static List *
2848{
2849
2851 " WHERE relkind IN ("
2855 " AND pg_catalog.has_table_privilege(pg_class.oid, 'SELECT')"
2857}
2858
2859
2860
2861
2862
2863
2864
2867 const char *xmlschema, bool nulls, bool tableforest,
2868 const char *targetns, bool top_level)
2869{
2871
2877 xmlschema, nulls, tableforest,
2878 targetns, top_level);
2879}
2880
2881
2884{
2889
2891 nulls, tableforest,
2892 targetns, true)));
2893}
2894
2895
2898{
2903
2905 NULL, nulls, tableforest,
2906 targetns, true)));
2907}
2908
2909
2912{
2918
2922
2924
2925 if (!tableforest)
2926 {
2929 }
2930
2933 if (portal == NULL)
2935 (errcode(ERRCODE_UNDEFINED_CURSOR),
2936 errmsg("cursor \"%s\" does not exist", name)));
2937
2941 tableforest, targetns, true);
2942
2944
2945 if (!tableforest)
2947
2949}
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964static void
2966 const char *xmlschema, const char *targetns,
2967 bool top_level)
2968{
2969
2970 Assert(top_level || !xmlschema);
2971
2973 if (top_level)
2974 {
2976 if (strlen(targetns) > 0)
2978 }
2979 if (xmlschema)
2980 {
2981
2982 if (strlen(targetns) > 0)
2983 appendStringInfo(result, " xsi:schemaLocation=\"%s #\"", targetns);
2984 else
2986 }
2988}
2989
2990
2991static void
2993{
2995}
2996
2997
3000 const char *xmlschema, bool nulls, bool tableforest,
3001 const char *targetns, bool top_level)
3002{
3004 char *xmltn;
3006
3007 if (tablename)
3009 else
3010 xmltn = "table";
3011
3013
3017 (errcode(ERRCODE_DATA_EXCEPTION),
3018 errmsg("invalid query")));
3019
3020 if (!tableforest)
3021 {
3023 targetns, top_level);
3025 }
3026
3027 if (xmlschema)
3029
3032 tableforest, targetns, top_level);
3033
3034 if (!tableforest)
3036
3038
3039 return result;
3040}
3041
3042
3045{
3050 const char *result;
3052
3055 tableforest, targetns);
3057
3059}
3060
3061
3064{
3069 const char *result;
3072
3074
3076 elog(ERROR, "SPI_prepare(\"%s\") failed", query);
3077
3079 elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
3080
3083 tableforest, targetns));
3086
3088}
3089
3090
3093{
3098 const char *xmlschema;
3100
3103 if (portal == NULL)
3105 (errcode(ERRCODE_UNDEFINED_CURSOR),
3106 errmsg("cursor \"%s\" does not exist", name)));
3107 if (portal->tupDesc == NULL)
3109 (errcode(ERRCODE_INVALID_CURSOR_STATE),
3110 errmsg("portal \"%s\" does not return tuples", name)));
3111
3114 tableforest, targetns));
3116
3118}
3119
3120
3123{
3129 const char *xmlschema;
3130
3133 tableforest, targetns);
3135
3137 xmlschema, nulls, tableforest,
3138 targetns, true)));
3139}
3140
3141
3144{
3149
3150 const char *xmlschema;
3153
3155
3157 elog(ERROR, "SPI_prepare(\"%s\") failed", query);
3158
3160 elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
3161
3163 InvalidOid, nulls, tableforest, targetns));
3166
3168 xmlschema, nulls, tableforest,
3169 targetns, true)));
3170}
3171
3172
3173
3174
3175
3176
3177
3180 bool tableforest, const char *targetns, bool top_level)
3181{
3183 char *xmlsn;
3184 List *relid_list;
3186
3188 true, false);
3190
3193
3194 if (xmlschema)
3196
3198
3200
3201 foreach(cell, relid_list)
3202 {
3205
3207 targetns, false);
3208
3211 }
3212
3214
3216
3217 return result;
3218}
3219
3220
3223{
3228
3229 char *schemaname;
3231
3234
3236 nulls, tableforest, targetns, true)));
3237}
3238
3239
3240
3241
3242
3243static void
3245{
3247 "<xsd:schema\n"
3249 if (strlen(targetns) > 0)
3251 "\n"
3252 " targetNamespace=\"%s\"\n"
3253 " elementFormDefault=\"qualified\"",
3254 targetns);
3256 ">\n\n");
3257}
3258
3259
3260static void
3262{
3264}
3265
3266
3269 bool tableforest, const char *targetns)
3270{
3272 List *relid_list;
3273 List *tupdesc_list;
3276
3278
3280
3282
3284
3286
3287 tupdesc_list = NIL;
3288 foreach(cell, relid_list)
3289 {
3291
3295 }
3296
3299
3302 nulls, tableforest, targetns));
3303
3305
3307
3308 return result;
3309}
3310
3311
3314{
3319
3321 nulls, tableforest, targetns)));
3322}
3323
3324
3327{
3332 char *schemaname;
3335
3338
3340 tableforest, targetns);
3341
3343 xmlschema->data, nulls,
3344 tableforest, targetns, true)));
3345}
3346
3347
3348
3349
3350
3351
3352
3355 bool tableforest, const char *targetns)
3356{
3358 List *nspid_list;
3360 char *xmlcn;
3361
3363 true, false);
3365
3368
3369 if (xmlschema)
3371
3373
3375
3376 foreach(cell, nspid_list)
3377 {
3380
3382 tableforest, targetns, false);
3383
3386 }
3387
3389
3391
3392 return result;
3393}
3394
3395
3398{
3402
3404 tableforest, targetns)));
3405}
3406
3407
3410 const char *targetns)
3411{
3412 List *relid_list;
3413 List *nspid_list;
3414 List *tupdesc_list;
3417
3419
3421
3423
3426
3427 tupdesc_list = NIL;
3428 foreach(cell, relid_list)
3429 {
3431
3435 }
3436
3439
3442
3444
3446
3447 return result;
3448}
3449
3450
3453{
3457
3459 tableforest, targetns)));
3460}
3461
3462
3465{
3470
3472
3474 nulls, tableforest, targetns)));
3475}
3476
3477
3478
3479
3480
3481
3482static char *
3484{
3486
3488
3489 if (a)
3492 if (b)
3495 if (c)
3498 if (d)
3501
3502 return result.data;
3503}
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513static const char *
3515 bool tableforest, const char *targetns)
3516{
3517 int i;
3518 char *xmltn;
3519 char *tabletypename;
3520 char *rowtypename;
3522
3524
3526 {
3529
3532 elog(ERROR, "cache lookup failed for relation %u", relid);
3534
3536 true, false);
3537
3541 NameStr(reltuple->relname));
3542
3546 NameStr(reltuple->relname));
3547
3549 }
3550 else
3551 {
3552 if (tableforest)
3553 xmltn = "row";
3554 else
3555 xmltn = "table";
3556
3557 tabletypename = "TableType";
3558 rowtypename = "RowType";
3559 }
3560
3562
3565
3567 "<xsd:complexType name=\"%s\">\n"
3568 " xsd:sequence\n",
3569 rowtypename);
3570
3571 for (i = 0; i < tupdesc->natts; i++)
3572 {
3574
3575 if (att->attisdropped)
3576 continue;
3578 " <xsd:element name=\"%s\" type=\"%s\"%s>\n",
3580 true, false),
3582 nulls ? " nillable=\"true\"" : " minOccurs=\"0\"");
3583 }
3584
3586 " \n"
3587 "\n\n");
3588
3589 if (!tableforest)
3590 {
3592 "<xsd:complexType name=\"%s\">\n"
3593 " xsd:sequence\n"
3594 " <xsd:element name=\"row\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n"
3595 " \n"
3596 "\n\n",
3597 tabletypename, rowtypename);
3598
3600 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3601 xmltn, tabletypename);
3602 }
3603 else
3605 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3606 xmltn, rowtypename);
3607
3609
3610 return result.data;
3611}
3612
3613
3614
3615
3616
3617
3618static const char *
3620 bool tableforest, const char *targetns)
3621{
3623 char *nspname;
3624 char *xmlsn;
3625 char *schematypename;
3628
3631
3633
3635
3638 nspname,
3639 NULL);
3640
3642 "<xsd:complexType name=\"%s\">\n", schematypename);
3643 if (!tableforest)
3645 " xsd:all\n");
3646 else
3648 " xsd:sequence\n");
3649
3650 foreach(cell, relid_list)
3651 {
3657 nspname,
3659
3660 if (!tableforest)
3662 " <xsd:element name=\"%s\" type=\"%s\"/>\n",
3663 xmltn, tabletypename);
3664 else
3666 " <xsd:element name=\"%s\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n",
3667 xmltn, tabletypename);
3668 }
3669
3670 if (!tableforest)
3672 " \n");
3673 else
3675 " \n");
3677 "\n\n");
3678
3680 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3681 xmlsn, schematypename);
3682
3683 return result.data;
3684}
3685
3686
3687
3688
3689
3690
3691static const char *
3693 bool tableforest, const char *targetns)
3694{
3696 char *xmlcn;
3697 char *catalogtypename;
3700
3702
3704
3706
3709 NULL,
3710 NULL);
3711
3713 "<xsd:complexType name=\"%s\">\n", catalogtypename);
3715 " xsd:all\n");
3716
3717 foreach(cell, nspid_list)
3718 {
3724 nspname,
3725 NULL);
3726
3728 " <xsd:element name=\"%s\" type=\"%s\"/>\n",
3729 xmlsn, schematypename);
3730 }
3731
3733 " \n");
3735 "\n\n");
3736
3738 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3739 xmlcn, catalogtypename);
3740
3741 return result.data;
3742}
3743
3744
3745
3746
3747
3748static const char *
3750{
3752
3754
3755 switch (typeoid)
3756 {
3757 case BPCHAROID:
3758 if (typmod == -1)
3760 else
3762 break;
3763 case VARCHAROID:
3764 if (typmod == -1)
3766 else
3768 break;
3769 case NUMERICOID:
3770 if (typmod == -1)
3772 else
3774 ((typmod - VARHDRSZ) >> 16) & 0xffff,
3775 (typmod - VARHDRSZ) & 0xffff);
3776 break;
3777 case INT4OID:
3779 break;
3780 case INT2OID:
3782 break;
3783 case INT8OID:
3785 break;
3786 case FLOAT4OID:
3788 break;
3789 case FLOAT8OID:
3791 break;
3792 case BOOLOID:
3794 break;
3795 case TIMEOID:
3796 if (typmod == -1)
3798 else
3800 break;
3801 case TIMETZOID:
3802 if (typmod == -1)
3804 else
3806 break;
3807 case TIMESTAMPOID:
3808 if (typmod == -1)
3810 else
3812 break;
3813 case TIMESTAMPTZOID:
3814 if (typmod == -1)
3816 else
3818 break;
3819 case DATEOID:
3821 break;
3822 case XMLOID:
3824 break;
3825 default:
3826 {
3829
3832 elog(ERROR, "cache lookup failed for type %u", typeoid);
3834
3839 NameStr(typtuple->typname)));
3840
3842 }
3843 }
3844
3845 return result.data;
3846}
3847
3848
3849
3850
3851
3852
3853static const char *
3855{
3857 int i;
3860
3861
3862 foreach(cell0, tupdesc_list)
3863 {
3865
3866 for (i = 0; i < tupdesc->natts; i++)
3867 {
3869
3870 if (att->attisdropped)
3871 continue;
3873 }
3874 }
3875
3876
3877 foreach(cell0, uniquetypes)
3878 {
3881
3882 if (basetypid != typid)
3884 }
3885
3886
3888
3889 foreach(cell0, uniquetypes)
3890 {
3893 -1));
3894 }
3895
3896 return result.data;
3897}
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908static const char *
3910{
3913
3915
3916 if (typeoid == XMLOID)
3917 {
3919 "<xsd:complexType mixed=\"true\">\n"
3920 " xsd:sequence\n"
3921 " <xsd:any name=\"element\" minOccurs=\"0\" maxOccurs=\"unbounded\" processContents=\"skip\"/>\n"
3922 " \n"
3923 "\n");
3924 }
3925 else
3926 {
3928 "<xsd:simpleType name=\"%s\">\n", typename);
3929
3930 switch (typeoid)
3931 {
3932 case BPCHAROID:
3933 case VARCHAROID:
3934 case TEXTOID:
3936 " <xsd:restriction base=\"xsd:string\">\n");
3937 if (typmod != -1)
3939 " <xsd:maxLength value=\"%d\"/>\n",
3942 break;
3943
3944 case BYTEAOID:
3946 " <xsd:restriction base=\"xsd:%s\">\n"
3947 " \n",
3949 break;
3950
3951 case NUMERICOID:
3952 if (typmod != -1)
3954 " <xsd:restriction base=\"xsd:decimal\">\n"
3955 " <xsd:totalDigits value=\"%d\"/>\n"
3956 " <xsd:fractionDigits value=\"%d\"/>\n"
3957 " \n",
3958 ((typmod - VARHDRSZ) >> 16) & 0xffff,
3959 (typmod - VARHDRSZ) & 0xffff);
3960 break;
3961
3962 case INT2OID:
3964 " <xsd:restriction base=\"xsd:short\">\n"
3965 " <xsd:maxInclusive value=\"%d\"/>\n"
3966 " <xsd:minInclusive value=\"%d\"/>\n"
3967 " \n",
3968 SHRT_MAX, SHRT_MIN);
3969 break;
3970
3971 case INT4OID:
3973 " <xsd:restriction base=\"xsd:int\">\n"
3974 " <xsd:maxInclusive value=\"%d\"/>\n"
3975 " <xsd:minInclusive value=\"%d\"/>\n"
3976 " \n",
3977 INT_MAX, INT_MIN);
3978 break;
3979
3980 case INT8OID:
3982 " <xsd:restriction base=\"xsd:long\">\n"
3983 " <xsd:maxInclusive value=\"" INT64_FORMAT "\"/>\n"
3984 " <xsd:minInclusive value=\"" INT64_FORMAT "\"/>\n"
3985 " \n",
3988 break;
3989
3990 case FLOAT4OID:
3992 " <xsd:restriction base=\"xsd:float\">\n");
3993 break;
3994
3995 case FLOAT8OID:
3997 " <xsd:restriction base=\"xsd:double\">\n");
3998 break;
3999
4000 case BOOLOID:
4002 " <xsd:restriction base=\"xsd:boolean\">\n");
4003 break;
4004
4005 case TIMEOID:
4006 case TIMETZOID:
4007 {
4008 const char *tz = (typeoid == TIMETZOID ? "(\\+|-)\\p{Nd}{2}:\\p{Nd}{2}" : "");
4009
4010 if (typmod == -1)
4012 " <xsd:restriction base=\"xsd:time\">\n"
4013 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}(.\\p{Nd}+)?%s\"/>\n"
4014 " \n", tz);
4015 else if (typmod == 0)
4017 " <xsd:restriction base=\"xsd:time\">\n"
4018 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"
4019 " \n", tz);
4020 else
4022 " <xsd:restriction base=\"xsd:time\">\n"
4023 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}.\\p{Nd}{%d}%s\"/>\n"
4024 " \n", typmod - VARHDRSZ, tz);
4025 break;
4026 }
4027
4028 case TIMESTAMPOID:
4029 case TIMESTAMPTZOID:
4030 {
4031 const char *tz = (typeoid == TIMESTAMPTZOID ? "(\\+|-)\\p{Nd}{2}:\\p{Nd}{2}" : "");
4032
4033 if (typmod == -1)
4035 " <xsd:restriction base=\"xsd:dateTime\">\n"
4036 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}(.\\p{Nd}+)?%s\"/>\n"
4037 " \n", tz);
4038 else if (typmod == 0)
4040 " <xsd:restriction base=\"xsd:dateTime\">\n"
4041 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"
4042 " \n", tz);
4043 else
4045 " <xsd:restriction base=\"xsd:dateTime\">\n"
4046 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}.\\p{Nd}{%d}%s\"/>\n"
4047 " \n", typmod - VARHDRSZ, tz);
4048 break;
4049 }
4050
4051 case DATEOID:
4053 " <xsd:restriction base=\"xsd:date\">\n"
4054 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}\"/>\n"
4055 " \n");
4056 break;
4057
4058 default:
4059 if (get_typtype(typeoid) == TYPTYPE_DOMAIN)
4060 {
4061 Oid base_typeoid;
4062 int32 base_typmod = -1;
4063
4065
4067 " <xsd:restriction base=\"%s\"/>\n",
4069 }
4070 break;
4071 }
4073 }
4074
4075 return result.data;
4076}
4077
4078
4079
4080
4081
4082
4083static void
4085 bool nulls, bool tableforest,
4086 const char *targetns, bool top_level)
4087{
4088 int i;
4089 char *xmltn;
4090
4091 if (tablename)
4093 else
4094 {
4095 if (tableforest)
4096 xmltn = "row";
4097 else
4098 xmltn = "table";
4099 }
4100
4101 if (tableforest)
4103 else
4105
4107 {
4108 char *colname;
4110 bool isnull;
4111
4113 true, false);
4116 i,
4117 &isnull);
4118 if (isnull)
4119 {
4120 if (nulls)
4121 appendStringInfo(result, " <%s xsi:nil=\"true\"/>\n", colname);
4122 }
4123 else
4125 colname,
4128 colname);
4129 }
4130
4131 if (tableforest)
4132 {
4135 }
4136 else
4138}
4139
4140
4141
4142
4143
4144
4145#ifdef USE_LIBXML
4146
4147
4148
4149
4150
4151
4152
4153static text *
4155{
4157
4158 if (cur->type != XML_ATTRIBUTE_NODE && cur->type != XML_TEXT_NODE)
4159 {
4160 void (*volatile nodefree) (xmlNodePtr) = NULL;
4161 volatile xmlBufferPtr buf = NULL;
4162 volatile xmlNodePtr cur_copy = NULL;
4163
4165 {
4166 int bytes;
4167
4168 buf = xmlBufferCreate();
4169 if (buf == NULL || xmlerrcxt->err_occurred)
4171 "could not allocate xmlBuffer");
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185 cur_copy = xmlCopyNode(cur, 1);
4186 if (cur_copy == NULL || xmlerrcxt->err_occurred)
4188 "could not copy node");
4189 nodefree = (cur_copy->type == XML_DOCUMENT_NODE) ?
4190 (void (*) (xmlNodePtr)) xmlFreeDoc : xmlFreeNode;
4191
4192 bytes = xmlNodeDump(buf, NULL, cur_copy, 0, 0);
4193 if (bytes == -1 || xmlerrcxt->err_occurred)
4195 "could not dump node");
4196
4197 result = xmlBuffer_to_xmltype(buf);
4198 }
4200 {
4201 if (nodefree)
4202 nodefree(cur_copy);
4203 if (buf)
4204 xmlBufferFree(buf);
4205 }
4207 }
4208 else
4209 {
4210 xmlChar *str;
4211
4212 str = xmlXPathCastNodeToString(cur);
4214 {
4215
4217
4220 }
4222 {
4223 xmlFree(str);
4224 }
4226 }
4227
4228 return result;
4229}
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243static int
4244xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
4247{
4248 int result = 0;
4250 Oid datumtype;
4251 char *result_str;
4252
4253 switch (xpathobj->type)
4254 {
4255 case XPATH_NODESET:
4256 if (xpathobj->nodesetval != NULL)
4257 {
4258 result = xpathobj->nodesetval->nodeNr;
4259 if (astate != NULL)
4260 {
4261 int i;
4262
4263 for (i = 0; i < result; i++)
4264 {
4265 datum = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],
4266 xmlerrcxt));
4269 }
4270 }
4271 }
4272 return result;
4273
4274 case XPATH_BOOLEAN:
4275 if (astate == NULL)
4276 return 1;
4278 datumtype = BOOLOID;
4279 break;
4280
4281 case XPATH_NUMBER:
4282 if (astate == NULL)
4283 return 1;
4285 datumtype = FLOAT8OID;
4286 break;
4287
4288 case XPATH_STRING:
4289 if (astate == NULL)
4290 return 1;
4292 datumtype = CSTRINGOID;
4293 break;
4294
4295 default:
4296 elog(ERROR, "xpath expression result type %d is unsupported",
4297 xpathobj->type);
4298 return 0;
4299 }
4300
4301
4306 return 1;
4307}
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321static void
4324{
4326 volatile xmlParserCtxtPtr ctxt = NULL;
4327 volatile xmlDocPtr doc = NULL;
4328 volatile xmlXPathContextPtr xpathctx = NULL;
4329 volatile xmlXPathCompExprPtr xpathcomp = NULL;
4330 volatile xmlXPathObjectPtr xpathobj = NULL;
4331 char *datastr;
4333 int32 xpath_len;
4335 xmlChar *xpath_expr;
4336 size_t xmldecl_len = 0;
4337 int i;
4338 int ndim;
4339 Datum *ns_names_uris;
4340 bool *ns_names_uris_nulls;
4341 int ns_count;
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352 ndim = namespaces ? ARR_NDIM(namespaces) : 0;
4353 if (ndim != 0)
4354 {
4355 int *dims;
4356
4357 dims = ARR_DIMS(namespaces);
4358
4359 if (ndim != 2 || dims[1] != 2)
4361 (errcode(ERRCODE_DATA_EXCEPTION),
4362 errmsg("invalid array for XML namespace mapping"),
4363 errdetail("The array must be two-dimensional with length of the second axis equal to 2.")));
4364
4366
4368 &ns_names_uris, &ns_names_uris_nulls,
4369 &ns_count);
4370
4371 Assert((ns_count % 2) == 0);
4372 ns_count /= 2;
4373 }
4374 else
4375 {
4376 ns_names_uris = NULL;
4377 ns_names_uris_nulls = NULL;
4378 ns_count = 0;
4379 }
4380
4384 if (xpath_len == 0)
4386 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),
4387 errmsg("empty XPath expression")));
4388
4389 string = pg_xmlCharStrndup(datastr, len);
4390 xpath_expr = pg_xmlCharStrndup(VARDATA_ANY(xpath_expr_text), xpath_len);
4391
4392
4393
4394
4395
4396
4397
4398
4400 parse_xml_decl(string, &xmldecl_len, NULL, NULL, NULL);
4401
4403
4405 {
4406 xmlInitParser();
4407
4408
4409
4410
4411
4412 ctxt = xmlNewParserCtxt();
4413 if (ctxt == NULL || xmlerrcxt->err_occurred)
4415 "could not allocate parser context");
4416 doc = xmlCtxtReadMemory(ctxt, (char *) string + xmldecl_len,
4417 len - xmldecl_len, NULL, NULL, 0);
4418 if (doc == NULL || xmlerrcxt->err_occurred)
4420 "could not parse XML document");
4421 xpathctx = xmlXPathNewContext(doc);
4422 if (xpathctx == NULL || xmlerrcxt->err_occurred)
4424 "could not allocate XPath context");
4425 xpathctx->node = (xmlNodePtr) doc;
4426
4427
4428 if (ns_count > 0)
4429 {
4430 for (i = 0; i < ns_count; i++)
4431 {
4432 char *ns_name;
4433 char *ns_uri;
4434
4435 if (ns_names_uris_nulls[i * 2] ||
4436 ns_names_uris_nulls[i * 2 + 1])
4438 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4439 errmsg("neither namespace name nor URI may be null")));
4442 if (xmlXPathRegisterNs(xpathctx,
4443 (xmlChar *) ns_name,
4444 (xmlChar *) ns_uri) != 0)
4446 (errmsg("could not register XML namespace with name \"%s\" and URI \"%s\"",
4447 ns_name, ns_uri)));
4448 }
4449 }
4450
4451
4452
4453
4454
4455
4456
4457 xpathcomp = xmlXPathCtxtCompile(xpathctx, xpath_expr);
4458 if (xpathcomp == NULL || xmlerrcxt->err_occurred)
4459 xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4460 "invalid XPath expression");
4461
4462
4463
4464
4465
4466
4467
4468
4469 xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
4470 if (xpathobj == NULL || xmlerrcxt->err_occurred)
4471 xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4472 "could not create XPath object");
4473
4474
4475
4476
4477 if (res_nitems != NULL)
4478 *res_nitems = xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);
4479 else
4480 (void) xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);
4481 }
4483 {
4484 if (xpathobj)
4485 xmlXPathFreeObject(xpathobj);
4486 if (xpathcomp)
4487 xmlXPathFreeCompExpr(xpathcomp);
4488 if (xpathctx)
4489 xmlXPathFreeContext(xpathctx);
4490 if (doc)
4491 xmlFreeDoc(doc);
4492 if (ctxt)
4493 xmlFreeParserCtxt(ctxt);
4494
4496
4498 }
4500
4501 xmlXPathFreeObject(xpathobj);
4502 xmlXPathFreeCompExpr(xpathcomp);
4503 xmlXPathFreeContext(xpathctx);
4504 xmlFreeDoc(doc);
4505 xmlFreeParserCtxt(ctxt);
4506
4508}
4509#endif
4510
4511
4512
4513
4514
4515
4516
4517
4520{
4521#ifdef USE_LIBXML
4526
4528 xpath_internal(xpath_expr_text, data, namespaces,
4529 NULL, astate);
4531#else
4533 return 0;
4534#endif
4535}
4536
4537
4538
4539
4540
4543{
4544#ifdef USE_LIBXML
4547 int res_nitems;
4548
4549 xpath_internal(xpath_expr_text, data, NULL,
4550 &res_nitems, NULL);
4551
4553#else
4555 return 0;
4556#endif
4557}
4558
4559
4560
4561
4562
4563
4566{
4567#ifdef USE_LIBXML
4571 int res_nitems;
4572
4573 xpath_internal(xpath_expr_text, data, namespaces,
4574 &res_nitems, NULL);
4575
4577#else
4579 return 0;
4580#endif
4581}
4582
4583
4584
4585
4586
4587#ifdef USE_LIBXML
4588static bool
4590{
4591 xmlDocPtr doc;
4593
4594
4595
4596
4597 doc = xml_parse(data, xmloption_arg, true,
4599 if (doc)
4600 xmlFreeDoc(doc);
4601
4603}
4604#endif
4605
4608{
4609#ifdef USE_LIBXML
4611
4613#else
4615 return 0;
4616#endif
4617}
4618
4621{
4622#ifdef USE_LIBXML
4624
4626#else
4628 return 0;
4629#endif
4630}
4631
4634{
4635#ifdef USE_LIBXML
4637
4639#else
4641 return 0;
4642#endif
4643}
4644
4645
4646
4647
4648
4649#ifdef USE_LIBXML
4650
4651
4652
4653
4654
4655static inline XmlTableBuilderData *
4657{
4658 XmlTableBuilderData *result;
4659
4661 elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4662 result = (XmlTableBuilderData *) state->opaque;
4663 if (result->magic != XMLTABLE_CONTEXT_MAGIC)
4664 elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4665
4666 return result;
4667}
4668#endif
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681static void
4683{
4684#ifdef USE_LIBXML
4685 volatile xmlParserCtxtPtr ctxt = NULL;
4686 XmlTableBuilderData *xtCxt;
4688
4689 xtCxt = palloc0(sizeof(XmlTableBuilderData));
4690 xtCxt->magic = XMLTABLE_CONTEXT_MAGIC;
4691 xtCxt->natts = natts;
4692 xtCxt->xpathscomp = palloc0(sizeof(xmlXPathCompExprPtr) * natts);
4693
4695
4697 {
4698 xmlInitParser();
4699
4700 ctxt = xmlNewParserCtxt();
4701 if (ctxt == NULL || xmlerrcxt->err_occurred)
4703 "could not allocate parser context");
4704 }
4706 {
4707 if (ctxt != NULL)
4708 xmlFreeParserCtxt(ctxt);
4709
4711
4713 }
4715
4716 xtCxt->xmlerrcxt = xmlerrcxt;
4717 xtCxt->ctxt = ctxt;
4718
4719 state->opaque = xtCxt;
4720#else
4722#endif
4723}
4724
4725
4726
4727
4728
4729static void
4731{
4732#ifdef USE_LIBXML
4733 XmlTableBuilderData *xtCxt;
4735 char *str;
4736 xmlChar *xstr;
4737 int length;
4738 volatile xmlDocPtr doc = NULL;
4739 volatile xmlXPathContextPtr xpathcxt = NULL;
4740
4741 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetDocument");
4742
4743
4744
4745
4746
4748
4749 length = strlen(str);
4750 xstr = pg_xmlCharStrndup(str, length);
4751
4753 {
4754 doc = xmlCtxtReadMemory(xtCxt->ctxt, (char *) xstr, length, NULL, NULL, 0);
4755 if (doc == NULL || xtCxt->xmlerrcxt->err_occurred)
4756 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
4757 "could not parse XML document");
4758 xpathcxt = xmlXPathNewContext(doc);
4759 if (xpathcxt == NULL || xtCxt->xmlerrcxt->err_occurred)
4761 "could not allocate XPath context");
4762 xpathcxt->node = (xmlNodePtr) doc;
4763 }
4765 {
4766 if (xpathcxt != NULL)
4767 xmlXPathFreeContext(xpathcxt);
4768 if (doc != NULL)
4769 xmlFreeDoc(doc);
4770
4772 }
4774
4775 xtCxt->doc = doc;
4776 xtCxt->xpathcxt = xpathcxt;
4777#else
4779#endif
4780}
4781
4782
4783
4784
4785
4786static void
4788{
4789#ifdef USE_LIBXML
4790 XmlTableBuilderData *xtCxt;
4791
4792 if (name == NULL)
4794 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4795 errmsg("DEFAULT namespace is not supported")));
4796 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetNamespace");
4797
4798 if (xmlXPathRegisterNs(xtCxt->xpathcxt,
4799 pg_xmlCharStrndup(name, strlen(name)),
4800 pg_xmlCharStrndup(uri, strlen(uri))))
4801 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4802 "could not set XML namespace");
4803#else
4805#endif
4806}
4807
4808
4809
4810
4811
4812static void
4814{
4815#ifdef USE_LIBXML
4816 XmlTableBuilderData *xtCxt;
4817 xmlChar *xstr;
4818
4819 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetRowFilter");
4820
4821 if (*path == '\0')
4823 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),
4824 errmsg("row path filter must not be empty string")));
4825
4826 xstr = pg_xmlCharStrndup(path, strlen(path));
4827
4828
4829 Assert(xtCxt->xpathcxt != NULL);
4830
4831 xtCxt->xpathcomp = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);
4832 if (xtCxt->xpathcomp == NULL || xtCxt->xmlerrcxt->err_occurred)
4833 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4834 "invalid XPath expression");
4835#else
4837#endif
4838}
4839
4840
4841
4842
4843
4844static void
4846{
4847#ifdef USE_LIBXML
4848 XmlTableBuilderData *xtCxt;
4849 xmlChar *xstr;
4850
4852
4853 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetColumnFilter");
4854
4855 if (*path == '\0')
4857 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),
4858 errmsg("column path filter must not be empty string")));
4859
4860 xstr = pg_xmlCharStrndup(path, strlen(path));
4861
4862
4863 Assert(xtCxt->xpathcxt != NULL);
4864
4865 xtCxt->xpathscomp[colnum] = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);
4866 if (xtCxt->xpathscomp[colnum] == NULL || xtCxt->xmlerrcxt->err_occurred)
4867 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4868 "invalid XPath expression");
4869#else
4871#endif
4872}
4873
4874
4875
4876
4877
4878
4879static bool
4881{
4882#ifdef USE_LIBXML
4883 XmlTableBuilderData *xtCxt;
4884
4885 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableFetchRow");
4886
4887
4888 xmlSetStructuredErrorFunc(xtCxt->xmlerrcxt, xml_errorHandler);
4889
4890 if (xtCxt->xpathobj == NULL)
4891 {
4892 xtCxt->xpathobj = xmlXPathCompiledEval(xtCxt->xpathcomp, xtCxt->xpathcxt);
4893 if (xtCxt->xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)
4894 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4895 "could not create XPath object");
4896
4897 xtCxt->row_count = 0;
4898 }
4899
4900 if (xtCxt->xpathobj->type == XPATH_NODESET)
4901 {
4902 if (xtCxt->xpathobj->nodesetval != NULL)
4903 {
4904 if (xtCxt->row_count++ < xtCxt->xpathobj->nodesetval->nodeNr)
4905 return true;
4906 }
4907 }
4908
4909 return false;
4910#else
4912 return false;
4913#endif
4914}
4915
4916
4917
4918
4919
4920
4921
4922
4923
4926 Oid typid, int32 typmod, bool *isnull)
4927{
4928#ifdef USE_LIBXML
4930 XmlTableBuilderData *xtCxt;
4931 volatile xmlXPathObjectPtr xpathobj = NULL;
4932
4933 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableGetValue");
4934
4935 Assert(xtCxt->xpathobj &&
4936 xtCxt->xpathobj->type == XPATH_NODESET &&
4937 xtCxt->xpathobj->nodesetval != NULL);
4938
4939
4940 xmlSetStructuredErrorFunc(xtCxt->xmlerrcxt, xml_errorHandler);
4941
4942 *isnull = false;
4943
4944 Assert(xtCxt->xpathscomp[colnum] != NULL);
4945
4947 {
4948 xmlNodePtr cur;
4949 char *cstr = NULL;
4950
4951
4952 cur = xtCxt->xpathobj->nodesetval->nodeTab[xtCxt->row_count - 1];
4953 xtCxt->xpathcxt->node = cur;
4954
4955
4956 xpathobj = xmlXPathCompiledEval(xtCxt->xpathscomp[colnum], xtCxt->xpathcxt);
4957 if (xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)
4958 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4959 "could not create XPath object");
4960
4961
4962
4963
4964
4965
4966
4967
4968 if (xpathobj->type == XPATH_NODESET)
4969 {
4970 int count = 0;
4971
4972 if (xpathobj->nodesetval != NULL)
4973 count = xpathobj->nodesetval->nodeNr;
4974
4975 if (xpathobj->nodesetval == NULL || count == 0)
4976 {
4977 *isnull = true;
4978 }
4979 else
4980 {
4981 if (typid == XMLOID)
4982 {
4983 text *textstr;
4985
4986
4988 for (int i = 0; i < count; i++)
4989 {
4990 textstr =
4991 xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],
4992 xtCxt->xmlerrcxt);
4993
4995 }
4996 cstr = str.data;
4997 }
4998 else
4999 {
5000 xmlChar *str;
5001
5002 if (count > 1)
5004 (errcode(ERRCODE_CARDINALITY_VIOLATION),
5005 errmsg("more than one value returned by column XPath expression")));
5006
5007 str = xmlXPathCastNodeSetToString(xpathobj->nodesetval);
5008 cstr = str ? xml_pstrdup_and_free(str) : "";
5009 }
5010 }
5011 }
5012 else if (xpathobj->type == XPATH_STRING)
5013 {
5014
5015 if (typid == XMLOID)
5016 cstr = escape_xml((char *) xpathobj->stringval);
5017 else
5018 cstr = (char *) xpathobj->stringval;
5019 }
5020 else if (xpathobj->type == XPATH_BOOLEAN)
5021 {
5022 char typcategory;
5023 bool typispreferred;
5024 xmlChar *str;
5025
5026
5028
5029 if (typcategory != TYPCATEGORY_NUMERIC)
5030 str = xmlXPathCastBooleanToString(xpathobj->boolval);
5031 else
5032 str = xmlXPathCastNumberToString(xmlXPathCastBooleanToNumber(xpathobj->boolval));
5033
5034 cstr = xml_pstrdup_and_free(str);
5035 }
5036 else if (xpathobj->type == XPATH_NUMBER)
5037 {
5038 xmlChar *str;
5039
5040 str = xmlXPathCastNumberToString(xpathobj->floatval);
5041 cstr = xml_pstrdup_and_free(str);
5042 }
5043 else
5044 elog(ERROR, "unexpected XPath object type %u", xpathobj->type);
5045
5046
5047
5048
5049
5050 Assert(cstr || *isnull);
5051
5052 if (!*isnull)
5054 cstr,
5055 state->typioparams[colnum],
5056 typmod);
5057 }
5059 {
5060 if (xpathobj != NULL)
5061 xmlXPathFreeObject(xpathobj);
5062 }
5064
5065 return result;
5066#else
5068 return 0;
5069#endif
5070}
5071
5072
5073
5074
5075
5076static void
5078{
5079#ifdef USE_LIBXML
5080 XmlTableBuilderData *xtCxt;
5081
5082 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableDestroyOpaque");
5083
5084
5085 xmlSetStructuredErrorFunc(xtCxt->xmlerrcxt, xml_errorHandler);
5086
5087 if (xtCxt->xpathscomp != NULL)
5088 {
5089 int i;
5090
5091 for (i = 0; i < xtCxt->natts; i++)
5092 if (xtCxt->xpathscomp[i] != NULL)
5093 xmlXPathFreeCompExpr(xtCxt->xpathscomp[i]);
5094 }
5095
5096 if (xtCxt->xpathobj != NULL)
5097 xmlXPathFreeObject(xtCxt->xpathobj);
5098 if (xtCxt->xpathcomp != NULL)
5099 xmlXPathFreeCompExpr(xtCxt->xpathcomp);
5100 if (xtCxt->xpathcxt != NULL)
5101 xmlXPathFreeContext(xtCxt->xpathcxt);
5102 if (xtCxt->doc != NULL)
5103 xmlFreeDoc(xtCxt->doc);
5104 if (xtCxt->ctxt != NULL)
5105 xmlFreeParserCtxt(xtCxt->ctxt);
5106
5108
5109
5110 xtCxt->magic = 0;
5111 state->opaque = NULL;
5112
5113#else
5115#endif
5116}
#define PG_GETARG_ARRAYTYPE_P(n)
#define DatumGetArrayTypeP(X)
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
void j2date(int jd, int *year, int *month, int *day)
void EncodeDateTime(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
void EncodeDateOnly(struct pg_tm *tm, int style, char *str)
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
#define TextDatumGetCString(d)
#define PointerIsValid(pointer)
#define OidIsValid(objectId)
#define TIMESTAMP_NOT_FINITE(j)
#define POSTGRES_EPOCH_JDATE
#define DATE_NOT_FINITE(j)
static DateADT DatumGetDateADT(Datum X)
char * get_database_name(Oid dbid)
int errmsg_internal(const char *fmt,...)
int errdetail_internal(const char *fmt,...)
int errdetail(const char *fmt,...)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define errsave(context,...)
#define ereport(elevel,...)
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
char * OidOutputFunctionCall(Oid functionId, Datum val)
Datum Float8GetDatum(float8 X)
#define PG_GETARG_TEXT_PP(n)
#define PG_RETURN_BYTEA_P(x)
#define DatumGetByteaPP(X)
#define PG_GETARG_POINTER(n)
#define PG_RETURN_CSTRING(x)
#define DirectFunctionCall1(func, arg1)
#define PG_GETARG_CSTRING(n)
#define PG_GETARG_NAME(n)
#define PG_RETURN_TEXT_P(x)
#define PG_GETARG_INT32(n)
#define PG_GETARG_BOOL(n)
#define PG_RETURN_DATUM(x)
#define PG_RETURN_BOOL(x)
Assert(PointerIsAligned(start, uint64))
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
if(TABLE==NULL||TABLE_index==NULL)
List * lappend(List *list, void *datum)
List * lappend_oid(List *list, Oid datum)
List * list_append_unique_oid(List *list, Oid datum)
char * get_rel_name(Oid relid)
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
char get_typtype(Oid typid)
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Oid getBaseType(Oid typid)
char * get_namespace_name(Oid nspid)
void get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
#define type_is_array_domain(typid)
int GetDatabaseEncoding(void)
char * pg_any_to_server(const char *s, int len, int encoding)
unsigned char * pg_do_encoding_conversion(unsigned char *src, int len, int src_encoding, int dest_encoding)
void pg_unicode_to_server(pg_wchar c, unsigned char *s)
int pg_get_client_encoding(void)
char * pg_server_to_any(const char *s, int len, int encoding)
int pg_encoding_mb2wchar_with_len(int encoding, const char *from, pg_wchar *to, int len)
int pg_mblen(const char *mbstr)
char * MemoryContextStrdup(MemoryContext context, const char *string)
void * MemoryContextAlloc(MemoryContext context, Size size)
char * pstrdup(const char *in)
void * repalloc(void *pointer, Size size)
void pfree(void *pointer)
void * palloc0(Size size)
MemoryContext TopMemoryContext
MemoryContext CurrentMemoryContext
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Oid exprType(const Node *expr)
#define IsA(nodeptr, _type_)
FormData_pg_attribute * Form_pg_attribute
#define ERRCODE_DATA_CORRUPTED
FormData_pg_class * Form_pg_class
#define forboth(cell1, list1, cell2, list2)
#define list_make2(x1, x2)
FormData_pg_type * Form_pg_type
#define MAX_MULTIBYTE_CHAR_LEN
#define MAX_UNICODE_EQUIVALENT_STRING
#define pg_encoding_to_char
#define pg_char_to_encoding
int pg_strcasecmp(const char *s1, const char *s2)
size_t strnlen(const char *str, size_t maxlen)
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
static bool DatumGetBool(Datum X)
static Datum PointerGetDatum(const void *X)
static Oid DatumGetObjectId(Datum X)
static Datum BoolGetDatum(bool X)
static Datum ObjectIdGetDatum(Oid X)
static char * DatumGetCString(Datum X)
static Datum CStringGetDatum(const char *X)
void pq_sendtext(StringInfo buf, const char *str, int slen)
void pq_begintypsend(StringInfo buf)
const char * pq_getmsgbytes(StringInfo msg, int datalen)
bytea * pq_endtypsend(StringInfo buf)
Datum regclassout(PG_FUNCTION_ARGS)
Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)
const char * SPI_result_code_string(int code)
SPITupleTable * SPI_tuptable
Portal SPI_cursor_find(const char *name)
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
void SPI_cursor_close(Portal portal)
void * SPI_palloc(Size size)
int SPI_execute(const char *src, bool read_only, long tcount)
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
char * SPI_fname(TupleDesc tupdesc, int fnumber)
void destroyStringInfo(StringInfo str)
StringInfo makeStringInfo(void)
void appendStringInfo(StringInfo str, const char *fmt,...)
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
void appendStringInfoString(StringInfo str, const char *s)
void appendStringInfoChar(StringInfo str, char ch)
void initStringInfo(StringInfo str)
StringInfoData * StringInfo
#define appendStringInfoCharMacro(str, ch)
void(* InitOpaque)(struct TableFuncScanState *state, int natts)
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
struct TupleDescData * TupleDesc
static Timestamp DatumGetTimestamp(Datum X)
#define SET_VARSIZE(PTR, len)
#define VARSIZE_ANY_EXHDR(PTR)
static void appendStringInfoText(StringInfo str, const text *t)
text * cstring_to_text_with_len(const char *s, int len)
text * cstring_to_text(const char *s)
char * text_to_cstring(const text *t)
int pg_encoding_mblen(int encoding, const char *mbstr)
Datum xml_in(PG_FUNCTION_ARGS)
Datum cursor_to_xmlschema(PG_FUNCTION_ARGS)
Datum table_to_xml(PG_FUNCTION_ARGS)
Datum query_to_xmlschema(PG_FUNCTION_ARGS)
Datum database_to_xml(PG_FUNCTION_ARGS)
static const char * map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tableforest, const char *targetns)
xmltype * xmlroot(xmltype *data, text *version, int standalone)
static void XmlTableInitOpaque(struct TableFuncScanState *state, int natts)
static const char * map_sql_type_to_xml_name(Oid typeoid, int typmod)
static const char * map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
Datum texttoxml(PG_FUNCTION_ARGS)
static char * xml_out_internal(xmltype *x, pg_enc target_encoding)
char * map_sql_identifier_to_xml_name(const char *ident, bool fully_escaped, bool escape_period)
static void xsd_schema_element_start(StringInfo result, const char *targetns)
Datum query_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
Datum xmltotext(PG_FUNCTION_ARGS)
Datum schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
Datum xmlexists(PG_FUNCTION_ARGS)
Datum xmltext(PG_FUNCTION_ARGS)
static char * map_multipart_sql_identifier_to_xml_name(const char *a, const char *b, const char *c, const char *d)
static StringInfo database_to_xmlschema_internal(bool nulls, bool tableforest, const char *targetns)
Datum database_to_xmlschema(PG_FUNCTION_ARGS)
static List * schema_get_xml_visible_tables(Oid nspid)
Datum schema_to_xmlschema(PG_FUNCTION_ARGS)
text * xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
static void xmldata_root_element_start(StringInfo result, const char *eltname, const char *xmlschema, const char *targetns, bool top_level)
char * map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
Datum xml_send(PG_FUNCTION_ARGS)
static const char * map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool tableforest, const char *targetns)
const TableFuncRoutine XmlTableRoutine
Datum xmlcomment(PG_FUNCTION_ARGS)
static void XmlTableSetNamespace(struct TableFuncScanState *state, const char *name, const char *uri)
Datum xmlconcat2(PG_FUNCTION_ARGS)
static void XmlTableSetRowFilter(struct TableFuncScanState *state, const char *path)
static List * database_get_xml_visible_schemas(void)
static void xmldata_root_element_end(StringInfo result, const char *eltname)
xmltype * xmlconcat(List *args)
static Datum XmlTableGetValue(struct TableFuncScanState *state, int colnum, Oid typid, int32 typmod, bool *isnull)
char * escape_xml(const char *str)
Datum xml_is_well_formed_document(PG_FUNCTION_ARGS)
Datum query_to_xml(PG_FUNCTION_ARGS)
static StringInfo database_to_xml_internal(const char *xmlschema, bool nulls, bool tableforest, const char *targetns)
static xmltype * stringinfo_to_xmltype(StringInfo buf)
Datum xml_is_well_formed_content(PG_FUNCTION_ARGS)
#define XML_VISIBLE_SCHEMAS
static List * database_get_xml_visible_tables(void)
bool xml_is_document(xmltype *arg)
static StringInfo schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tableforest, const char *targetns)
Datum table_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
Datum xmlvalidate(PG_FUNCTION_ARGS)
xmltype * xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace)
static xmltype * cstring_to_xmltype(const char *string)
static List * query_to_oid_list(const char *query)
xmltype * xmlelement(XmlExpr *xexpr, Datum *named_argvalue, bool *named_argnull, Datum *argvalue, bool *argnull)
static void XmlTableSetDocument(struct TableFuncScanState *state, Datum value)
static void XmlTableDestroyOpaque(struct TableFuncScanState *state)
static const char * map_sql_typecoll_to_xmlschema_types(List *tupdesc_list)
#define PG_XML_DEFAULT_VERSION
Datum table_to_xmlschema(PG_FUNCTION_ARGS)
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 void SPI_sql_row_to_xmlelement(uint64 rownum, StringInfo result, char *tablename, bool nulls, bool tableforest, const char *targetns, bool top_level)
static StringInfo schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
static StringInfo table_to_xml_internal(Oid relid, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
Datum schema_to_xml(PG_FUNCTION_ARGS)
char * map_xml_name_to_sql_identifier(const char *name)
Datum database_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
static bool XmlTableFetchRow(struct TableFuncScanState *state)
Datum cursor_to_xml(PG_FUNCTION_ARGS)
Datum xpath_exists(PG_FUNCTION_ARGS)
Datum xml_is_well_formed(PG_FUNCTION_ARGS)
static char * _SPI_strdup(const char *s)
static void XmlTableSetColumnFilter(struct TableFuncScanState *state, const char *path, int colnum)
static const char * map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tableforest, const char *targetns)
Datum xml_out(PG_FUNCTION_ARGS)
Datum xml_recv(PG_FUNCTION_ARGS)
xmltype * xmlpi(const char *target, text *arg, bool arg_is_null, bool *result_is_null)
Datum xpath(PG_FUNCTION_ARGS)
static void xsd_schema_element_end(StringInfo result)
@ XML_STANDALONE_NO_VALUE
struct PgXmlErrorContext PgXmlErrorContext
PgXmlErrorContext * pg_xml_init(PgXmlStrictness strictness)
#define PG_RETURN_XML_P(x)
void xml_ereport(PgXmlErrorContext *errcxt, int level, int sqlcode, const char *msg)
bool pg_xml_error_occurred(PgXmlErrorContext *errcxt)
static xmltype * DatumGetXmlP(Datum X)
void pg_xml_done(PgXmlErrorContext *errcxt, bool isError)
#define PG_GETARG_XML_P(n)
void pg_xml_init_library(void)
@ PG_XML_STRICTNESS_LEGACY
@ PG_XML_STRICTNESS_WELLFORMED