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;
757 xmlNodePtr oldroot;
759
760 root = xmlNewNode(NULL, (const xmlChar *) "content-root");
761 if (root == NULL || xmlerrcxt->err_occurred)
763 "could not allocate xml node");
764
765
766
767
768
769 oldroot = xmlDocSetRootElement(doc, root);
770 if (oldroot != NULL)
771 xmlFreeNode(oldroot);
772
773 xmlAddChildList(root, content_nodes);
774
775
776
777
778
779
780
781
782 newline = xmlNewDocText(NULL, (const xmlChar *) "\n");
783 if (newline == NULL || xmlerrcxt->err_occurred)
785 "could not allocate xml node");
786
787 for (xmlNodePtr node = root->children; node; node = node->next)
788 {
789
790 if (node->type != XML_TEXT_NODE && node->prev != NULL)
791 {
792 if (xmlSaveTree(ctxt, newline) == -1 || xmlerrcxt->err_occurred)
793 {
796 "could not save newline to xmlBuffer");
797 }
798 }
799
800 if (xmlSaveTree(ctxt, node) == -1 || xmlerrcxt->err_occurred)
801 {
804 "could not save content to xmlBuffer");
805 }
806 }
807
809 }
810
811 if (xmlSaveClose(ctxt) == -1 || xmlerrcxt->err_occurred)
812 {
813 ctxt = NULL;
815 "could not close xmlSaveCtxtPtr");
816 }
817
818
819
820
822 {
823 const char *str = (const char *) xmlBufferContent(buf);
824 int len = xmlBufferLength(buf);
825
826 while (len > 0 && (str[len - 1] == '\n' ||
829
831 }
832 else
833 result = (text *) xmlBuffer_to_xmltype(buf);
834 }
836 {
837 if (ctxt)
838 xmlSaveClose(ctxt);
840 xmlBufferFree(buf);
841 if (doc)
842 xmlFreeDoc(doc);
843
845
847 }
849
850 xmlBufferFree(buf);
851 xmlFreeDoc(doc);
852
854
855 return result;
856#else
858 return NULL;
859#endif
860}
861
862
865 Datum *named_argvalue, bool *named_argnull,
866 Datum *argvalue, bool *argnull)
867{
868#ifdef USE_LIBXML
870 List *named_arg_strings;
871 List *arg_strings;
872 int i;
876 volatile xmlBufferPtr buf = NULL;
877 volatile xmlTextWriterPtr writer = NULL;
878
879
880
881
882
883
884
885
886 named_arg_strings = NIL;
887 i = 0;
889 {
891 char *str;
892
893 if (named_argnull[i])
894 str = NULL;
895 else
898 false);
899 named_arg_strings = lappend(named_arg_strings, str);
900 i++;
901 }
902
903 arg_strings = NIL;
904 i = 0;
906 {
908 char *str;
909
910
911 if (!argnull[i])
912 {
915 true);
916 arg_strings = lappend(arg_strings, str);
917 }
918 i++;
919 }
920
922
924 {
925 buf = xmlBufferCreate();
926 if (buf == NULL || xmlerrcxt->err_occurred)
928 "could not allocate xmlBuffer");
929 writer = xmlNewTextWriterMemory(buf, 0);
930 if (writer == NULL || xmlerrcxt->err_occurred)
932 "could not allocate xmlTextWriter");
933
934 xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name);
935
936 forboth(arg, named_arg_strings, narg, xexpr->arg_names)
937 {
940
942 xmlTextWriterWriteAttribute(writer,
943 (xmlChar *) argname,
944 (xmlChar *) str);
945 }
946
947 foreach(arg, arg_strings)
948 {
950
951 xmlTextWriterWriteRaw(writer, (xmlChar *) str);
952 }
953
954 xmlTextWriterEndElement(writer);
955
956
957 xmlFreeTextWriter(writer);
958 writer = NULL;
959
960 result = xmlBuffer_to_xmltype(buf);
961 }
963 {
964 if (writer)
965 xmlFreeTextWriter(writer);
967 xmlBufferFree(buf);
968
970
972 }
974
975 xmlBufferFree(buf);
976
978
979 return result;
980#else
982 return NULL;
983#endif
984}
985
986
989{
990#ifdef USE_LIBXML
991 xmlDocPtr doc;
992
993 doc = xml_parse(data, xmloption_arg, preserve_whitespace,
995 xmlFreeDoc(doc);
996
998#else
1000 return NULL;
1001#endif
1002}
1003
1004
1006xmlpi(const char *target, text *arg, bool arg_is_null, bool *result_is_null)
1007{
1008#ifdef USE_LIBXML
1011
1014 (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
1015 errmsg("invalid XML processing instruction"),
1016 errdetail("XML processing instruction target name cannot be \"%s\".", target)));
1017
1018
1019
1020
1021
1022 *result_is_null = arg_is_null;
1023 if (*result_is_null)
1024 return NULL;
1025
1027
1029
1030 if (arg != NULL)
1031 {
1033
1035 if (strstr(string, "?>") != NULL)
1037 (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
1038 errmsg("invalid XML processing instruction"),
1039 errdetail("XML processing instruction cannot contain \"?>\".")));
1040
1044 }
1046
1049 return result;
1050#else
1052 return NULL;
1053#endif
1054}
1055
1056
1059{
1060#ifdef USE_LIBXML
1061 char *str;
1062 size_t len;
1063 xmlChar *orig_version;
1064 int orig_standalone;
1066
1069
1070 parse_xml_decl((xmlChar *) str, &len, &orig_version, NULL, &orig_standalone);
1071
1072 if (version)
1073 orig_version = xml_text2xmlChar(version);
1074 else
1075 orig_version = NULL;
1076
1077 switch (standalone)
1078 {
1080 orig_standalone = 1;
1081 break;
1083 orig_standalone = 0;
1084 break;
1086 orig_standalone = -1;
1087 break;
1089
1090 break;
1091 }
1092
1094 print_xml_decl(&buf, orig_version, 0, orig_standalone);
1096
1098#else
1100 return NULL;
1101#endif
1102}
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1115{
1117 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1118 errmsg("xmlvalidate is not implemented")));
1119 return 0;
1120}
1121
1122
1123bool
1125{
1126#ifdef USE_LIBXML
1127 xmlDocPtr doc;
1129
1130
1131
1132
1135 if (doc)
1136 xmlFreeDoc(doc);
1137
1139#else
1141 return false;
1142#endif
1143}
1144
1145
1146#ifdef USE_LIBXML
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159void
1161{
1162 static bool first_time = true;
1163
1164 if (first_time)
1165 {
1166
1167
1168
1169
1170
1171
1172 if (sizeof(char) != sizeof(xmlChar))
1174 (errmsg("could not initialize XML library"),
1175 errdetail("libxml2 has incompatible char type: sizeof(char)=%zu, sizeof(xmlChar)=%zu.",
1176 sizeof(char), sizeof(xmlChar))));
1177
1178#ifdef USE_LIBXMLCONTEXT
1179
1180 xml_memory_init();
1181#endif
1182
1183
1184 LIBXML_TEST_VERSION;
1185
1186 first_time = false;
1187 }
1188}
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1207{
1209 void *new_errcxt;
1210
1211
1213
1214
1216 errcxt->magic = ERRCXT_MAGIC;
1217 errcxt->strictness = strictness;
1218 errcxt->err_occurred = false;
1220
1221
1222
1223
1224
1225
1226
1227
1228 errcxt->saved_errfunc = xmlStructuredError;
1229
1230#ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
1231 errcxt->saved_errcxt = xmlStructuredErrorContext;
1232#else
1233 errcxt->saved_errcxt = xmlGenericErrorContext;
1234#endif
1235
1236 xmlSetStructuredErrorFunc(errcxt, xml_errorHandler);
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252#ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
1253 new_errcxt = xmlStructuredErrorContext;
1254#else
1255 new_errcxt = xmlGenericErrorContext;
1256#endif
1257
1258 if (new_errcxt != errcxt)
1260 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1261 errmsg("could not set up XML error handler"),
1262 errhint("This probably indicates that the version of libxml2"
1263 " being used is not compatible with the libxml2"
1264 " header files that PostgreSQL was built with.")));
1265
1266
1267
1268
1269
1270 errcxt->saved_entityfunc = xmlGetExternalEntityLoader();
1271 xmlSetExternalEntityLoader(xmlPgEntityLoader);
1272
1273 return errcxt;
1274}
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286void
1288{
1289 void *cur_errcxt;
1290
1291
1292 Assert(errcxt->magic == ERRCXT_MAGIC);
1293
1294
1295
1296
1297
1298
1299 Assert(!errcxt->err_occurred || isError);
1300
1301
1302
1303
1304
1305
1306#ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
1307 cur_errcxt = xmlStructuredErrorContext;
1308#else
1309 cur_errcxt = xmlGenericErrorContext;
1310#endif
1311
1312 if (cur_errcxt != errcxt)
1313 elog(WARNING, "libxml error handling state is out of sync with xml.c");
1314
1315
1316 xmlSetStructuredErrorFunc(errcxt->saved_errcxt, errcxt->saved_errfunc);
1317 xmlSetExternalEntityLoader(errcxt->saved_entityfunc);
1318
1319
1320
1321
1322
1323 errcxt->magic = 0;
1324
1325
1326 pfree(errcxt->err_buf.data);
1328}
1329
1330
1331
1332
1333
1334bool
1336{
1337 return errcxt->err_occurred;
1338}
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350#define CHECK_XML_SPACE(p) \
1351 do { \
1352 if (!xmlIsBlank_ch(*(p))) \
1353 return XML_ERR_SPACE_REQUIRED; \
1354 } while (0)
1355
1356#define SKIP_XML_SPACE(p) \
1357 while (xmlIsBlank_ch(*(p))) (p)++
1358
1359
1360
1361#define PG_XMLISNAMECHAR(c) \
1362 (xmlIsBaseChar_ch(c) || xmlIsIdeographicQ(c) \
1363 || xmlIsDigit_ch(c) \
1364 || c == '.' || c == '-' || c == '_' || c == ':' \
1365 || xmlIsCombiningQ(c) \
1366 || xmlIsExtender_ch(c))
1367
1368
1369static xmlChar *
1370xml_pnstrdup(const xmlChar *str, size_t len)
1371{
1372 xmlChar *result;
1373
1374 result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));
1375 memcpy(result, str, len * sizeof(xmlChar));
1376 result[len] = 0;
1377 return result;
1378}
1379
1380
1381static xmlChar *
1382pg_xmlCharStrndup(const char *str, size_t len)
1383{
1384 xmlChar *result;
1385
1386 result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));
1387 memcpy(result, str, len);
1388 result[len] = '\0';
1389
1390 return result;
1391}
1392
1393
1394
1395
1396
1397
1398static char *
1399xml_pstrdup_and_free(xmlChar *str)
1400{
1401 char *result;
1402
1403 if (str)
1404 {
1406 {
1408 }
1410 {
1411 xmlFree(str);
1412 }
1414 }
1415 else
1416 result = NULL;
1417
1418 return result;
1419}
1420
1421
1422
1423
1424
1425
1426
1427static int
1428parse_xml_decl(const xmlChar *str, size_t *lenp,
1429 xmlChar **version, xmlChar **encoding, int *standalone)
1430{
1431 const xmlChar *p;
1432 const xmlChar *save_p;
1433 size_t len;
1434 int utf8char;
1435 int utf8len;
1436
1437
1438
1439
1440
1441
1442
1444
1445
1446 if (version)
1447 *version = NULL;
1450 if (standalone)
1451 *standalone = -1;
1452
1453 p = str;
1454
1455 if (xmlStrncmp(p, (xmlChar *) "<?xml", 5) != 0)
1456 goto finished;
1457
1458
1459
1460
1461
1462
1463
1464
1465
1467 utf8char = xmlGetUTF8Char(p + 5, &utf8len);
1468 if (PG_XMLISNAMECHAR(utf8char))
1469 goto finished;
1470
1471 p += 5;
1472
1473
1474 CHECK_XML_SPACE(p);
1475 SKIP_XML_SPACE(p);
1476 if (xmlStrncmp(p, (xmlChar *) "version", 7) != 0)
1477 return XML_ERR_VERSION_MISSING;
1478 p += 7;
1479 SKIP_XML_SPACE(p);
1480 if (*p != '=')
1481 return XML_ERR_VERSION_MISSING;
1482 p += 1;
1483 SKIP_XML_SPACE(p);
1484
1485 if (*p == '\'' || *p == '"')
1486 {
1487 const xmlChar *q;
1488
1489 q = xmlStrchr(p + 1, *p);
1490 if (!q)
1491 return XML_ERR_VERSION_MISSING;
1492
1493 if (version)
1494 *version = xml_pnstrdup(p + 1, q - p - 1);
1495 p = q + 1;
1496 }
1497 else
1498 return XML_ERR_VERSION_MISSING;
1499
1500
1501 save_p = p;
1502 SKIP_XML_SPACE(p);
1503 if (xmlStrncmp(p, (xmlChar *) "encoding", 8) == 0)
1504 {
1505 CHECK_XML_SPACE(save_p);
1506 p += 8;
1507 SKIP_XML_SPACE(p);
1508 if (*p != '=')
1509 return XML_ERR_MISSING_ENCODING;
1510 p += 1;
1511 SKIP_XML_SPACE(p);
1512
1513 if (*p == '\'' || *p == '"')
1514 {
1515 const xmlChar *q;
1516
1517 q = xmlStrchr(p + 1, *p);
1518 if (!q)
1519 return XML_ERR_MISSING_ENCODING;
1520
1522 *encoding = xml_pnstrdup(p + 1, q - p - 1);
1523 p = q + 1;
1524 }
1525 else
1526 return XML_ERR_MISSING_ENCODING;
1527 }
1528 else
1529 {
1530 p = save_p;
1531 }
1532
1533
1534 save_p = p;
1535 SKIP_XML_SPACE(p);
1536 if (xmlStrncmp(p, (xmlChar *) "standalone", 10) == 0)
1537 {
1538 CHECK_XML_SPACE(save_p);
1539 p += 10;
1540 SKIP_XML_SPACE(p);
1541 if (*p != '=')
1542 return XML_ERR_STANDALONE_VALUE;
1543 p += 1;
1544 SKIP_XML_SPACE(p);
1545 if (xmlStrncmp(p, (xmlChar *) "'yes'", 5) == 0 ||
1546 xmlStrncmp(p, (xmlChar *) "\"yes\"", 5) == 0)
1547 {
1548 if (standalone)
1549 *standalone = 1;
1550 p += 5;
1551 }
1552 else if (xmlStrncmp(p, (xmlChar *) "'no'", 4) == 0 ||
1553 xmlStrncmp(p, (xmlChar *) "\"no\"", 4) == 0)
1554 {
1555 if (standalone)
1556 *standalone = 0;
1557 p += 4;
1558 }
1559 else
1560 return XML_ERR_STANDALONE_VALUE;
1561 }
1562 else
1563 {
1564 p = save_p;
1565 }
1566
1567 SKIP_XML_SPACE(p);
1568 if (xmlStrncmp(p, (xmlChar *) "?>", 2) != 0)
1569 return XML_ERR_XMLDECL_NOT_FINISHED;
1570 p += 2;
1571
1572finished:
1574
1575 for (p = str; p < str + len; p++)
1576 if (*p > 127)
1577 return XML_ERR_INVALID_CHAR;
1578
1579 if (lenp)
1580 *lenp = len;
1581
1582 return XML_ERR_OK;
1583}
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600static bool
1601print_xml_decl(StringInfo buf, const xmlChar *version,
1603{
1606 || standalone != -1)
1607 {
1609
1610 if (version)
1612 else
1614
1616 {
1617
1618
1619
1620
1623 }
1624
1625 if (standalone == 1)
1627 else if (standalone == 0)
1630
1631 return true;
1632 }
1633 else
1634 return false;
1635}
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666static bool
1667xml_doctype_in_content(const xmlChar *str)
1668{
1669 const xmlChar *p = str;
1670
1671 for (;;)
1672 {
1673 const xmlChar *e;
1674
1675 SKIP_XML_SPACE(p);
1676 if (*p != '<')
1677 return false;
1678 p++;
1679
1680 if (*p == '!')
1681 {
1682 p++;
1683
1684
1685 if (xmlStrncmp(p, (xmlChar *) "DOCTYPE", 7) == 0)
1686 return true;
1687
1688
1689 if (xmlStrncmp(p, (xmlChar *) "--", 2) != 0)
1690 return false;
1691
1692 p = xmlStrstr(p + 2, (xmlChar *) "--");
1693 if (!p || p[2] != '>')
1694 return false;
1695
1696 p += 3;
1697 continue;
1698 }
1699
1700
1701 if (*p != '?')
1702 return false;
1703 p++;
1704
1705
1706 e = xmlStrstr(p, (xmlChar *) "?>");
1707 if ()
1708 return false;
1709
1710
1711 p = e + 2;
1712 }
1713}
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742static xmlDocPtr
1744 bool preserve_whitespace, int encoding,
1745 XmlOptionType *parsed_xmloptiontype, xmlNodePtr *parsed_nodes,
1746 Node *escontext)
1747{
1750 xmlChar *utf8string;
1752 volatile xmlParserCtxtPtr ctxt = NULL;
1753 volatile xmlDocPtr doc = NULL;
1754
1755
1756
1757
1758
1760 string = xml_text2xmlChar(data);
1761
1762
1763
1764
1765
1766
1767
1768
1773
1774
1776
1777
1779 {
1780 bool parse_as_document = false;
1782 int res_code;
1783 size_t count = 0;
1784 xmlChar *version = NULL;
1785 int standalone = 0;
1786
1787
1788 xmlInitParser();
1789
1790
1792 parse_as_document = true;
1793 else
1794 {
1795
1796 res_code = parse_xml_decl(utf8string,
1797 &count, &version, NULL, &standalone);
1798 if (res_code != 0)
1799 {
1801 errcode(ERRCODE_INVALID_XML_CONTENT),
1802 errmsg_internal("invalid XML content: invalid XML declaration"),
1803 errdetail_for_xml_code(res_code));
1804 goto fail;
1805 }
1806
1807
1808 if (xml_doctype_in_content(utf8string + count))
1809 parse_as_document = true;
1810 }
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821 options = XML_PARSE_NOENT | XML_PARSE_DTDATTR
1822 | (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS);
1823
1824
1825 if (parsed_xmloptiontype != NULL)
1828 if (parsed_nodes != NULL)
1829 *parsed_nodes = NULL;
1830
1831 if (parse_as_document)
1832 {
1833 ctxt = xmlNewParserCtxt();
1834 if (ctxt == NULL || xmlerrcxt->err_occurred)
1836 "could not allocate parser context");
1837
1838 doc = xmlCtxtReadDoc(ctxt, utf8string,
1839 NULL,
1840 "UTF-8",
1842
1843 if (doc == NULL || xmlerrcxt->err_occurred)
1844 {
1845
1847 xml_errsave(escontext, xmlerrcxt,
1848 ERRCODE_INVALID_XML_DOCUMENT,
1849 "invalid XML document");
1850 else
1851 xml_errsave(escontext, xmlerrcxt,
1852 ERRCODE_INVALID_XML_CONTENT,
1853 "invalid XML content");
1854 goto fail;
1855 }
1856 }
1857 else
1858 {
1859 xmlNodePtr root;
1861
1862
1863 doc = xmlNewDoc(version);
1864 if (doc == NULL || xmlerrcxt->err_occurred)
1866 "could not allocate XML document");
1867
1868 Assert(doc->encoding == NULL);
1869 doc->encoding = xmlStrdup((const xmlChar *) "UTF-8");
1870 if (doc->encoding == NULL || xmlerrcxt->err_occurred)
1872 "could not allocate XML document");
1873 doc->standalone = standalone;
1874
1875 root = xmlNewNode(NULL, (const xmlChar *) "content-root");
1876 if (root == NULL || xmlerrcxt->err_occurred)
1878 "could not allocate xml node");
1879
1880
1881
1882
1883
1884 oldroot = xmlDocSetRootElement(doc, root);
1885 Assert(oldroot == NULL);
1886
1887
1888 if (*(utf8string + count))
1889 {
1890 xmlNodePtr node_list = NULL;
1891 xmlParserErrors res;
1892
1893 res = xmlParseInNodeContext(root,
1894 (char *) utf8string + count,
1895 strlen((char *) utf8string + count),
1897 &node_list);
1898
1899 if (res != XML_ERR_OK || xmlerrcxt->err_occurred)
1900 {
1901 xmlFreeNodeList(node_list);
1902 xml_errsave(escontext, xmlerrcxt,
1903 ERRCODE_INVALID_XML_CONTENT,
1904 "invalid XML content");
1905 goto fail;
1906 }
1907
1908 if (parsed_nodes != NULL)
1909 *parsed_nodes = node_list;
1910 else
1911 xmlFreeNodeList(node_list);
1912 }
1913 }
1914
1915fail:
1916 ;
1917 }
1919 {
1920 if (doc != NULL)
1921 xmlFreeDoc(doc);
1922 if (ctxt != NULL)
1923 xmlFreeParserCtxt(ctxt);
1924
1926
1928 }
1930
1931 if (ctxt != NULL)
1932 xmlFreeParserCtxt(ctxt);
1933
1935
1936 return doc;
1937}
1938
1939
1940
1941
1942
1943static xmlChar *
1944xml_text2xmlChar(text *in)
1945{
1947}
1948
1949
1950#ifdef USE_LIBXMLCONTEXT
1951
1952
1953
1954
1955
1956static void
1957xml_memory_init(void)
1958{
1959
1960 if (LibxmlContext == NULL)
1962 "Libxml context",
1964
1965
1966 xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
1967}
1968
1969
1970
1971
1972static void *
1973xml_palloc(size_t size)
1974{
1976}
1977
1978
1979static void *
1980xml_repalloc(void *ptr, size_t size)
1981{
1983}
1984
1985
1986static void
1987xml_pfree(void *ptr)
1988{
1989
1990 if (ptr)
1992}
1993
1994
1995static char *
1996xml_pstrdup(const char *string)
1997{
1999}
2000#endif
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014static xmlParserInputPtr
2015xmlPgEntityLoader(const char *URL, const char *ID,
2016 xmlParserCtxtPtr ctxt)
2017{
2018 return xmlNewStringInputStream(ctxt, (const xmlChar *) "");
2019}
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032void
2034{
2035 char *detail;
2036
2037
2038 if (errcxt->magic != ERRCXT_MAGIC)
2039 elog(ERROR, "xml_ereport called with invalid PgXmlErrorContext");
2040
2041
2042 errcxt->err_occurred = false;
2043
2044
2045 if (errcxt->err_buf.len > 0)
2046 detail = errcxt->err_buf.data;
2047 else
2048 detail = NULL;
2049
2054}
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069static void
2071 int sqlcode, const char *msg)
2072{
2073 char *detail;
2074
2075
2076 if (errcxt->magic != ERRCXT_MAGIC)
2077 elog(ERROR, "xml_errsave called with invalid PgXmlErrorContext");
2078
2079
2080 errcxt->err_occurred = false;
2081
2082
2083 if (errcxt->err_buf.len > 0)
2084 detail = errcxt->err_buf.data;
2085 else
2086 detail = NULL;
2087
2092}
2093
2094
2095
2096
2097
2098static void
2099xml_errorHandler(void *data, PgXmlErrorPtr error)
2100{
2102 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) error->ctxt;
2103 xmlParserInputPtr input = (ctxt != NULL) ? ctxt->input : NULL;
2104 xmlNodePtr node = error->node;
2105 const xmlChar *name = (node != NULL &&
2106 node->type == XML_ELEMENT_NODE) ? node->name : NULL;
2107 int domain = error->domain;
2108 int level = error->level;
2110
2111
2112
2113
2114
2115
2116
2117 if (xmlerrcxt->magic != ERRCXT_MAGIC)
2118 elog(FATAL, "xml_errorHandler called with invalid PgXmlErrorContext");
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128 switch (error->code)
2129 {
2130 case XML_WAR_NS_URI:
2131 level = XML_ERR_ERROR;
2132 domain = XML_FROM_NAMESPACE;
2133 break;
2134
2135 case XML_ERR_NS_DECL_ERROR:
2136 case XML_WAR_NS_URI_RELATIVE:
2137 case XML_WAR_NS_COLUMN:
2138 case XML_NS_ERR_XML_NAMESPACE:
2139 case XML_NS_ERR_UNDEFINED_NAMESPACE:
2140 case XML_NS_ERR_QNAME:
2141 case XML_NS_ERR_ATTRIBUTE_REDEFINED:
2142 case XML_NS_ERR_EMPTY:
2143 domain = XML_FROM_NAMESPACE;
2144 break;
2145 }
2146
2147
2148 switch (domain)
2149 {
2150 case XML_FROM_PARSER:
2151
2152
2153
2154
2155
2156
2157
2158
2159 if (error->code == XML_ERR_NOT_WELL_BALANCED &&
2160 xmlerrcxt->err_occurred)
2161 return;
2162
2163
2164 case XML_FROM_NONE:
2165 case XML_FROM_MEMORY:
2166 case XML_FROM_IO:
2167
2168
2169
2170
2171
2172 if (error->code == XML_WAR_UNDECLARED_ENTITY)
2173 return;
2174
2175
2176 break;
2177
2178 default:
2179
2181 return;
2182 break;
2183 }
2184
2185
2187
2188 if (error->line > 0)
2190 if (name != NULL)
2192 if (error->message != NULL)
2194 else
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208 if (input != NULL)
2209 {
2210 xmlGenericErrorFunc errFuncSaved = xmlGenericError;
2211 void *errCtxSaved = xmlGenericErrorContext;
2212
2213 xmlSetGenericErrorFunc(errorBuf,
2215
2216
2217 appendStringInfoLineSeparator(errorBuf);
2218
2219 xmlParserPrintFileContext(input);
2220
2221
2222 xmlSetGenericErrorFunc(errCtxSaved, errFuncSaved);
2223 }
2224
2225
2226 chopStringInfoNewlines(errorBuf);
2227
2228
2229
2230
2231
2232
2233
2234
2235
2237 {
2238 appendStringInfoLineSeparator(&xmlerrcxt->err_buf);
2240 errorBuf->len);
2241
2243 return;
2244 }
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254 if (level >= XML_ERR_ERROR)
2255 {
2256 appendStringInfoLineSeparator(&xmlerrcxt->err_buf);
2258 errorBuf->len);
2259
2260 xmlerrcxt->err_occurred = true;
2261 }
2262 else if (level >= XML_ERR_WARNING)
2263 {
2266 }
2267 else
2268 {
2271 }
2272
2274}
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286static int
2287errdetail_for_xml_code(int code)
2288{
2289 const char *det;
2290
2291 switch (code)
2292 {
2293 case XML_ERR_INVALID_CHAR:
2294 det = gettext_noop("Invalid character value.");
2295 break;
2296 case XML_ERR_SPACE_REQUIRED:
2298 break;
2299 case XML_ERR_STANDALONE_VALUE:
2300 det = gettext_noop("standalone accepts only 'yes' or 'no'.");
2301 break;
2302 case XML_ERR_VERSION_MISSING:
2303 det = gettext_noop("Malformed declaration: missing version.");
2304 break;
2305 case XML_ERR_MISSING_ENCODING:
2306 det = gettext_noop("Missing encoding in text declaration.");
2307 break;
2308 case XML_ERR_XMLDECL_NOT_FINISHED:
2309 det = gettext_noop("Parsing XML declaration: '?>' expected.");
2310 break;
2311 default:
2312 det = gettext_noop("Unrecognized libxml error code: %d.");
2313 break;
2314 }
2315
2317}
2318
2319
2320
2321
2322
2323static void
2325{
2326 while (str->len > 0 && str->data[str->len - 1] == '\n')
2327 str->data[--str->len] = '\0';
2328}
2329
2330
2331
2332
2333
2334static void
2336{
2337 chopStringInfoNewlines(str);
2338 if (str->len > 0)
2340}
2341
2342
2343
2344
2345
2347sqlchar_to_unicode(const char *s)
2348{
2349 char *utf8string;
2350 pg_wchar ret[2];
2351
2352
2354
2357
2358 if (utf8string != s)
2359 pfree(utf8string);
2360
2361 return ret[0];
2362}
2363
2364
2365static bool
2366is_valid_xml_namefirst(pg_wchar c)
2367{
2368
2369 return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)
2370 || c == '_' || c == ':');
2371}
2372
2373
2374static bool
2375is_valid_xml_namechar(pg_wchar c)
2376{
2377
2378 return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)
2379 || xmlIsDigitQ(c)
2380 || c == '.' || c == '-' || c == '_' || c == ':'
2381 || xmlIsCombiningQ(c)
2382 || xmlIsExtenderQ(c));
2383}
2384#endif
2385
2386
2387
2388
2389
2390char *
2392 bool escape_period)
2393{
2394#ifdef USE_LIBXML
2396 const char *p;
2397
2398
2399
2400
2401
2402 Assert(fully_escaped || !escape_period);
2403
2405
2407 {
2408 if (*p == ':' && (p == ident || fully_escaped))
2410 else if (*p == '_' && *(p + 1) == 'x')
2412 else if (fully_escaped && p == ident &&
2414 {
2415 if (*p == 'x')
2417 else
2419 }
2420 else if (escape_period && *p == '.')
2422 else
2423 {
2424 pg_wchar u = sqlchar_to_unicode(p);
2425
2426 if ((p == ident)
2427 ? !is_valid_xml_namefirst(u)
2428 : !is_valid_xml_namechar(u))
2430 else
2432 }
2433 }
2434
2435 return buf.data;
2436#else
2438 return NULL;
2439#endif
2440}
2441
2442
2443
2444
2445
2446char *
2448{
2450 const char *p;
2451
2453
2455 {
2456 if (*p == '_' && *(p + 1) == 'x'
2457 && isxdigit((unsigned char) *(p + 2))
2458 && isxdigit((unsigned char) *(p + 3))
2459 && isxdigit((unsigned char) *(p + 4))
2460 && isxdigit((unsigned char) *(p + 5))
2461 && *(p + 6) == '_')
2462 {
2464 unsigned int u;
2465
2466 sscanf(p + 2, "%X", &u);
2469 p += 6;
2470 }
2471 else
2473 }
2474
2475 return buf.data;
2476}
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488char *
2490{
2492 {
2494 Oid elmtype;
2496 bool elmbyval;
2497 char elmalign;
2498 int num_elems;
2499 Datum *elem_values;
2500 bool *elem_nulls;
2502 int i;
2503
2507
2509 elmlen, elmbyval, elmalign,
2510 &elem_values, &elem_nulls,
2511 &num_elems);
2512
2514
2515 for (i = 0; i < num_elems; i++)
2516 {
2517 if (elem_nulls[i])
2518 continue;
2522 elmtype, true));
2524 }
2525
2526 pfree(elem_values);
2527 pfree(elem_nulls);
2528
2529 return buf.data;
2530 }
2531 else
2532 {
2533 Oid typeOut;
2534 bool isvarlena;
2535 char *str;
2536
2537
2538
2539
2540
2542
2543
2544
2545
2546 switch (type)
2547 {
2548 case BOOLOID:
2550 return "true";
2551 else
2552 return "false";
2553
2554 case DATEOID:
2555 {
2559
2561
2564 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2565 errmsg("date out of range"),
2566 errdetail("XML does not support infinite date values.")));
2570
2572 }
2573
2574 case TIMESTAMPOID:
2575 {
2580
2582
2583
2586 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2587 errmsg("timestamp out of range"),
2588 errdetail("XML does not support infinite timestamp values.")));
2591 else
2593 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2594 errmsg("timestamp out of range")));
2595
2597 }
2598
2599 case TIMESTAMPTZOID:
2600 {
2603 int tz;
2605 const char *tzn = NULL;
2607
2609
2610
2613 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2614 errmsg("timestamp out of range"),
2615 errdetail("XML does not support infinite timestamp values.")));
2618 else
2620 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2621 errmsg("timestamp out of range")));
2622
2624 }
2625
2626#ifdef USE_LIBXML
2627 case BYTEAOID:
2628 {
2631 volatile xmlBufferPtr buf = NULL;
2632 volatile xmlTextWriterPtr writer = NULL;
2633 char *result;
2634
2636
2638 {
2639 buf = xmlBufferCreate();
2640 if (buf == NULL || xmlerrcxt->err_occurred)
2642 "could not allocate xmlBuffer");
2643 writer = xmlNewTextWriterMemory(buf, 0);
2644 if (writer == NULL || xmlerrcxt->err_occurred)
2646 "could not allocate xmlTextWriter");
2647
2649 xmlTextWriterWriteBase64(writer, VARDATA_ANY(bstr),
2651 else
2652 xmlTextWriterWriteBinHex(writer, VARDATA_ANY(bstr),
2654
2655
2656 xmlFreeTextWriter(writer);
2657 writer = NULL;
2658
2659 result = pstrdup((const char *) xmlBufferContent(buf));
2660 }
2662 {
2663 if (writer)
2664 xmlFreeTextWriter(writer);
2665 if (buf)
2666 xmlBufferFree(buf);
2667
2669
2671 }
2673
2674 xmlBufferFree(buf);
2675
2677
2678 return result;
2679 }
2680#endif
2681
2682 }
2683
2684
2685
2686
2689
2690
2691 if (type == XMLOID || !xml_escape_strings)
2692 return str;
2693
2694
2696 }
2697}
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707char *
2709{
2711 const char *p;
2712
2714 for (p = str; *p; p++)
2715 {
2716 switch (*p)
2717 {
2718 case '&':
2720 break;
2721 case '<':
2723 break;
2724 case '>':
2726 break;
2727 case '\r':
2729 break;
2730 default:
2732 break;
2733 }
2734 }
2735 return buf.data;
2736}
2737
2738
2739static char *
2741{
2742 size_t len = strlen(s) + 1;
2744
2745 memcpy(ret, s, len);
2746 return ret;
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
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796static List *
2798{
2801 int spi_result;
2802
2803 spi_result = SPI_execute(query, true, 0);
2805 elog(ERROR, "SPI_execute returned %s for %s",
2807
2809 {
2811 bool isnull;
2812
2815 1,
2816 &isnull);
2817 if (!isnull)
2819 }
2820
2821 return list;
2822}
2823
2824
2825static List *
2827{
2829
2831 appendStringInfo(&query, "SELECT oid FROM pg_catalog.pg_class"
2832 " WHERE relnamespace = %u AND relkind IN ("
2836 " AND pg_catalog.has_table_privilege (oid, 'SELECT')"
2837 " ORDER BY relname;", nspid);
2838
2840}
2841
2842
2843
2844
2845
2846
2847#define XML_VISIBLE_SCHEMAS_EXCLUDE "(nspname ~ '^pg_' OR nspname = 'information_schema')"
2848
2849#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
2850
2851
2852static List *
2854{
2856}
2857
2858
2859static List *
2861{
2862
2864 " WHERE relkind IN ("
2868 " AND pg_catalog.has_table_privilege(pg_class.oid, 'SELECT')"
2870}
2871
2872
2873
2874
2875
2876
2877
2880 const char *xmlschema, bool nulls, bool tableforest,
2881 const char *targetns, bool top_level)
2882{
2884
2890 xmlschema, nulls, tableforest,
2891 targetns, top_level);
2892}
2893
2894
2897{
2902
2904 nulls, tableforest,
2905 targetns, true)));
2906}
2907
2908
2911{
2916
2918 NULL, nulls, tableforest,
2919 targetns, true)));
2920}
2921
2922
2925{
2931
2935
2937
2938 if (!tableforest)
2939 {
2942 }
2943
2946 if (portal == NULL)
2948 (errcode(ERRCODE_UNDEFINED_CURSOR),
2949 errmsg("cursor \"%s\" does not exist", name)));
2950
2954 tableforest, targetns, true);
2955
2957
2958 if (!tableforest)
2960
2962}
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977static void
2979 const char *xmlschema, const char *targetns,
2980 bool top_level)
2981{
2982
2983 Assert(top_level || !xmlschema);
2984
2986 if (top_level)
2987 {
2989 if (strlen(targetns) > 0)
2991 }
2992 if (xmlschema)
2993 {
2994
2995 if (strlen(targetns) > 0)
2996 appendStringInfo(result, " xsi:schemaLocation=\"%s #\"", targetns);
2997 else
2999 }
3001}
3002
3003
3004static void
3006{
3008}
3009
3010
3013 const char *xmlschema, bool nulls, bool tableforest,
3014 const char *targetns, bool top_level)
3015{
3017 char *xmltn;
3019
3020 if (tablename)
3022 else
3023 xmltn = "table";
3024
3026
3030 (errcode(ERRCODE_DATA_EXCEPTION),
3031 errmsg("invalid query")));
3032
3033 if (!tableforest)
3034 {
3036 targetns, top_level);
3038 }
3039
3040 if (xmlschema)
3042
3045 tableforest, targetns, top_level);
3046
3047 if (!tableforest)
3049
3051
3052 return result;
3053}
3054
3055
3058{
3063 const char *result;
3065
3068 tableforest, targetns);
3070
3072}
3073
3074
3077{
3082 const char *result;
3085
3087
3089 elog(ERROR, "SPI_prepare(\"%s\") failed", query);
3090
3092 elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
3093
3096 tableforest, targetns));
3099
3101}
3102
3103
3106{
3111 const char *xmlschema;
3113
3116 if (portal == NULL)
3118 (errcode(ERRCODE_UNDEFINED_CURSOR),
3119 errmsg("cursor \"%s\" does not exist", name)));
3120 if (portal->tupDesc == NULL)
3122 (errcode(ERRCODE_INVALID_CURSOR_STATE),
3123 errmsg("portal \"%s\" does not return tuples", name)));
3124
3127 tableforest, targetns));
3129
3131}
3132
3133
3136{
3142 const char *xmlschema;
3143
3146 tableforest, targetns);
3148
3150 xmlschema, nulls, tableforest,
3151 targetns, true)));
3152}
3153
3154
3157{
3162
3163 const char *xmlschema;
3166
3168
3170 elog(ERROR, "SPI_prepare(\"%s\") failed", query);
3171
3173 elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
3174
3176 InvalidOid, nulls, tableforest, targetns));
3179
3181 xmlschema, nulls, tableforest,
3182 targetns, true)));
3183}
3184
3185
3186
3187
3188
3189
3190
3193 bool tableforest, const char *targetns, bool top_level)
3194{
3196 char *xmlsn;
3197 List *relid_list;
3199
3201 true, false);
3203
3206
3207 if (xmlschema)
3209
3211
3213
3214 foreach(cell, relid_list)
3215 {
3218
3220 targetns, false);
3221
3224 }
3225
3227
3229
3230 return result;
3231}
3232
3233
3236{
3241
3242 char *schemaname;
3244
3247
3249 nulls, tableforest, targetns, true)));
3250}
3251
3252
3253
3254
3255
3256static void
3258{
3260 "<xsd:schema\n"
3262 if (strlen(targetns) > 0)
3264 "\n"
3265 " targetNamespace=\"%s\"\n"
3266 " elementFormDefault=\"qualified\"",
3267 targetns);
3269 ">\n\n");
3270}
3271
3272
3273static void
3275{
3277}
3278
3279
3282 bool tableforest, const char *targetns)
3283{
3285 List *relid_list;
3286 List *tupdesc_list;
3289
3291
3293
3295
3297
3299
3300 tupdesc_list = NIL;
3301 foreach(cell, relid_list)
3302 {
3304
3308 }
3309
3312
3315 nulls, tableforest, targetns));
3316
3318
3320
3321 return result;
3322}
3323
3324
3327{
3332
3334 nulls, tableforest, targetns)));
3335}
3336
3337
3340{
3345 char *schemaname;
3348
3351
3353 tableforest, targetns);
3354
3356 xmlschema->data, nulls,
3357 tableforest, targetns, true)));
3358}
3359
3360
3361
3362
3363
3364
3365
3368 bool tableforest, const char *targetns)
3369{
3371 List *nspid_list;
3373 char *xmlcn;
3374
3376 true, false);
3378
3381
3382 if (xmlschema)
3384
3386
3388
3389 foreach(cell, nspid_list)
3390 {
3393
3395 tableforest, targetns, false);
3396
3399 }
3400
3402
3404
3405 return result;
3406}
3407
3408
3411{
3415
3417 tableforest, targetns)));
3418}
3419
3420
3423 const char *targetns)
3424{
3425 List *relid_list;
3426 List *nspid_list;
3427 List *tupdesc_list;
3430
3432
3434
3436
3439
3440 tupdesc_list = NIL;
3441 foreach(cell, relid_list)
3442 {
3444
3448 }
3449
3452
3455
3457
3459
3460 return result;
3461}
3462
3463
3466{
3470
3472 tableforest, targetns)));
3473}
3474
3475
3478{
3483
3485
3487 nulls, tableforest, targetns)));
3488}
3489
3490
3491
3492
3493
3494
3495static char *
3497{
3499
3501
3502 if (a)
3505 if (b)
3508 if (c)
3511 if (d)
3514
3515 return result.data;
3516}
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526static const char *
3528 bool tableforest, const char *targetns)
3529{
3530 int i;
3531 char *xmltn;
3532 char *tabletypename;
3533 char *rowtypename;
3535
3537
3539 {
3542
3545 elog(ERROR, "cache lookup failed for relation %u", relid);
3547
3549 true, false);
3550
3554 NameStr(reltuple->relname));
3555
3559 NameStr(reltuple->relname));
3560
3562 }
3563 else
3564 {
3565 if (tableforest)
3566 xmltn = "row";
3567 else
3568 xmltn = "table";
3569
3570 tabletypename = "TableType";
3571 rowtypename = "RowType";
3572 }
3573
3575
3578
3580 "<xsd:complexType name=\"%s\">\n"
3581 " xsd:sequence\n",
3582 rowtypename);
3583
3584 for (i = 0; i < tupdesc->natts; i++)
3585 {
3587
3588 if (att->attisdropped)
3589 continue;
3591 " <xsd:element name=\"%s\" type=\"%s\"%s>\n",
3593 true, false),
3595 nulls ? " nillable=\"true\"" : " minOccurs=\"0\"");
3596 }
3597
3599 " \n"
3600 "\n\n");
3601
3602 if (!tableforest)
3603 {
3605 "<xsd:complexType name=\"%s\">\n"
3606 " xsd:sequence\n"
3607 " <xsd:element name=\"row\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n"
3608 " \n"
3609 "\n\n",
3610 tabletypename, rowtypename);
3611
3613 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3614 xmltn, tabletypename);
3615 }
3616 else
3618 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3619 xmltn, rowtypename);
3620
3622
3623 return result.data;
3624}
3625
3626
3627
3628
3629
3630
3631static const char *
3633 bool tableforest, const char *targetns)
3634{
3636 char *nspname;
3637 char *xmlsn;
3638 char *schematypename;
3641
3644
3646
3648
3651 nspname,
3652 NULL);
3653
3655 "<xsd:complexType name=\"%s\">\n", schematypename);
3656 if (!tableforest)
3658 " xsd:all\n");
3659 else
3661 " xsd:sequence\n");
3662
3663 foreach(cell, relid_list)
3664 {
3670 nspname,
3672
3673 if (!tableforest)
3675 " <xsd:element name=\"%s\" type=\"%s\"/>\n",
3676 xmltn, tabletypename);
3677 else
3679 " <xsd:element name=\"%s\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n",
3680 xmltn, tabletypename);
3681 }
3682
3683 if (!tableforest)
3685 " \n");
3686 else
3688 " \n");
3690 "\n\n");
3691
3693 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3694 xmlsn, schematypename);
3695
3696 return result.data;
3697}
3698
3699
3700
3701
3702
3703
3704static const char *
3706 bool tableforest, const char *targetns)
3707{
3709 char *xmlcn;
3710 char *catalogtypename;
3713
3715
3717
3719
3722 NULL,
3723 NULL);
3724
3726 "<xsd:complexType name=\"%s\">\n", catalogtypename);
3728 " xsd:all\n");
3729
3730 foreach(cell, nspid_list)
3731 {
3737 nspname,
3738 NULL);
3739
3741 " <xsd:element name=\"%s\" type=\"%s\"/>\n",
3742 xmlsn, schematypename);
3743 }
3744
3746 " \n");
3748 "\n\n");
3749
3751 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
3752 xmlcn, catalogtypename);
3753
3754 return result.data;
3755}
3756
3757
3758
3759
3760
3761static const char *
3763{
3765
3767
3768 switch (typeoid)
3769 {
3770 case BPCHAROID:
3771 if (typmod == -1)
3773 else
3775 break;
3776 case VARCHAROID:
3777 if (typmod == -1)
3779 else
3781 break;
3782 case NUMERICOID:
3783 if (typmod == -1)
3785 else
3787 ((typmod - VARHDRSZ) >> 16) & 0xffff,
3788 (typmod - VARHDRSZ) & 0xffff);
3789 break;
3790 case INT4OID:
3792 break;
3793 case INT2OID:
3795 break;
3796 case INT8OID:
3798 break;
3799 case FLOAT4OID:
3801 break;
3802 case FLOAT8OID:
3804 break;
3805 case BOOLOID:
3807 break;
3808 case TIMEOID:
3809 if (typmod == -1)
3811 else
3813 break;
3814 case TIMETZOID:
3815 if (typmod == -1)
3817 else
3819 break;
3820 case TIMESTAMPOID:
3821 if (typmod == -1)
3823 else
3825 break;
3826 case TIMESTAMPTZOID:
3827 if (typmod == -1)
3829 else
3831 break;
3832 case DATEOID:
3834 break;
3835 case XMLOID:
3837 break;
3838 default:
3839 {
3842
3845 elog(ERROR, "cache lookup failed for type %u", typeoid);
3847
3852 NameStr(typtuple->typname)));
3853
3855 }
3856 }
3857
3858 return result.data;
3859}
3860
3861
3862
3863
3864
3865
3866static const char *
3868{
3870 int i;
3873
3874
3875 foreach(cell0, tupdesc_list)
3876 {
3878
3879 for (i = 0; i < tupdesc->natts; i++)
3880 {
3882
3883 if (att->attisdropped)
3884 continue;
3886 }
3887 }
3888
3889
3890 foreach(cell0, uniquetypes)
3891 {
3894
3895 if (basetypid != typid)
3897 }
3898
3899
3901
3902 foreach(cell0, uniquetypes)
3903 {
3906 -1));
3907 }
3908
3909 return result.data;
3910}
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921static const char *
3923{
3926
3928
3929 if (typeoid == XMLOID)
3930 {
3932 "<xsd:complexType mixed=\"true\">\n"
3933 " xsd:sequence\n"
3934 " <xsd:any name=\"element\" minOccurs=\"0\" maxOccurs=\"unbounded\" processContents=\"skip\"/>\n"
3935 " \n"
3936 "\n");
3937 }
3938 else
3939 {
3941 "<xsd:simpleType name=\"%s\">\n", typename);
3942
3943 switch (typeoid)
3944 {
3945 case BPCHAROID:
3946 case VARCHAROID:
3947 case TEXTOID:
3949 " <xsd:restriction base=\"xsd:string\">\n");
3950 if (typmod != -1)
3952 " <xsd:maxLength value=\"%d\"/>\n",
3955 break;
3956
3957 case BYTEAOID:
3959 " <xsd:restriction base=\"xsd:%s\">\n"
3960 " \n",
3962 break;
3963
3964 case NUMERICOID:
3965 if (typmod != -1)
3967 " <xsd:restriction base=\"xsd:decimal\">\n"
3968 " <xsd:totalDigits value=\"%d\"/>\n"
3969 " <xsd:fractionDigits value=\"%d\"/>\n"
3970 " \n",
3971 ((typmod - VARHDRSZ) >> 16) & 0xffff,
3972 (typmod - VARHDRSZ) & 0xffff);
3973 break;
3974
3975 case INT2OID:
3977 " <xsd:restriction base=\"xsd:short\">\n"
3978 " <xsd:maxInclusive value=\"%d\"/>\n"
3979 " <xsd:minInclusive value=\"%d\"/>\n"
3980 " \n",
3981 SHRT_MAX, SHRT_MIN);
3982 break;
3983
3984 case INT4OID:
3986 " <xsd:restriction base=\"xsd:int\">\n"
3987 " <xsd:maxInclusive value=\"%d\"/>\n"
3988 " <xsd:minInclusive value=\"%d\"/>\n"
3989 " \n",
3990 INT_MAX, INT_MIN);
3991 break;
3992
3993 case INT8OID:
3995 " <xsd:restriction base=\"xsd:long\">\n"
3996 " <xsd:maxInclusive value=\"" INT64_FORMAT "\"/>\n"
3997 " <xsd:minInclusive value=\"" INT64_FORMAT "\"/>\n"
3998 " \n",
4001 break;
4002
4003 case FLOAT4OID:
4005 " <xsd:restriction base=\"xsd:float\">\n");
4006 break;
4007
4008 case FLOAT8OID:
4010 " <xsd:restriction base=\"xsd:double\">\n");
4011 break;
4012
4013 case BOOLOID:
4015 " <xsd:restriction base=\"xsd:boolean\">\n");
4016 break;
4017
4018 case TIMEOID:
4019 case TIMETZOID:
4020 {
4021 const char *tz = (typeoid == TIMETZOID ? "(\\+|-)\\p{Nd}{2}:\\p{Nd}{2}" : "");
4022
4023 if (typmod == -1)
4025 " <xsd:restriction base=\"xsd:time\">\n"
4026 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}(.\\p{Nd}+)?%s\"/>\n"
4027 " \n", tz);
4028 else if (typmod == 0)
4030 " <xsd:restriction base=\"xsd:time\">\n"
4031 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"
4032 " \n", tz);
4033 else
4035 " <xsd:restriction base=\"xsd:time\">\n"
4036 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}.\\p{Nd}{%d}%s\"/>\n"
4037 " \n", typmod - VARHDRSZ, tz);
4038 break;
4039 }
4040
4041 case TIMESTAMPOID:
4042 case TIMESTAMPTZOID:
4043 {
4044 const char *tz = (typeoid == TIMESTAMPTZOID ? "(\\+|-)\\p{Nd}{2}:\\p{Nd}{2}" : "");
4045
4046 if (typmod == -1)
4048 " <xsd:restriction base=\"xsd:dateTime\">\n"
4049 " <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"
4050 " \n", tz);
4051 else if (typmod == 0)
4053 " <xsd:restriction base=\"xsd:dateTime\">\n"
4054 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"
4055 " \n", tz);
4056 else
4058 " <xsd:restriction base=\"xsd:dateTime\">\n"
4059 " <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"
4060 " \n", typmod - VARHDRSZ, tz);
4061 break;
4062 }
4063
4064 case DATEOID:
4066 " <xsd:restriction base=\"xsd:date\">\n"
4067 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}\"/>\n"
4068 " \n");
4069 break;
4070
4071 default:
4072 if (get_typtype(typeoid) == TYPTYPE_DOMAIN)
4073 {
4074 Oid base_typeoid;
4075 int32 base_typmod = -1;
4076
4078
4080 " <xsd:restriction base=\"%s\"/>\n",
4082 }
4083 break;
4084 }
4086 }
4087
4088 return result.data;
4089}
4090
4091
4092
4093
4094
4095
4096static void
4098 bool nulls, bool tableforest,
4099 const char *targetns, bool top_level)
4100{
4101 int i;
4102 char *xmltn;
4103
4104 if (tablename)
4106 else
4107 {
4108 if (tableforest)
4109 xmltn = "row";
4110 else
4111 xmltn = "table";
4112 }
4113
4114 if (tableforest)
4116 else
4118
4120 {
4121 char *colname;
4123 bool isnull;
4124
4126 true, false);
4129 i,
4130 &isnull);
4131 if (isnull)
4132 {
4133 if (nulls)
4134 appendStringInfo(result, " <%s xsi:nil=\"true\"/>\n", colname);
4135 }
4136 else
4138 colname,
4141 colname);
4142 }
4143
4144 if (tableforest)
4145 {
4148 }
4149 else
4151}
4152
4153
4154
4155
4156
4157
4158#ifdef USE_LIBXML
4159
4160
4161
4162
4163
4164
4165
4166static text *
4168{
4170
4171 if (cur->type != XML_ATTRIBUTE_NODE && cur->type != XML_TEXT_NODE)
4172 {
4173 void (*volatile nodefree) (xmlNodePtr) = NULL;
4174 volatile xmlBufferPtr buf = NULL;
4175 volatile xmlNodePtr cur_copy = NULL;
4176
4178 {
4179 int bytes;
4180
4181 buf = xmlBufferCreate();
4182 if (buf == NULL || xmlerrcxt->err_occurred)
4184 "could not allocate xmlBuffer");
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198 cur_copy = xmlCopyNode(cur, 1);
4199 if (cur_copy == NULL || xmlerrcxt->err_occurred)
4201 "could not copy node");
4202 nodefree = (cur_copy->type == XML_DOCUMENT_NODE) ?
4203 (void (*) (xmlNodePtr)) xmlFreeDoc : xmlFreeNode;
4204
4205 bytes = xmlNodeDump(buf, NULL, cur_copy, 0, 0);
4206 if (bytes == -1 || xmlerrcxt->err_occurred)
4208 "could not dump node");
4209
4210 result = xmlBuffer_to_xmltype(buf);
4211 }
4213 {
4214 if (nodefree)
4215 nodefree(cur_copy);
4216 if (buf)
4217 xmlBufferFree(buf);
4218 }
4220 }
4221 else
4222 {
4223 xmlChar *str;
4224
4225 str = xmlXPathCastNodeToString(cur);
4227 {
4228
4230
4233 }
4235 {
4236 xmlFree(str);
4237 }
4239 }
4240
4241 return result;
4242}
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256static int
4257xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
4260{
4261 int result = 0;
4263 Oid datumtype;
4264 char *result_str;
4265
4266 switch (xpathobj->type)
4267 {
4268 case XPATH_NODESET:
4269 if (xpathobj->nodesetval != NULL)
4270 {
4271 result = xpathobj->nodesetval->nodeNr;
4272 if (astate != NULL)
4273 {
4274 int i;
4275
4276 for (i = 0; i < result; i++)
4277 {
4278 datum = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],
4279 xmlerrcxt));
4282 }
4283 }
4284 }
4285 return result;
4286
4287 case XPATH_BOOLEAN:
4288 if (astate == NULL)
4289 return 1;
4291 datumtype = BOOLOID;
4292 break;
4293
4294 case XPATH_NUMBER:
4295 if (astate == NULL)
4296 return 1;
4298 datumtype = FLOAT8OID;
4299 break;
4300
4301 case XPATH_STRING:
4302 if (astate == NULL)
4303 return 1;
4305 datumtype = CSTRINGOID;
4306 break;
4307
4308 default:
4309 elog(ERROR, "xpath expression result type %d is unsupported",
4310 xpathobj->type);
4311 return 0;
4312 }
4313
4314
4319 return 1;
4320}
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334static void
4337{
4339 volatile xmlParserCtxtPtr ctxt = NULL;
4340 volatile xmlDocPtr doc = NULL;
4341 volatile xmlXPathContextPtr xpathctx = NULL;
4342 volatile xmlXPathCompExprPtr xpathcomp = NULL;
4343 volatile xmlXPathObjectPtr xpathobj = NULL;
4344 char *datastr;
4346 int32 xpath_len;
4348 xmlChar *xpath_expr;
4349 size_t xmldecl_len = 0;
4350 int i;
4351 int ndim;
4352 Datum *ns_names_uris;
4353 bool *ns_names_uris_nulls;
4354 int ns_count;
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365 ndim = namespaces ? ARR_NDIM(namespaces) : 0;
4366 if (ndim != 0)
4367 {
4368 int *dims;
4369
4370 dims = ARR_DIMS(namespaces);
4371
4372 if (ndim != 2 || dims[1] != 2)
4374 (errcode(ERRCODE_DATA_EXCEPTION),
4375 errmsg("invalid array for XML namespace mapping"),
4376 errdetail("The array must be two-dimensional with length of the second axis equal to 2.")));
4377
4379
4381 &ns_names_uris, &ns_names_uris_nulls,
4382 &ns_count);
4383
4384 Assert((ns_count % 2) == 0);
4385 ns_count /= 2;
4386 }
4387 else
4388 {
4389 ns_names_uris = NULL;
4390 ns_names_uris_nulls = NULL;
4391 ns_count = 0;
4392 }
4393
4397 if (xpath_len == 0)
4399 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),
4400 errmsg("empty XPath expression")));
4401
4402 string = pg_xmlCharStrndup(datastr, len);
4403 xpath_expr = pg_xmlCharStrndup(VARDATA_ANY(xpath_expr_text), xpath_len);
4404
4405
4406
4407
4408
4409
4410
4411
4413 parse_xml_decl(string, &xmldecl_len, NULL, NULL, NULL);
4414
4416
4418 {
4419 xmlInitParser();
4420
4421
4422
4423
4424
4425 ctxt = xmlNewParserCtxt();
4426 if (ctxt == NULL || xmlerrcxt->err_occurred)
4428 "could not allocate parser context");
4429 doc = xmlCtxtReadMemory(ctxt, (char *) string + xmldecl_len,
4430 len - xmldecl_len, NULL, NULL, 0);
4431 if (doc == NULL || xmlerrcxt->err_occurred)
4433 "could not parse XML document");
4434 xpathctx = xmlXPathNewContext(doc);
4435 if (xpathctx == NULL || xmlerrcxt->err_occurred)
4437 "could not allocate XPath context");
4438 xpathctx->node = (xmlNodePtr) doc;
4439
4440
4441 if (ns_count > 0)
4442 {
4443 for (i = 0; i < ns_count; i++)
4444 {
4445 char *ns_name;
4446 char *ns_uri;
4447
4448 if (ns_names_uris_nulls[i * 2] ||
4449 ns_names_uris_nulls[i * 2 + 1])
4451 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4452 errmsg("neither namespace name nor URI may be null")));
4455 if (xmlXPathRegisterNs(xpathctx,
4456 (xmlChar *) ns_name,
4457 (xmlChar *) ns_uri) != 0)
4459 (errmsg("could not register XML namespace with name \"%s\" and URI \"%s\"",
4460 ns_name, ns_uri)));
4461 }
4462 }
4463
4464
4465
4466
4467
4468
4469
4470 xpathcomp = xmlXPathCtxtCompile(xpathctx, xpath_expr);
4471 if (xpathcomp == NULL || xmlerrcxt->err_occurred)
4472 xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4473 "invalid XPath expression");
4474
4475
4476
4477
4478
4479
4480
4481
4482 xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
4483 if (xpathobj == NULL || xmlerrcxt->err_occurred)
4484 xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4485 "could not create XPath object");
4486
4487
4488
4489
4490 if (res_nitems != NULL)
4491 *res_nitems = xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);
4492 else
4493 (void) xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);
4494 }
4496 {
4497 if (xpathobj)
4498 xmlXPathFreeObject(xpathobj);
4499 if (xpathcomp)
4500 xmlXPathFreeCompExpr(xpathcomp);
4501 if (xpathctx)
4502 xmlXPathFreeContext(xpathctx);
4503 if (doc)
4504 xmlFreeDoc(doc);
4505 if (ctxt)
4506 xmlFreeParserCtxt(ctxt);
4507
4509
4511 }
4513
4514 xmlXPathFreeObject(xpathobj);
4515 xmlXPathFreeCompExpr(xpathcomp);
4516 xmlXPathFreeContext(xpathctx);
4517 xmlFreeDoc(doc);
4518 xmlFreeParserCtxt(ctxt);
4519
4521}
4522#endif
4523
4524
4525
4526
4527
4528
4529
4530
4533{
4534#ifdef USE_LIBXML
4539
4541 xpath_internal(xpath_expr_text, data, namespaces,
4542 NULL, astate);
4544#else
4546 return 0;
4547#endif
4548}
4549
4550
4551
4552
4553
4556{
4557#ifdef USE_LIBXML
4560 int res_nitems;
4561
4562 xpath_internal(xpath_expr_text, data, NULL,
4563 &res_nitems, NULL);
4564
4566#else
4568 return 0;
4569#endif
4570}
4571
4572
4573
4574
4575
4576
4579{
4580#ifdef USE_LIBXML
4584 int res_nitems;
4585
4586 xpath_internal(xpath_expr_text, data, namespaces,
4587 &res_nitems, NULL);
4588
4590#else
4592 return 0;
4593#endif
4594}
4595
4596
4597
4598
4599
4600#ifdef USE_LIBXML
4601static bool
4603{
4604 xmlDocPtr doc;
4606
4607
4608
4609
4610 doc = xml_parse(data, xmloption_arg, true,
4612 if (doc)
4613 xmlFreeDoc(doc);
4614
4616}
4617#endif
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
4647{
4648#ifdef USE_LIBXML
4650
4652#else
4654 return 0;
4655#endif
4656}
4657
4658
4659
4660
4661
4662#ifdef USE_LIBXML
4663
4664
4665
4666
4667
4668static inline XmlTableBuilderData *
4670{
4671 XmlTableBuilderData *result;
4672
4674 elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4675 result = (XmlTableBuilderData *) state->opaque;
4676 if (result->magic != XMLTABLE_CONTEXT_MAGIC)
4677 elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4678
4679 return result;
4680}
4681#endif
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694static void
4696{
4697#ifdef USE_LIBXML
4698 volatile xmlParserCtxtPtr ctxt = NULL;
4699 XmlTableBuilderData *xtCxt;
4701
4702 xtCxt = palloc0(sizeof(XmlTableBuilderData));
4703 xtCxt->magic = XMLTABLE_CONTEXT_MAGIC;
4704 xtCxt->natts = natts;
4705 xtCxt->xpathscomp = palloc0(sizeof(xmlXPathCompExprPtr) * natts);
4706
4708
4710 {
4711 xmlInitParser();
4712
4713 ctxt = xmlNewParserCtxt();
4714 if (ctxt == NULL || xmlerrcxt->err_occurred)
4716 "could not allocate parser context");
4717 }
4719 {
4720 if (ctxt != NULL)
4721 xmlFreeParserCtxt(ctxt);
4722
4724
4726 }
4728
4729 xtCxt->xmlerrcxt = xmlerrcxt;
4730 xtCxt->ctxt = ctxt;
4731
4732 state->opaque = xtCxt;
4733#else
4735#endif
4736}
4737
4738
4739
4740
4741
4742static void
4744{
4745#ifdef USE_LIBXML
4746 XmlTableBuilderData *xtCxt;
4748 char *str;
4749 xmlChar *xstr;
4750 int length;
4751 volatile xmlDocPtr doc = NULL;
4752 volatile xmlXPathContextPtr xpathcxt = NULL;
4753
4754 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetDocument");
4755
4756
4757
4758
4759
4761
4762 length = strlen(str);
4763 xstr = pg_xmlCharStrndup(str, length);
4764
4766 {
4767 doc = xmlCtxtReadMemory(xtCxt->ctxt, (char *) xstr, length, NULL, NULL, 0);
4768 if (doc == NULL || xtCxt->xmlerrcxt->err_occurred)
4769 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
4770 "could not parse XML document");
4771 xpathcxt = xmlXPathNewContext(doc);
4772 if (xpathcxt == NULL || xtCxt->xmlerrcxt->err_occurred)
4774 "could not allocate XPath context");
4775 xpathcxt->node = (xmlNodePtr) doc;
4776 }
4778 {
4779 if (xpathcxt != NULL)
4780 xmlXPathFreeContext(xpathcxt);
4781 if (doc != NULL)
4782 xmlFreeDoc(doc);
4783
4785 }
4787
4788 xtCxt->doc = doc;
4789 xtCxt->xpathcxt = xpathcxt;
4790#else
4792#endif
4793}
4794
4795
4796
4797
4798
4799static void
4801{
4802#ifdef USE_LIBXML
4803 XmlTableBuilderData *xtCxt;
4804
4805 if (name == NULL)
4807 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4808 errmsg("DEFAULT namespace is not supported")));
4809 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetNamespace");
4810
4811 if (xmlXPathRegisterNs(xtCxt->xpathcxt,
4812 pg_xmlCharStrndup(name, strlen(name)),
4813 pg_xmlCharStrndup(uri, strlen(uri))))
4814 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4815 "could not set XML namespace");
4816#else
4818#endif
4819}
4820
4821
4822
4823
4824
4825static void
4827{
4828#ifdef USE_LIBXML
4829 XmlTableBuilderData *xtCxt;
4830 xmlChar *xstr;
4831
4832 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetRowFilter");
4833
4834 if (*path == '\0')
4836 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),
4837 errmsg("row path filter must not be empty string")));
4838
4839 xstr = pg_xmlCharStrndup(path, strlen(path));
4840
4841
4842 Assert(xtCxt->xpathcxt != NULL);
4843
4844 xtCxt->xpathcomp = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);
4845 if (xtCxt->xpathcomp == NULL || xtCxt->xmlerrcxt->err_occurred)
4846 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4847 "invalid XPath expression");
4848#else
4850#endif
4851}
4852
4853
4854
4855
4856
4857static void
4859{
4860#ifdef USE_LIBXML
4861 XmlTableBuilderData *xtCxt;
4862 xmlChar *xstr;
4863
4865
4866 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetColumnFilter");
4867
4868 if (*path == '\0')
4870 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),
4871 errmsg("column path filter must not be empty string")));
4872
4873 xstr = pg_xmlCharStrndup(path, strlen(path));
4874
4875
4876 Assert(xtCxt->xpathcxt != NULL);
4877
4878 xtCxt->xpathscomp[colnum] = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);
4879 if (xtCxt->xpathscomp[colnum] == NULL || xtCxt->xmlerrcxt->err_occurred)
4880 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4881 "invalid XPath expression");
4882#else
4884#endif
4885}
4886
4887
4888
4889
4890
4891
4892static bool
4894{
4895#ifdef USE_LIBXML
4896 XmlTableBuilderData *xtCxt;
4897
4898 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableFetchRow");
4899
4900
4901 xmlSetStructuredErrorFunc(xtCxt->xmlerrcxt, xml_errorHandler);
4902
4903 if (xtCxt->xpathobj == NULL)
4904 {
4905 xtCxt->xpathobj = xmlXPathCompiledEval(xtCxt->xpathcomp, xtCxt->xpathcxt);
4906 if (xtCxt->xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)
4907 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4908 "could not create XPath object");
4909
4910 xtCxt->row_count = 0;
4911 }
4912
4913 if (xtCxt->xpathobj->type == XPATH_NODESET)
4914 {
4915 if (xtCxt->xpathobj->nodesetval != NULL)
4916 {
4917 if (xtCxt->row_count++ < xtCxt->xpathobj->nodesetval->nodeNr)
4918 return true;
4919 }
4920 }
4921
4922 return false;
4923#else
4925 return false;
4926#endif
4927}
4928
4929
4930
4931
4932
4933
4934
4935
4936
4939 Oid typid, int32 typmod, bool *isnull)
4940{
4941#ifdef USE_LIBXML
4943 XmlTableBuilderData *xtCxt;
4944 volatile xmlXPathObjectPtr xpathobj = NULL;
4945
4946 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableGetValue");
4947
4948 Assert(xtCxt->xpathobj &&
4949 xtCxt->xpathobj->type == XPATH_NODESET &&
4950 xtCxt->xpathobj->nodesetval != NULL);
4951
4952
4953 xmlSetStructuredErrorFunc(xtCxt->xmlerrcxt, xml_errorHandler);
4954
4955 *isnull = false;
4956
4957 Assert(xtCxt->xpathscomp[colnum] != NULL);
4958
4960 {
4961 xmlNodePtr cur;
4962 char *cstr = NULL;
4963
4964
4965 cur = xtCxt->xpathobj->nodesetval->nodeTab[xtCxt->row_count - 1];
4966 xtCxt->xpathcxt->node = cur;
4967
4968
4969 xpathobj = xmlXPathCompiledEval(xtCxt->xpathscomp[colnum], xtCxt->xpathcxt);
4970 if (xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)
4971 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
4972 "could not create XPath object");
4973
4974
4975
4976
4977
4978
4979
4980
4981 if (xpathobj->type == XPATH_NODESET)
4982 {
4983 int count = 0;
4984
4985 if (xpathobj->nodesetval != NULL)
4986 count = xpathobj->nodesetval->nodeNr;
4987
4988 if (xpathobj->nodesetval == NULL || count == 0)
4989 {
4990 *isnull = true;
4991 }
4992 else
4993 {
4994 if (typid == XMLOID)
4995 {
4996 text *textstr;
4998
4999
5001 for (int i = 0; i < count; i++)
5002 {
5003 textstr =
5004 xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],
5005 xtCxt->xmlerrcxt);
5006
5008 }
5009 cstr = str.data;
5010 }
5011 else
5012 {
5013 xmlChar *str;
5014
5015 if (count > 1)
5017 (errcode(ERRCODE_CARDINALITY_VIOLATION),
5018 errmsg("more than one value returned by column XPath expression")));
5019
5020 str = xmlXPathCastNodeSetToString(xpathobj->nodesetval);
5021 cstr = str ? xml_pstrdup_and_free(str) : "";
5022 }
5023 }
5024 }
5025 else if (xpathobj->type == XPATH_STRING)
5026 {
5027
5028 if (typid == XMLOID)
5029 cstr = escape_xml((char *) xpathobj->stringval);
5030 else
5031 cstr = (char *) xpathobj->stringval;
5032 }
5033 else if (xpathobj->type == XPATH_BOOLEAN)
5034 {
5035 char typcategory;
5036 bool typispreferred;
5037 xmlChar *str;
5038
5039
5041
5042 if (typcategory != TYPCATEGORY_NUMERIC)
5043 str = xmlXPathCastBooleanToString(xpathobj->boolval);
5044 else
5045 str = xmlXPathCastNumberToString(xmlXPathCastBooleanToNumber(xpathobj->boolval));
5046
5047 cstr = xml_pstrdup_and_free(str);
5048 }
5049 else if (xpathobj->type == XPATH_NUMBER)
5050 {
5051 xmlChar *str;
5052
5053 str = xmlXPathCastNumberToString(xpathobj->floatval);
5054 cstr = xml_pstrdup_and_free(str);
5055 }
5056 else
5057 elog(ERROR, "unexpected XPath object type %u", xpathobj->type);
5058
5059
5060
5061
5062
5063 Assert(cstr || *isnull);
5064
5065 if (!*isnull)
5067 cstr,
5068 state->typioparams[colnum],
5069 typmod);
5070 }
5072 {
5073 if (xpathobj != NULL)
5074 xmlXPathFreeObject(xpathobj);
5075 }
5077
5078 return result;
5079#else
5081 return 0;
5082#endif
5083}
5084
5085
5086
5087
5088
5089static void
5091{
5092#ifdef USE_LIBXML
5093 XmlTableBuilderData *xtCxt;
5094
5095 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableDestroyOpaque");
5096
5097
5098 xmlSetStructuredErrorFunc(xtCxt->xmlerrcxt, xml_errorHandler);
5099
5100 if (xtCxt->xpathscomp != NULL)
5101 {
5102 int i;
5103
5104 for (i = 0; i < xtCxt->natts; i++)
5105 if (xtCxt->xpathscomp[i] != NULL)
5106 xmlXPathFreeCompExpr(xtCxt->xpathscomp[i]);
5107 }
5108
5109 if (xtCxt->xpathobj != NULL)
5110 xmlXPathFreeObject(xtCxt->xpathobj);
5111 if (xtCxt->xpathcomp != NULL)
5112 xmlXPathFreeCompExpr(xtCxt->xpathcomp);
5113 if (xtCxt->xpathcxt != NULL)
5114 xmlXPathFreeContext(xtCxt->xpathcxt);
5115 if (xtCxt->doc != NULL)
5116 xmlFreeDoc(xtCxt->doc);
5117 if (xtCxt->ctxt != NULL)
5118 xmlFreeParserCtxt(xtCxt->ctxt);
5119
5121
5122
5123 xtCxt->magic = 0;
5124 state->opaque = NULL;
5125
5126#else
5128#endif
5129}
#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 PG_USED_FOR_ASSERTS_ONLY
#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