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

317 size_t len = strlen(str);

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

336 if (*(str + len) == '\n')

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

501 for (i = 1; i < len; i++)

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' ||

827 str[len - 1] == '\r'))

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;

905 foreach(arg, xexpr->args)

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 (e)

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{

3869 List *uniquetypes = NIL;

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)

4458 ereport(ERROR,

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