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;

758

759 root = xmlNewNode(NULL, (const xmlChar *) "content-root");

760 if (root == NULL || xmlerrcxt->err_occurred)

762 "could not allocate xml node");

763

764

765 xmlDocSetRootElement(doc, root);

766 xmlAddChildList(root, content_nodes);

767

768

769

770

771

772

773

774

775 newline = xmlNewDocText(NULL, (const xmlChar *) "\n");

776 if (newline == NULL || xmlerrcxt->err_occurred)

778 "could not allocate xml node");

779

780 for (xmlNodePtr node = root->children; node; node = node->next)

781 {

782

783 if (node->type != XML_TEXT_NODE && node->prev != NULL)

784 {

785 if (xmlSaveTree(ctxt, newline) == -1 || xmlerrcxt->err_occurred)

786 {

789 "could not save newline to xmlBuffer");

790 }

791 }

792

793 if (xmlSaveTree(ctxt, node) == -1 || xmlerrcxt->err_occurred)

794 {

797 "could not save content to xmlBuffer");

798 }

799 }

800

802 }

803

804 if (xmlSaveClose(ctxt) == -1 || xmlerrcxt->err_occurred)

805 {

806 ctxt = NULL;

808 "could not close xmlSaveCtxtPtr");

809 }

810

811

812

813

815 {

816 const char *str = (const char *) xmlBufferContent(buf);

817 int len = xmlBufferLength(buf);

818

819 while (len > 0 && (str[len - 1] == '\n' ||

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

822

824 }

825 else

826 result = (text *) xmlBuffer_to_xmltype(buf);

827 }

829 {

830 if (ctxt)

831 xmlSaveClose(ctxt);

833 xmlBufferFree(buf);

834 if (doc)

835 xmlFreeDoc(doc);

836

838

840 }

842

843 xmlBufferFree(buf);

844 xmlFreeDoc(doc);

845

847

848 return result;

849#else

851 return NULL;

852#endif

853}

854

855

858 Datum *named_argvalue, bool *named_argnull,

859 Datum *argvalue, bool *argnull)

860{

861#ifdef USE_LIBXML

863 List *named_arg_strings;

864 List *arg_strings;

865 int i;

869 volatile xmlBufferPtr buf = NULL;

870 volatile xmlTextWriterPtr writer = NULL;

871

872

873

874

875

876

877

878

879 named_arg_strings = NIL;

880 i = 0;

882 {

884 char *str;

885

886 if (named_argnull[i])

887 str = NULL;

888 else

891 false);

892 named_arg_strings = lappend(named_arg_strings, str);

893 i++;

894 }

895

896 arg_strings = NIL;

897 i = 0;

898 foreach(arg, xexpr->args)

899 {

901 char *str;

902

903

904 if (!argnull[i])

905 {

908 true);

909 arg_strings = lappend(arg_strings, str);

910 }

911 i++;

912 }

913

915

917 {

918 buf = xmlBufferCreate();

919 if (buf == NULL || xmlerrcxt->err_occurred)

921 "could not allocate xmlBuffer");

922 writer = xmlNewTextWriterMemory(buf, 0);

923 if (writer == NULL || xmlerrcxt->err_occurred)

925 "could not allocate xmlTextWriter");

926

927 xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name);

928

929 forboth(arg, named_arg_strings, narg, xexpr->arg_names)

930 {

933

935 xmlTextWriterWriteAttribute(writer,

936 (xmlChar *) argname,

937 (xmlChar *) str);

938 }

939

940 foreach(arg, arg_strings)

941 {

943

944 xmlTextWriterWriteRaw(writer, (xmlChar *) str);

945 }

946

947 xmlTextWriterEndElement(writer);

948

949

950 xmlFreeTextWriter(writer);

951 writer = NULL;

952

953 result = xmlBuffer_to_xmltype(buf);

954 }

956 {

957 if (writer)

958 xmlFreeTextWriter(writer);

960 xmlBufferFree(buf);

961

963

965 }

967

968 xmlBufferFree(buf);

969

971

972 return result;

973#else

975 return NULL;

976#endif

977}

978

979

982{

983#ifdef USE_LIBXML

984 xmlDocPtr doc;

985

986 doc = xml_parse(data, xmloption_arg, preserve_whitespace,

988 xmlFreeDoc(doc);

989

991#else

993 return NULL;

994#endif

995}

996

997

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

1000{

1001#ifdef USE_LIBXML

1004

1007 (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),

1008 errmsg("invalid XML processing instruction"),

1009 errdetail("XML processing instruction target name cannot be \"%s\".", target)));

1010

1011

1012

1013

1014

1015 *result_is_null = arg_is_null;

1016 if (*result_is_null)

1017 return NULL;

1018

1020

1022

1023 if (arg != NULL)

1024 {

1026

1028 if (strstr(string, "?>") != NULL)

1030 (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),

1031 errmsg("invalid XML processing instruction"),

1032 errdetail("XML processing instruction cannot contain \"?>\".")));

1033

1037 }

1039

1042 return result;

1043#else

1045 return NULL;

1046#endif

1047}

1048

1049

1052{

1053#ifdef USE_LIBXML

1054 char *str;

1055 size_t len;

1056 xmlChar *orig_version;

1057 int orig_standalone;

1059

1062

1063 parse_xml_decl((xmlChar *) str, &len, &orig_version, NULL, &orig_standalone);

1064

1065 if (version)

1066 orig_version = xml_text2xmlChar(version);

1067 else

1068 orig_version = NULL;

1069

1070 switch (standalone)

1071 {

1073 orig_standalone = 1;

1074 break;

1076 orig_standalone = 0;

1077 break;

1079 orig_standalone = -1;

1080 break;

1082

1083 break;

1084 }

1085

1087 print_xml_decl(&buf, orig_version, 0, orig_standalone);

1089

1091#else

1093 return NULL;

1094#endif

1095}

1096

1097

1098

1099

1100

1101

1102

1103

1104

1105

1108{

1110 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

1111 errmsg("xmlvalidate is not implemented")));

1112 return 0;

1113}

1114

1115

1116bool

1118{

1119#ifdef USE_LIBXML

1120 xmlDocPtr doc;

1122

1123

1124

1125

1128 if (doc)

1129 xmlFreeDoc(doc);

1130

1132#else

1134 return false;

1135#endif

1136}

1137

1138

1139#ifdef USE_LIBXML

1140

1141

1142

1143

1144

1145

1146

1147

1148

1149

1150

1151

1152void

1154{

1155 static bool first_time = true;

1156

1157 if (first_time)

1158 {

1159

1160

1161

1162

1163

1164

1165 if (sizeof(char) != sizeof(xmlChar))

1167 (errmsg("could not initialize XML library"),

1168 errdetail("libxml2 has incompatible char type: sizeof(char)=%zu, sizeof(xmlChar)=%zu.",

1169 sizeof(char), sizeof(xmlChar))));

1170

1171#ifdef USE_LIBXMLCONTEXT

1172

1173 xml_memory_init();

1174#endif

1175

1176

1177 LIBXML_TEST_VERSION;

1178

1179 first_time = false;

1180 }

1181}

1182

1183

1184

1185

1186

1187

1188

1189

1190

1191

1192

1193

1194

1195

1196

1197

1200{

1202 void *new_errcxt;

1203

1204

1206

1207

1209 errcxt->magic = ERRCXT_MAGIC;

1210 errcxt->strictness = strictness;

1211 errcxt->err_occurred = false;

1213

1214

1215

1216

1217

1218

1219

1220

1221 errcxt->saved_errfunc = xmlStructuredError;

1222

1223#ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT

1224 errcxt->saved_errcxt = xmlStructuredErrorContext;

1225#else

1226 errcxt->saved_errcxt = xmlGenericErrorContext;

1227#endif

1228

1229 xmlSetStructuredErrorFunc(errcxt, xml_errorHandler);

1230

1231

1232

1233

1234

1235

1236

1237

1238

1239

1240

1241

1242

1243

1244

1245#ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT

1246 new_errcxt = xmlStructuredErrorContext;

1247#else

1248 new_errcxt = xmlGenericErrorContext;

1249#endif

1250

1251 if (new_errcxt != errcxt)

1253 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

1254 errmsg("could not set up XML error handler"),

1255 errhint("This probably indicates that the version of libxml2"

1256 " being used is not compatible with the libxml2"

1257 " header files that PostgreSQL was built with.")));

1258

1259

1260

1261

1262

1263 errcxt->saved_entityfunc = xmlGetExternalEntityLoader();

1264 xmlSetExternalEntityLoader(xmlPgEntityLoader);

1265

1266 return errcxt;

1267}

1268

1269

1270

1271

1272

1273

1274

1275

1276

1277

1278

1279void

1281{

1282 void *cur_errcxt;

1283

1284

1285 Assert(errcxt->magic == ERRCXT_MAGIC);

1286

1287

1288

1289

1290

1291

1292 Assert(!errcxt->err_occurred || isError);

1293

1294

1295

1296

1297

1298

1299#ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT

1300 cur_errcxt = xmlStructuredErrorContext;

1301#else

1302 cur_errcxt = xmlGenericErrorContext;

1303#endif

1304

1305 if (cur_errcxt != errcxt)

1306 elog(WARNING, "libxml error handling state is out of sync with xml.c");

1307

1308

1309 xmlSetStructuredErrorFunc(errcxt->saved_errcxt, errcxt->saved_errfunc);

1310 xmlSetExternalEntityLoader(errcxt->saved_entityfunc);

1311

1312

1313

1314

1315

1316 errcxt->magic = 0;

1317

1318

1319 pfree(errcxt->err_buf.data);

1321}

1322

1323

1324

1325

1326

1327bool

1329{

1330 return errcxt->err_occurred;

1331}

1332

1333

1334

1335

1336

1337

1338

1339

1340

1341

1342

1343#define CHECK_XML_SPACE(p) \

1344 do { \

1345 if (!xmlIsBlank_ch(*(p))) \

1346 return XML_ERR_SPACE_REQUIRED; \

1347 } while (0)

1348

1349#define SKIP_XML_SPACE(p) \

1350 while (xmlIsBlank_ch(*(p))) (p)++

1351

1352

1353

1354#define PG_XMLISNAMECHAR(c) \

1355 (xmlIsBaseChar_ch(c) || xmlIsIdeographicQ(c) \

1356 || xmlIsDigit_ch(c) \

1357 || c == '.' || c == '-' || c == '_' || c == ':' \

1358 || xmlIsCombiningQ(c) \

1359 || xmlIsExtender_ch(c))

1360

1361

1362static xmlChar *

1363xml_pnstrdup(const xmlChar *str, size_t len)

1364{

1365 xmlChar *result;

1366

1367 result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));

1368 memcpy(result, str, len * sizeof(xmlChar));

1369 result[len] = 0;

1370 return result;

1371}

1372

1373

1374static xmlChar *

1375pg_xmlCharStrndup(const char *str, size_t len)

1376{

1377 xmlChar *result;

1378

1379 result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));

1380 memcpy(result, str, len);

1381 result[len] = '\0';

1382

1383 return result;

1384}

1385

1386

1387

1388

1389

1390

1391static char *

1392xml_pstrdup_and_free(xmlChar *str)

1393{

1394 char *result;

1395

1396 if (str)

1397 {

1399 {

1401 }

1403 {

1404 xmlFree(str);

1405 }

1407 }

1408 else

1409 result = NULL;

1410

1411 return result;

1412}

1413

1414

1415

1416

1417

1418

1419

1420static int

1421parse_xml_decl(const xmlChar *str, size_t *lenp,

1422 xmlChar **version, xmlChar **encoding, int *standalone)

1423{

1424 const xmlChar *p;

1425 const xmlChar *save_p;

1426 size_t len;

1427 int utf8char;

1428 int utf8len;

1429

1430

1431

1432

1433

1434

1435

1437

1438

1439 if (version)

1440 *version = NULL;

1443 if (standalone)

1444 *standalone = -1;

1445

1446 p = str;

1447

1448 if (xmlStrncmp(p, (xmlChar *) "<?xml", 5) != 0)

1449 goto finished;

1450

1451

1452

1453

1454

1455

1456

1457

1458

1460 utf8char = xmlGetUTF8Char(p + 5, &utf8len);

1461 if (PG_XMLISNAMECHAR(utf8char))

1462 goto finished;

1463

1464 p += 5;

1465

1466

1467 CHECK_XML_SPACE(p);

1468 SKIP_XML_SPACE(p);

1469 if (xmlStrncmp(p, (xmlChar *) "version", 7) != 0)

1470 return XML_ERR_VERSION_MISSING;

1471 p += 7;

1472 SKIP_XML_SPACE(p);

1473 if (*p != '=')

1474 return XML_ERR_VERSION_MISSING;

1475 p += 1;

1476 SKIP_XML_SPACE(p);

1477

1478 if (*p == '\'' || *p == '"')

1479 {

1480 const xmlChar *q;

1481

1482 q = xmlStrchr(p + 1, *p);

1483 if (!q)

1484 return XML_ERR_VERSION_MISSING;

1485

1486 if (version)

1487 *version = xml_pnstrdup(p + 1, q - p - 1);

1488 p = q + 1;

1489 }

1490 else

1491 return XML_ERR_VERSION_MISSING;

1492

1493

1494 save_p = p;

1495 SKIP_XML_SPACE(p);

1496 if (xmlStrncmp(p, (xmlChar *) "encoding", 8) == 0)

1497 {

1498 CHECK_XML_SPACE(save_p);

1499 p += 8;

1500 SKIP_XML_SPACE(p);

1501 if (*p != '=')

1502 return XML_ERR_MISSING_ENCODING;

1503 p += 1;

1504 SKIP_XML_SPACE(p);

1505

1506 if (*p == '\'' || *p == '"')

1507 {

1508 const xmlChar *q;

1509

1510 q = xmlStrchr(p + 1, *p);

1511 if (!q)

1512 return XML_ERR_MISSING_ENCODING;

1513

1515 *encoding = xml_pnstrdup(p + 1, q - p - 1);

1516 p = q + 1;

1517 }

1518 else

1519 return XML_ERR_MISSING_ENCODING;

1520 }

1521 else

1522 {

1523 p = save_p;

1524 }

1525

1526

1527 save_p = p;

1528 SKIP_XML_SPACE(p);

1529 if (xmlStrncmp(p, (xmlChar *) "standalone", 10) == 0)

1530 {

1531 CHECK_XML_SPACE(save_p);

1532 p += 10;

1533 SKIP_XML_SPACE(p);

1534 if (*p != '=')

1535 return XML_ERR_STANDALONE_VALUE;

1536 p += 1;

1537 SKIP_XML_SPACE(p);

1538 if (xmlStrncmp(p, (xmlChar *) "'yes'", 5) == 0 ||

1539 xmlStrncmp(p, (xmlChar *) "\"yes\"", 5) == 0)

1540 {

1541 if (standalone)

1542 *standalone = 1;

1543 p += 5;

1544 }

1545 else if (xmlStrncmp(p, (xmlChar *) "'no'", 4) == 0 ||

1546 xmlStrncmp(p, (xmlChar *) "\"no\"", 4) == 0)

1547 {

1548 if (standalone)

1549 *standalone = 0;

1550 p += 4;

1551 }

1552 else

1553 return XML_ERR_STANDALONE_VALUE;

1554 }

1555 else

1556 {

1557 p = save_p;

1558 }

1559

1560 SKIP_XML_SPACE(p);

1561 if (xmlStrncmp(p, (xmlChar *) "?>", 2) != 0)

1562 return XML_ERR_XMLDECL_NOT_FINISHED;

1563 p += 2;

1564

1565finished:

1567

1568 for (p = str; p < str + len; p++)

1569 if (*p > 127)

1570 return XML_ERR_INVALID_CHAR;

1571

1572 if (lenp)

1573 *lenp = len;

1574

1575 return XML_ERR_OK;

1576}

1577

1578

1579

1580

1581

1582

1583

1584

1585

1586

1587

1588

1589

1590

1591

1592

1593static bool

1594print_xml_decl(StringInfo buf, const xmlChar *version,

1596{

1599 || standalone != -1)

1600 {

1602

1603 if (version)

1605 else

1607

1609 {

1610

1611

1612

1613

1616 }

1617

1618 if (standalone == 1)

1620 else if (standalone == 0)

1623

1624 return true;

1625 }

1626 else

1627 return false;

1628}

1629

1630

1631

1632

1633

1634

1635

1636

1637

1638

1639

1640

1641

1642

1643

1644

1645

1646

1647

1648

1649

1650

1651

1652

1653

1654

1655

1656

1657

1658

1659static bool

1660xml_doctype_in_content(const xmlChar *str)

1661{

1662 const xmlChar *p = str;

1663

1664 for (;;)

1665 {

1666 const xmlChar *e;

1667

1668 SKIP_XML_SPACE(p);

1669 if (*p != '<')

1670 return false;

1671 p++;

1672

1673 if (*p == '!')

1674 {

1675 p++;

1676

1677

1678 if (xmlStrncmp(p, (xmlChar *) "DOCTYPE", 7) == 0)

1679 return true;

1680

1681

1682 if (xmlStrncmp(p, (xmlChar *) "--", 2) != 0)

1683 return false;

1684

1685 p = xmlStrstr(p + 2, (xmlChar *) "--");

1686 if (!p || p[2] != '>')

1687 return false;

1688

1689 p += 3;

1690 continue;

1691 }

1692

1693

1694 if (*p != '?')

1695 return false;

1696 p++;

1697

1698

1699 e = xmlStrstr(p, (xmlChar *) "?>");

1700 if (e)

1701 return false;

1702

1703

1704 p = e + 2;

1705 }

1706}

1707

1708

1709

1710

1711

1712

1713

1714

1715

1716

1717

1718

1719

1720

1721

1722

1723

1724

1725

1726

1727

1728

1729

1730

1731

1732

1733

1734

1735static xmlDocPtr

1737 bool preserve_whitespace, int encoding,

1738 XmlOptionType *parsed_xmloptiontype, xmlNodePtr *parsed_nodes,

1739 Node *escontext)

1740{

1743 xmlChar *utf8string;

1745 volatile xmlParserCtxtPtr ctxt = NULL;

1746 volatile xmlDocPtr doc = NULL;

1747

1748

1749

1750

1751

1753 string = xml_text2xmlChar(data);

1754

1755

1756

1757

1758

1759

1760

1761

1766

1767

1769

1770

1772 {

1773 bool parse_as_document = false;

1775 int res_code;

1776 size_t count = 0;

1777 xmlChar *version = NULL;

1778 int standalone = 0;

1779

1780

1781 xmlInitParser();

1782

1783

1785 parse_as_document = true;

1786 else

1787 {

1788

1789 res_code = parse_xml_decl(utf8string,

1790 &count, &version, NULL, &standalone);

1791 if (res_code != 0)

1792 {

1794 errcode(ERRCODE_INVALID_XML_CONTENT),

1795 errmsg_internal("invalid XML content: invalid XML declaration"),

1796 errdetail_for_xml_code(res_code));

1797 goto fail;

1798 }

1799

1800

1801 if (xml_doctype_in_content(utf8string + count))

1802 parse_as_document = true;

1803 }

1804

1805

1806

1807

1808

1809

1810

1811

1812

1813

1814 options = XML_PARSE_NOENT | XML_PARSE_DTDATTR

1815 | (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS);

1816

1817

1818 if (parsed_xmloptiontype != NULL)

1821 if (parsed_nodes != NULL)

1822 *parsed_nodes = NULL;

1823

1824 if (parse_as_document)

1825 {

1826 ctxt = xmlNewParserCtxt();

1827 if (ctxt == NULL || xmlerrcxt->err_occurred)

1829 "could not allocate parser context");

1830

1831 doc = xmlCtxtReadDoc(ctxt, utf8string,

1832 NULL,

1833 "UTF-8",

1835

1836 if (doc == NULL || xmlerrcxt->err_occurred)

1837 {

1838

1840 xml_errsave(escontext, xmlerrcxt,

1841 ERRCODE_INVALID_XML_DOCUMENT,

1842 "invalid XML document");

1843 else

1844 xml_errsave(escontext, xmlerrcxt,

1845 ERRCODE_INVALID_XML_CONTENT,

1846 "invalid XML content");

1847 goto fail;

1848 }

1849 }

1850 else

1851 {

1852 xmlNodePtr root;

1853

1854

1855 doc = xmlNewDoc(version);

1856 if (doc == NULL || xmlerrcxt->err_occurred)

1858 "could not allocate XML document");

1859

1860 Assert(doc->encoding == NULL);

1861 doc->encoding = xmlStrdup((const xmlChar *) "UTF-8");

1862 if (doc->encoding == NULL || xmlerrcxt->err_occurred)

1864 "could not allocate XML document");

1865 doc->standalone = standalone;

1866

1867 root = xmlNewNode(NULL, (const xmlChar *) "content-root");

1868 if (root == NULL || xmlerrcxt->err_occurred)

1870 "could not allocate xml node");

1871

1872 xmlDocSetRootElement(doc, root);

1873

1874

1875 if (*(utf8string + count))

1876 {

1877 xmlNodePtr node_list = NULL;

1878 xmlParserErrors res;

1879

1880 res = xmlParseInNodeContext(root,

1881 (char *) utf8string + count,

1882 strlen((char *) utf8string + count),

1884 &node_list);

1885

1886 if (res != XML_ERR_OK || xmlerrcxt->err_occurred)

1887 {

1888 xmlFreeNodeList(node_list);

1889 xml_errsave(escontext, xmlerrcxt,

1890 ERRCODE_INVALID_XML_CONTENT,

1891 "invalid XML content");

1892 goto fail;

1893 }

1894

1895 if (parsed_nodes != NULL)

1896 *parsed_nodes = node_list;

1897 else

1898 xmlFreeNodeList(node_list);

1899 }

1900 }

1901

1902fail:

1903 ;

1904 }

1906 {

1907 if (doc != NULL)

1908 xmlFreeDoc(doc);

1909 if (ctxt != NULL)

1910 xmlFreeParserCtxt(ctxt);

1911

1913

1915 }

1917

1918 if (ctxt != NULL)

1919 xmlFreeParserCtxt(ctxt);

1920

1922

1923 return doc;

1924}

1925

1926

1927

1928

1929

1930static xmlChar *

1931xml_text2xmlChar(text *in)

1932{

1934}

1935

1936

1937#ifdef USE_LIBXMLCONTEXT

1938

1939

1940

1941

1942

1943static void

1944xml_memory_init(void)

1945{

1946

1947 if (LibxmlContext == NULL)

1949 "Libxml context",

1951

1952

1953 xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);

1954}

1955

1956

1957

1958

1959static void *

1960xml_palloc(size_t size)

1961{

1963}

1964

1965

1966static void *

1967xml_repalloc(void *ptr, size_t size)

1968{

1970}

1971

1972

1973static void

1974xml_pfree(void *ptr)

1975{

1976

1977 if (ptr)

1979}

1980

1981

1982static char *

1983xml_pstrdup(const char *string)

1984{

1986}

1987#endif

1988

1989

1990

1991

1992

1993

1994

1995

1996

1997

1998

1999

2000

2001static xmlParserInputPtr

2002xmlPgEntityLoader(const char *URL, const char *ID,

2003 xmlParserCtxtPtr ctxt)

2004{

2005 return xmlNewStringInputStream(ctxt, (const xmlChar *) "");

2006}

2007

2008

2009

2010

2011

2012

2013

2014

2015

2016

2017

2018

2019void

2021{

2022 char *detail;

2023

2024

2025 if (errcxt->magic != ERRCXT_MAGIC)

2026 elog(ERROR, "xml_ereport called with invalid PgXmlErrorContext");

2027

2028

2029 errcxt->err_occurred = false;

2030

2031

2032 if (errcxt->err_buf.len > 0)

2033 detail = errcxt->err_buf.data;

2034 else

2035 detail = NULL;

2036

2041}

2042

2043

2044

2045

2046

2047

2048

2049

2050

2051

2052

2053

2054

2055

2056static void

2058 int sqlcode, const char *msg)

2059{

2060 char *detail;

2061

2062

2063 if (errcxt->magic != ERRCXT_MAGIC)

2064 elog(ERROR, "xml_errsave called with invalid PgXmlErrorContext");

2065

2066

2067 errcxt->err_occurred = false;

2068

2069

2070 if (errcxt->err_buf.len > 0)

2071 detail = errcxt->err_buf.data;

2072 else

2073 detail = NULL;

2074

2079}

2080

2081

2082

2083

2084

2085static void

2086xml_errorHandler(void *data, PgXmlErrorPtr error)

2087{

2089 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) error->ctxt;

2090 xmlParserInputPtr input = (ctxt != NULL) ? ctxt->input : NULL;

2091 xmlNodePtr node = error->node;

2092 const xmlChar *name = (node != NULL &&

2093 node->type == XML_ELEMENT_NODE) ? node->name : NULL;

2094 int domain = error->domain;

2095 int level = error->level;

2097

2098

2099

2100

2101

2102

2103

2104 if (xmlerrcxt->magic != ERRCXT_MAGIC)

2105 elog(FATAL, "xml_errorHandler called with invalid PgXmlErrorContext");

2106

2107

2108

2109

2110

2111

2112

2113

2114

2115 switch (error->code)

2116 {

2117 case XML_WAR_NS_URI:

2118 level = XML_ERR_ERROR;

2119 domain = XML_FROM_NAMESPACE;

2120 break;

2121

2122 case XML_ERR_NS_DECL_ERROR:

2123 case XML_WAR_NS_URI_RELATIVE:

2124 case XML_WAR_NS_COLUMN:

2125 case XML_NS_ERR_XML_NAMESPACE:

2126 case XML_NS_ERR_UNDEFINED_NAMESPACE:

2127 case XML_NS_ERR_QNAME:

2128 case XML_NS_ERR_ATTRIBUTE_REDEFINED:

2129 case XML_NS_ERR_EMPTY:

2130 domain = XML_FROM_NAMESPACE;

2131 break;

2132 }

2133

2134

2135 switch (domain)

2136 {

2137 case XML_FROM_PARSER:

2138

2139

2140

2141

2142

2143

2144

2145

2146 if (error->code == XML_ERR_NOT_WELL_BALANCED &&

2147 xmlerrcxt->err_occurred)

2148 return;

2149

2150

2151 case XML_FROM_NONE:

2152 case XML_FROM_MEMORY:

2153 case XML_FROM_IO:

2154

2155

2156

2157

2158

2159 if (error->code == XML_WAR_UNDECLARED_ENTITY)

2160 return;

2161

2162

2163 break;

2164

2165 default:

2166

2168 return;

2169 break;

2170 }

2171

2172

2174

2175 if (error->line > 0)

2177 if (name != NULL)

2179 if (error->message != NULL)

2181 else

2183

2184

2185

2186

2187

2188

2189

2190

2191

2192

2193

2194

2195 if (input != NULL)

2196 {

2197 xmlGenericErrorFunc errFuncSaved = xmlGenericError;

2198 void *errCtxSaved = xmlGenericErrorContext;

2199

2200 xmlSetGenericErrorFunc(errorBuf,

2202

2203

2204 appendStringInfoLineSeparator(errorBuf);

2205

2206 xmlParserPrintFileContext(input);

2207

2208

2209 xmlSetGenericErrorFunc(errCtxSaved, errFuncSaved);

2210 }

2211

2212

2213 chopStringInfoNewlines(errorBuf);

2214

2215

2216

2217

2218

2219

2220

2221

2222

2224 {

2225 appendStringInfoLineSeparator(&xmlerrcxt->err_buf);

2227 errorBuf->len);

2228

2230 return;

2231 }

2232

2233

2234

2235

2236

2237

2238

2239

2240

2241 if (level >= XML_ERR_ERROR)

2242 {

2243 appendStringInfoLineSeparator(&xmlerrcxt->err_buf);

2245 errorBuf->len);

2246

2247 xmlerrcxt->err_occurred = true;

2248 }

2249 else if (level >= XML_ERR_WARNING)

2250 {

2253 }

2254 else

2255 {

2258 }

2259

2261}

2262

2263

2264

2265

2266

2267

2268

2269

2270

2271

2272

2273static int

2274errdetail_for_xml_code(int code)

2275{

2276 const char *det;

2277

2278 switch (code)

2279 {

2280 case XML_ERR_INVALID_CHAR:

2281 det = gettext_noop("Invalid character value.");

2282 break;

2283 case XML_ERR_SPACE_REQUIRED:

2285 break;

2286 case XML_ERR_STANDALONE_VALUE:

2287 det = gettext_noop("standalone accepts only 'yes' or 'no'.");

2288 break;

2289 case XML_ERR_VERSION_MISSING:

2290 det = gettext_noop("Malformed declaration: missing version.");

2291 break;

2292 case XML_ERR_MISSING_ENCODING:

2293 det = gettext_noop("Missing encoding in text declaration.");

2294 break;

2295 case XML_ERR_XMLDECL_NOT_FINISHED:

2296 det = gettext_noop("Parsing XML declaration: '?>' expected.");

2297 break;

2298 default:

2299 det = gettext_noop("Unrecognized libxml error code: %d.");

2300 break;

2301 }

2302

2304}

2305

2306

2307

2308

2309

2310static void

2312{

2313 while (str->len > 0 && str->data[str->len - 1] == '\n')

2314 str->data[--str->len] = '\0';

2315}

2316

2317

2318

2319

2320

2321static void

2323{

2324 chopStringInfoNewlines(str);

2325 if (str->len > 0)

2327}

2328

2329

2330

2331

2332

2334sqlchar_to_unicode(const char *s)

2335{

2336 char *utf8string;

2337 pg_wchar ret[2];

2338

2339

2341

2344

2345 if (utf8string != s)

2346 pfree(utf8string);

2347

2348 return ret[0];

2349}

2350

2351

2352static bool

2353is_valid_xml_namefirst(pg_wchar c)

2354{

2355

2356 return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)

2357 || c == '_' || c == ':');

2358}

2359

2360

2361static bool

2362is_valid_xml_namechar(pg_wchar c)

2363{

2364

2365 return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)

2366 || xmlIsDigitQ(c)

2367 || c == '.' || c == '-' || c == '_' || c == ':'

2368 || xmlIsCombiningQ(c)

2369 || xmlIsExtenderQ(c));

2370}

2371#endif

2372

2373

2374

2375

2376

2377char *

2379 bool escape_period)

2380{

2381#ifdef USE_LIBXML

2383 const char *p;

2384

2385

2386

2387

2388

2389 Assert(fully_escaped || !escape_period);

2390

2392

2394 {

2395 if (*p == ':' && (p == ident || fully_escaped))

2397 else if (*p == '_' && *(p + 1) == 'x')

2399 else if (fully_escaped && p == ident &&

2401 {

2402 if (*p == 'x')

2404 else

2406 }

2407 else if (escape_period && *p == '.')

2409 else

2410 {

2411 pg_wchar u = sqlchar_to_unicode(p);

2412

2413 if ((p == ident)

2414 ? !is_valid_xml_namefirst(u)

2415 : !is_valid_xml_namechar(u))

2417 else

2419 }

2420 }

2421

2422 return buf.data;

2423#else

2425 return NULL;

2426#endif

2427}

2428

2429

2430

2431

2432

2433char *

2435{

2437 const char *p;

2438

2440

2442 {

2443 if (*p == '_' && *(p + 1) == 'x'

2444 && isxdigit((unsigned char) *(p + 2))

2445 && isxdigit((unsigned char) *(p + 3))

2446 && isxdigit((unsigned char) *(p + 4))

2447 && isxdigit((unsigned char) *(p + 5))

2448 && *(p + 6) == '_')

2449 {

2451 unsigned int u;

2452

2453 sscanf(p + 2, "%X", &u);

2456 p += 6;

2457 }

2458 else

2460 }

2461

2462 return buf.data;

2463}

2464

2465

2466

2467

2468

2469

2470

2471

2472

2473

2474

2475char *

2477{

2479 {

2481 Oid elmtype;

2483 bool elmbyval;

2484 char elmalign;

2485 int num_elems;

2486 Datum *elem_values;

2487 bool *elem_nulls;

2489 int i;

2490

2494

2496 elmlen, elmbyval, elmalign,

2497 &elem_values, &elem_nulls,

2498 &num_elems);

2499

2501

2502 for (i = 0; i < num_elems; i++)

2503 {

2504 if (elem_nulls[i])

2505 continue;

2509 elmtype, true));

2511 }

2512

2513 pfree(elem_values);

2514 pfree(elem_nulls);

2515

2516 return buf.data;

2517 }

2518 else

2519 {

2520 Oid typeOut;

2521 bool isvarlena;

2522 char *str;

2523

2524

2525

2526

2527

2529

2530

2531

2532

2533 switch (type)

2534 {

2535 case BOOLOID:

2537 return "true";

2538 else

2539 return "false";

2540

2541 case DATEOID:

2542 {

2546

2548

2551 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),

2552 errmsg("date out of range"),

2553 errdetail("XML does not support infinite date values.")));

2557

2559 }

2560

2561 case TIMESTAMPOID:

2562 {

2567

2569

2570

2573 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),

2574 errmsg("timestamp out of range"),

2575 errdetail("XML does not support infinite timestamp values.")));

2578 else

2580 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),

2581 errmsg("timestamp out of range")));

2582

2584 }

2585

2586 case TIMESTAMPTZOID:

2587 {

2590 int tz;

2592 const char *tzn = NULL;

2594

2596

2597

2600 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),

2601 errmsg("timestamp out of range"),

2602 errdetail("XML does not support infinite timestamp values.")));

2605 else

2607 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),

2608 errmsg("timestamp out of range")));

2609

2611 }

2612

2613#ifdef USE_LIBXML

2614 case BYTEAOID:

2615 {

2618 volatile xmlBufferPtr buf = NULL;

2619 volatile xmlTextWriterPtr writer = NULL;

2620 char *result;

2621

2623

2625 {

2626 buf = xmlBufferCreate();

2627 if (buf == NULL || xmlerrcxt->err_occurred)

2629 "could not allocate xmlBuffer");

2630 writer = xmlNewTextWriterMemory(buf, 0);

2631 if (writer == NULL || xmlerrcxt->err_occurred)

2633 "could not allocate xmlTextWriter");

2634

2636 xmlTextWriterWriteBase64(writer, VARDATA_ANY(bstr),

2638 else

2639 xmlTextWriterWriteBinHex(writer, VARDATA_ANY(bstr),

2641

2642

2643 xmlFreeTextWriter(writer);

2644 writer = NULL;

2645

2646 result = pstrdup((const char *) xmlBufferContent(buf));

2647 }

2649 {

2650 if (writer)

2651 xmlFreeTextWriter(writer);

2652 if (buf)

2653 xmlBufferFree(buf);

2654

2656

2658 }

2660

2661 xmlBufferFree(buf);

2662

2664

2665 return result;

2666 }

2667#endif

2668

2669 }

2670

2671

2672

2673

2676

2677

2678 if (type == XMLOID || !xml_escape_strings)

2679 return str;

2680

2681

2683 }

2684}

2685

2686

2687

2688

2689

2690

2691

2692

2693

2694char *

2696{

2698 const char *p;

2699

2701 for (p = str; *p; p++)

2702 {

2703 switch (*p)

2704 {

2705 case '&':

2707 break;

2708 case '<':

2710 break;

2711 case '>':

2713 break;

2714 case '\r':

2716 break;

2717 default:

2719 break;

2720 }

2721 }

2722 return buf.data;

2723}

2724

2725

2726static char *

2728{

2729 size_t len = strlen(s) + 1;

2731

2732 memcpy(ret, s, len);

2733 return ret;

2734}

2735

2736

2737

2738

2739

2740

2741

2742

2743

2744

2745

2746

2747

2748

2749

2750

2751

2752

2753

2754

2755

2756

2757

2758

2759

2760

2761

2762

2763

2764

2765

2766

2767

2768

2769

2770

2771

2772

2773

2774

2775

2776

2777

2778

2779

2780

2781

2782

2783static List *

2785{

2788 int spi_result;

2789

2790 spi_result = SPI_execute(query, true, 0);

2792 elog(ERROR, "SPI_execute returned %s for %s",

2794

2796 {

2798 bool isnull;

2799

2802 1,

2803 &isnull);

2804 if (!isnull)

2806 }

2807

2808 return list;

2809}

2810

2811

2812static List *

2814{

2816

2818 appendStringInfo(&query, "SELECT oid FROM pg_catalog.pg_class"

2819 " WHERE relnamespace = %u AND relkind IN ("

2823 " AND pg_catalog.has_table_privilege (oid, 'SELECT')"

2824 " ORDER BY relname;", nspid);

2825

2827}

2828

2829

2830

2831

2832

2833

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

2835

2836#define XML_VISIBLE_SCHEMAS "SELECT oid FROM pg_catalog.pg_namespace WHERE pg_catalog.has_schema_privilege (oid, 'USAGE') AND NOT " XML_VISIBLE_SCHEMAS_EXCLUDE

2837

2838

2839static List *

2841{

2843}

2844

2845

2846static List *

2848{

2849

2851 " WHERE relkind IN ("

2855 " AND pg_catalog.has_table_privilege(pg_class.oid, 'SELECT')"

2857}

2858

2859

2860

2861

2862

2863

2864

2867 const char *xmlschema, bool nulls, bool tableforest,

2868 const char *targetns, bool top_level)

2869{

2871

2877 xmlschema, nulls, tableforest,

2878 targetns, top_level);

2879}

2880

2881

2884{

2889

2891 nulls, tableforest,

2892 targetns, true)));

2893}

2894

2895

2898{

2903

2905 NULL, nulls, tableforest,

2906 targetns, true)));

2907}

2908

2909

2912{

2918

2922

2924

2925 if (!tableforest)

2926 {

2929 }

2930

2933 if (portal == NULL)

2935 (errcode(ERRCODE_UNDEFINED_CURSOR),

2936 errmsg("cursor \"%s\" does not exist", name)));

2937

2941 tableforest, targetns, true);

2942

2944

2945 if (!tableforest)

2947

2949}

2950

2951

2952

2953

2954

2955

2956

2957

2958

2959

2960

2961

2962

2963

2964static void

2966 const char *xmlschema, const char *targetns,

2967 bool top_level)

2968{

2969

2970 Assert(top_level || !xmlschema);

2971

2973 if (top_level)

2974 {

2976 if (strlen(targetns) > 0)

2978 }

2979 if (xmlschema)

2980 {

2981

2982 if (strlen(targetns) > 0)

2983 appendStringInfo(result, " xsi:schemaLocation=\"%s #\"", targetns);

2984 else

2986 }

2988}

2989

2990

2991static void

2993{

2995}

2996

2997

3000 const char *xmlschema, bool nulls, bool tableforest,

3001 const char *targetns, bool top_level)

3002{

3004 char *xmltn;

3006

3007 if (tablename)

3009 else

3010 xmltn = "table";

3011

3013

3017 (errcode(ERRCODE_DATA_EXCEPTION),

3018 errmsg("invalid query")));

3019

3020 if (!tableforest)

3021 {

3023 targetns, top_level);

3025 }

3026

3027 if (xmlschema)

3029

3032 tableforest, targetns, top_level);

3033

3034 if (!tableforest)

3036

3038

3039 return result;

3040}

3041

3042

3045{

3050 const char *result;

3052

3055 tableforest, targetns);

3057

3059}

3060

3061

3064{

3069 const char *result;

3072

3074

3076 elog(ERROR, "SPI_prepare(\"%s\") failed", query);

3077

3079 elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);

3080

3083 tableforest, targetns));

3086

3088}

3089

3090

3093{

3098 const char *xmlschema;

3100

3103 if (portal == NULL)

3105 (errcode(ERRCODE_UNDEFINED_CURSOR),

3106 errmsg("cursor \"%s\" does not exist", name)));

3107 if (portal->tupDesc == NULL)

3109 (errcode(ERRCODE_INVALID_CURSOR_STATE),

3110 errmsg("portal \"%s\" does not return tuples", name)));

3111

3114 tableforest, targetns));

3116

3118}

3119

3120

3123{

3129 const char *xmlschema;

3130

3133 tableforest, targetns);

3135

3137 xmlschema, nulls, tableforest,

3138 targetns, true)));

3139}

3140

3141

3144{

3149

3150 const char *xmlschema;

3153

3155

3157 elog(ERROR, "SPI_prepare(\"%s\") failed", query);

3158

3160 elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);

3161

3163 InvalidOid, nulls, tableforest, targetns));

3166

3168 xmlschema, nulls, tableforest,

3169 targetns, true)));

3170}

3171

3172

3173

3174

3175

3176

3177

3180 bool tableforest, const char *targetns, bool top_level)

3181{

3183 char *xmlsn;

3184 List *relid_list;

3186

3188 true, false);

3190

3193

3194 if (xmlschema)

3196

3198

3200

3201 foreach(cell, relid_list)

3202 {

3205

3207 targetns, false);

3208

3211 }

3212

3214

3216

3217 return result;

3218}

3219

3220

3223{

3228

3229 char *schemaname;

3231

3234

3236 nulls, tableforest, targetns, true)));

3237}

3238

3239

3240

3241

3242

3243static void

3245{

3247 "<xsd:schema\n"

3249 if (strlen(targetns) > 0)

3251 "\n"

3252 " targetNamespace=\"%s\"\n"

3253 " elementFormDefault=\"qualified\"",

3254 targetns);

3256 ">\n\n");

3257}

3258

3259

3260static void

3262{

3264}

3265

3266

3269 bool tableforest, const char *targetns)

3270{

3272 List *relid_list;

3273 List *tupdesc_list;

3276

3278

3280

3282

3284

3286

3287 tupdesc_list = NIL;

3288 foreach(cell, relid_list)

3289 {

3291

3295 }

3296

3299

3302 nulls, tableforest, targetns));

3303

3305

3307

3308 return result;

3309}

3310

3311

3314{

3319

3321 nulls, tableforest, targetns)));

3322}

3323

3324

3327{

3332 char *schemaname;

3335

3338

3340 tableforest, targetns);

3341

3343 xmlschema->data, nulls,

3344 tableforest, targetns, true)));

3345}

3346

3347

3348

3349

3350

3351

3352

3355 bool tableforest, const char *targetns)

3356{

3358 List *nspid_list;

3360 char *xmlcn;

3361

3363 true, false);

3365

3368

3369 if (xmlschema)

3371

3373

3375

3376 foreach(cell, nspid_list)

3377 {

3380

3382 tableforest, targetns, false);

3383

3386 }

3387

3389

3391

3392 return result;

3393}

3394

3395

3398{

3402

3404 tableforest, targetns)));

3405}

3406

3407

3410 const char *targetns)

3411{

3412 List *relid_list;

3413 List *nspid_list;

3414 List *tupdesc_list;

3417

3419

3421

3423

3426

3427 tupdesc_list = NIL;

3428 foreach(cell, relid_list)

3429 {

3431

3435 }

3436

3439

3442

3444

3446

3447 return result;

3448}

3449

3450

3453{

3457

3459 tableforest, targetns)));

3460}

3461

3462

3465{

3470

3472

3474 nulls, tableforest, targetns)));

3475}

3476

3477

3478

3479

3480

3481

3482static char *

3484{

3486

3488

3489 if (a)

3492 if (b)

3495 if (c)

3498 if (d)

3501

3502 return result.data;

3503}

3504

3505

3506

3507

3508

3509

3510

3511

3512

3513static const char *

3515 bool tableforest, const char *targetns)

3516{

3517 int i;

3518 char *xmltn;

3519 char *tabletypename;

3520 char *rowtypename;

3522

3524

3526 {

3529

3532 elog(ERROR, "cache lookup failed for relation %u", relid);

3534

3536 true, false);

3537

3541 NameStr(reltuple->relname));

3542

3546 NameStr(reltuple->relname));

3547

3549 }

3550 else

3551 {

3552 if (tableforest)

3553 xmltn = "row";

3554 else

3555 xmltn = "table";

3556

3557 tabletypename = "TableType";

3558 rowtypename = "RowType";

3559 }

3560

3562

3565

3567 "<xsd:complexType name=\"%s\">\n"

3568 " xsd:sequence\n",

3569 rowtypename);

3570

3571 for (i = 0; i < tupdesc->natts; i++)

3572 {

3574

3575 if (att->attisdropped)

3576 continue;

3578 " <xsd:element name=\"%s\" type=\"%s\"%s>\n",

3580 true, false),

3582 nulls ? " nillable=\"true\"" : " minOccurs=\"0\"");

3583 }

3584

3586 " \n"

3587 "\n\n");

3588

3589 if (!tableforest)

3590 {

3592 "<xsd:complexType name=\"%s\">\n"

3593 " xsd:sequence\n"

3594 " <xsd:element name=\"row\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n"

3595 " \n"

3596 "\n\n",

3597 tabletypename, rowtypename);

3598

3600 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",

3601 xmltn, tabletypename);

3602 }

3603 else

3605 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",

3606 xmltn, rowtypename);

3607

3609

3610 return result.data;

3611}

3612

3613

3614

3615

3616

3617

3618static const char *

3620 bool tableforest, const char *targetns)

3621{

3623 char *nspname;

3624 char *xmlsn;

3625 char *schematypename;

3628

3631

3633

3635

3638 nspname,

3639 NULL);

3640

3642 "<xsd:complexType name=\"%s\">\n", schematypename);

3643 if (!tableforest)

3645 " xsd:all\n");

3646 else

3648 " xsd:sequence\n");

3649

3650 foreach(cell, relid_list)

3651 {

3657 nspname,

3659

3660 if (!tableforest)

3662 " <xsd:element name=\"%s\" type=\"%s\"/>\n",

3663 xmltn, tabletypename);

3664 else

3666 " <xsd:element name=\"%s\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n",

3667 xmltn, tabletypename);

3668 }

3669

3670 if (!tableforest)

3672 " \n");

3673 else

3675 " \n");

3677 "\n\n");

3678

3680 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",

3681 xmlsn, schematypename);

3682

3683 return result.data;

3684}

3685

3686

3687

3688

3689

3690

3691static const char *

3693 bool tableforest, const char *targetns)

3694{

3696 char *xmlcn;

3697 char *catalogtypename;

3700

3702

3704

3706

3709 NULL,

3710 NULL);

3711

3713 "<xsd:complexType name=\"%s\">\n", catalogtypename);

3715 " xsd:all\n");

3716

3717 foreach(cell, nspid_list)

3718 {

3724 nspname,

3725 NULL);

3726

3728 " <xsd:element name=\"%s\" type=\"%s\"/>\n",

3729 xmlsn, schematypename);

3730 }

3731

3733 " \n");

3735 "\n\n");

3736

3738 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",

3739 xmlcn, catalogtypename);

3740

3741 return result.data;

3742}

3743

3744

3745

3746

3747

3748static const char *

3750{

3752

3754

3755 switch (typeoid)

3756 {

3757 case BPCHAROID:

3758 if (typmod == -1)

3760 else

3762 break;

3763 case VARCHAROID:

3764 if (typmod == -1)

3766 else

3768 break;

3769 case NUMERICOID:

3770 if (typmod == -1)

3772 else

3774 ((typmod - VARHDRSZ) >> 16) & 0xffff,

3775 (typmod - VARHDRSZ) & 0xffff);

3776 break;

3777 case INT4OID:

3779 break;

3780 case INT2OID:

3782 break;

3783 case INT8OID:

3785 break;

3786 case FLOAT4OID:

3788 break;

3789 case FLOAT8OID:

3791 break;

3792 case BOOLOID:

3794 break;

3795 case TIMEOID:

3796 if (typmod == -1)

3798 else

3800 break;

3801 case TIMETZOID:

3802 if (typmod == -1)

3804 else

3806 break;

3807 case TIMESTAMPOID:

3808 if (typmod == -1)

3810 else

3812 break;

3813 case TIMESTAMPTZOID:

3814 if (typmod == -1)

3816 else

3818 break;

3819 case DATEOID:

3821 break;

3822 case XMLOID:

3824 break;

3825 default:

3826 {

3829

3832 elog(ERROR, "cache lookup failed for type %u", typeoid);

3834

3839 NameStr(typtuple->typname)));

3840

3842 }

3843 }

3844

3845 return result.data;

3846}

3847

3848

3849

3850

3851

3852

3853static const char *

3855{

3856 List *uniquetypes = NIL;

3857 int i;

3860

3861

3862 foreach(cell0, tupdesc_list)

3863 {

3865

3866 for (i = 0; i < tupdesc->natts; i++)

3867 {

3869

3870 if (att->attisdropped)

3871 continue;

3873 }

3874 }

3875

3876

3877 foreach(cell0, uniquetypes)

3878 {

3881

3882 if (basetypid != typid)

3884 }

3885

3886

3888

3889 foreach(cell0, uniquetypes)

3890 {

3893 -1));

3894 }

3895

3896 return result.data;

3897}

3898

3899

3900

3901

3902

3903

3904

3905

3906

3907

3908static const char *

3910{

3913

3915

3916 if (typeoid == XMLOID)

3917 {

3919 "<xsd:complexType mixed=\"true\">\n"

3920 " xsd:sequence\n"

3921 " <xsd:any name=\"element\" minOccurs=\"0\" maxOccurs=\"unbounded\" processContents=\"skip\"/>\n"

3922 " \n"

3923 "\n");

3924 }

3925 else

3926 {

3928 "<xsd:simpleType name=\"%s\">\n", typename);

3929

3930 switch (typeoid)

3931 {

3932 case BPCHAROID:

3933 case VARCHAROID:

3934 case TEXTOID:

3936 " <xsd:restriction base=\"xsd:string\">\n");

3937 if (typmod != -1)

3939 " <xsd:maxLength value=\"%d\"/>\n",

3942 break;

3943

3944 case BYTEAOID:

3946 " <xsd:restriction base=\"xsd:%s\">\n"

3947 " \n",

3949 break;

3950

3951 case NUMERICOID:

3952 if (typmod != -1)

3954 " <xsd:restriction base=\"xsd:decimal\">\n"

3955 " <xsd:totalDigits value=\"%d\"/>\n"

3956 " <xsd:fractionDigits value=\"%d\"/>\n"

3957 " \n",

3958 ((typmod - VARHDRSZ) >> 16) & 0xffff,

3959 (typmod - VARHDRSZ) & 0xffff);

3960 break;

3961

3962 case INT2OID:

3964 " <xsd:restriction base=\"xsd:short\">\n"

3965 " <xsd:maxInclusive value=\"%d\"/>\n"

3966 " <xsd:minInclusive value=\"%d\"/>\n"

3967 " \n",

3968 SHRT_MAX, SHRT_MIN);

3969 break;

3970

3971 case INT4OID:

3973 " <xsd:restriction base=\"xsd:int\">\n"

3974 " <xsd:maxInclusive value=\"%d\"/>\n"

3975 " <xsd:minInclusive value=\"%d\"/>\n"

3976 " \n",

3977 INT_MAX, INT_MIN);

3978 break;

3979

3980 case INT8OID:

3982 " <xsd:restriction base=\"xsd:long\">\n"

3983 " <xsd:maxInclusive value=\"" INT64_FORMAT "\"/>\n"

3984 " <xsd:minInclusive value=\"" INT64_FORMAT "\"/>\n"

3985 " \n",

3988 break;

3989

3990 case FLOAT4OID:

3992 " <xsd:restriction base=\"xsd:float\">\n");

3993 break;

3994

3995 case FLOAT8OID:

3997 " <xsd:restriction base=\"xsd:double\">\n");

3998 break;

3999

4000 case BOOLOID:

4002 " <xsd:restriction base=\"xsd:boolean\">\n");

4003 break;

4004

4005 case TIMEOID:

4006 case TIMETZOID:

4007 {

4008 const char *tz = (typeoid == TIMETZOID ? "(\\+|-)\\p{Nd}{2}:\\p{Nd}{2}" : "");

4009

4010 if (typmod == -1)

4012 " <xsd:restriction base=\"xsd:time\">\n"

4013 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}(.\\p{Nd}+)?%s\"/>\n"

4014 " \n", tz);

4015 else if (typmod == 0)

4017 " <xsd:restriction base=\"xsd:time\">\n"

4018 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"

4019 " \n", tz);

4020 else

4022 " <xsd:restriction base=\"xsd:time\">\n"

4023 " <xsd:pattern value=\"\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}.\\p{Nd}{%d}%s\"/>\n"

4024 " \n", typmod - VARHDRSZ, tz);

4025 break;

4026 }

4027

4028 case TIMESTAMPOID:

4029 case TIMESTAMPTZOID:

4030 {

4031 const char *tz = (typeoid == TIMESTAMPTZOID ? "(\\+|-)\\p{Nd}{2}:\\p{Nd}{2}" : "");

4032

4033 if (typmod == -1)

4035 " <xsd:restriction base=\"xsd:dateTime\">\n"

4036 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}(.\\p{Nd}+)?%s\"/>\n"

4037 " \n", tz);

4038 else if (typmod == 0)

4040 " <xsd:restriction base=\"xsd:dateTime\">\n"

4041 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"

4042 " \n", tz);

4043 else

4045 " <xsd:restriction base=\"xsd:dateTime\">\n"

4046 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}.\\p{Nd}{%d}%s\"/>\n"

4047 " \n", typmod - VARHDRSZ, tz);

4048 break;

4049 }

4050

4051 case DATEOID:

4053 " <xsd:restriction base=\"xsd:date\">\n"

4054 " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}\"/>\n"

4055 " \n");

4056 break;

4057

4058 default:

4059 if (get_typtype(typeoid) == TYPTYPE_DOMAIN)

4060 {

4061 Oid base_typeoid;

4062 int32 base_typmod = -1;

4063

4065

4067 " <xsd:restriction base=\"%s\"/>\n",

4069 }

4070 break;

4071 }

4073 }

4074

4075 return result.data;

4076}

4077

4078

4079

4080

4081

4082

4083static void

4085 bool nulls, bool tableforest,

4086 const char *targetns, bool top_level)

4087{

4088 int i;

4089 char *xmltn;

4090

4091 if (tablename)

4093 else

4094 {

4095 if (tableforest)

4096 xmltn = "row";

4097 else

4098 xmltn = "table";

4099 }

4100

4101 if (tableforest)

4103 else

4105

4107 {

4108 char *colname;

4110 bool isnull;

4111

4113 true, false);

4116 i,

4117 &isnull);

4118 if (isnull)

4119 {

4120 if (nulls)

4121 appendStringInfo(result, " <%s xsi:nil=\"true\"/>\n", colname);

4122 }

4123 else

4125 colname,

4128 colname);

4129 }

4130

4131 if (tableforest)

4132 {

4135 }

4136 else

4138}

4139

4140

4141

4142

4143

4144

4145#ifdef USE_LIBXML

4146

4147

4148

4149

4150

4151

4152

4153static text *

4155{

4157

4158 if (cur->type != XML_ATTRIBUTE_NODE && cur->type != XML_TEXT_NODE)

4159 {

4160 void (*volatile nodefree) (xmlNodePtr) = NULL;

4161 volatile xmlBufferPtr buf = NULL;

4162 volatile xmlNodePtr cur_copy = NULL;

4163

4165 {

4166 int bytes;

4167

4168 buf = xmlBufferCreate();

4169 if (buf == NULL || xmlerrcxt->err_occurred)

4171 "could not allocate xmlBuffer");

4172

4173

4174

4175

4176

4177

4178

4179

4180

4181

4182

4183

4184

4185 cur_copy = xmlCopyNode(cur, 1);

4186 if (cur_copy == NULL || xmlerrcxt->err_occurred)

4188 "could not copy node");

4189 nodefree = (cur_copy->type == XML_DOCUMENT_NODE) ?

4190 (void (*) (xmlNodePtr)) xmlFreeDoc : xmlFreeNode;

4191

4192 bytes = xmlNodeDump(buf, NULL, cur_copy, 0, 0);

4193 if (bytes == -1 || xmlerrcxt->err_occurred)

4195 "could not dump node");

4196

4197 result = xmlBuffer_to_xmltype(buf);

4198 }

4200 {

4201 if (nodefree)

4202 nodefree(cur_copy);

4203 if (buf)

4204 xmlBufferFree(buf);

4205 }

4207 }

4208 else

4209 {

4210 xmlChar *str;

4211

4212 str = xmlXPathCastNodeToString(cur);

4214 {

4215

4217

4220 }

4222 {

4223 xmlFree(str);

4224 }

4226 }

4227

4228 return result;

4229}

4230

4231

4232

4233

4234

4235

4236

4237

4238

4239

4240

4241

4242

4243static int

4244xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,

4247{

4248 int result = 0;

4250 Oid datumtype;

4251 char *result_str;

4252

4253 switch (xpathobj->type)

4254 {

4255 case XPATH_NODESET:

4256 if (xpathobj->nodesetval != NULL)

4257 {

4258 result = xpathobj->nodesetval->nodeNr;

4259 if (astate != NULL)

4260 {

4261 int i;

4262

4263 for (i = 0; i < result; i++)

4264 {

4265 datum = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],

4266 xmlerrcxt));

4269 }

4270 }

4271 }

4272 return result;

4273

4274 case XPATH_BOOLEAN:

4275 if (astate == NULL)

4276 return 1;

4278 datumtype = BOOLOID;

4279 break;

4280

4281 case XPATH_NUMBER:

4282 if (astate == NULL)

4283 return 1;

4285 datumtype = FLOAT8OID;

4286 break;

4287

4288 case XPATH_STRING:

4289 if (astate == NULL)

4290 return 1;

4292 datumtype = CSTRINGOID;

4293 break;

4294

4295 default:

4296 elog(ERROR, "xpath expression result type %d is unsupported",

4297 xpathobj->type);

4298 return 0;

4299 }

4300

4301

4306 return 1;

4307}

4308

4309

4310

4311

4312

4313

4314

4315

4316

4317

4318

4319

4320

4321static void

4324{

4326 volatile xmlParserCtxtPtr ctxt = NULL;

4327 volatile xmlDocPtr doc = NULL;

4328 volatile xmlXPathContextPtr xpathctx = NULL;

4329 volatile xmlXPathCompExprPtr xpathcomp = NULL;

4330 volatile xmlXPathObjectPtr xpathobj = NULL;

4331 char *datastr;

4333 int32 xpath_len;

4335 xmlChar *xpath_expr;

4336 size_t xmldecl_len = 0;

4337 int i;

4338 int ndim;

4339 Datum *ns_names_uris;

4340 bool *ns_names_uris_nulls;

4341 int ns_count;

4342

4343

4344

4345

4346

4347

4348

4349

4350

4351

4352 ndim = namespaces ? ARR_NDIM(namespaces) : 0;

4353 if (ndim != 0)

4354 {

4355 int *dims;

4356

4357 dims = ARR_DIMS(namespaces);

4358

4359 if (ndim != 2 || dims[1] != 2)

4361 (errcode(ERRCODE_DATA_EXCEPTION),

4362 errmsg("invalid array for XML namespace mapping"),

4363 errdetail("The array must be two-dimensional with length of the second axis equal to 2.")));

4364

4366

4368 &ns_names_uris, &ns_names_uris_nulls,

4369 &ns_count);

4370

4371 Assert((ns_count % 2) == 0);

4372 ns_count /= 2;

4373 }

4374 else

4375 {

4376 ns_names_uris = NULL;

4377 ns_names_uris_nulls = NULL;

4378 ns_count = 0;

4379 }

4380

4384 if (xpath_len == 0)

4386 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),

4387 errmsg("empty XPath expression")));

4388

4389 string = pg_xmlCharStrndup(datastr, len);

4390 xpath_expr = pg_xmlCharStrndup(VARDATA_ANY(xpath_expr_text), xpath_len);

4391

4392

4393

4394

4395

4396

4397

4398

4400 parse_xml_decl(string, &xmldecl_len, NULL, NULL, NULL);

4401

4403

4405 {

4406 xmlInitParser();

4407

4408

4409

4410

4411

4412 ctxt = xmlNewParserCtxt();

4413 if (ctxt == NULL || xmlerrcxt->err_occurred)

4415 "could not allocate parser context");

4416 doc = xmlCtxtReadMemory(ctxt, (char *) string + xmldecl_len,

4417 len - xmldecl_len, NULL, NULL, 0);

4418 if (doc == NULL || xmlerrcxt->err_occurred)

4420 "could not parse XML document");

4421 xpathctx = xmlXPathNewContext(doc);

4422 if (xpathctx == NULL || xmlerrcxt->err_occurred)

4424 "could not allocate XPath context");

4425 xpathctx->node = (xmlNodePtr) doc;

4426

4427

4428 if (ns_count > 0)

4429 {

4430 for (i = 0; i < ns_count; i++)

4431 {

4432 char *ns_name;

4433 char *ns_uri;

4434

4435 if (ns_names_uris_nulls[i * 2] ||

4436 ns_names_uris_nulls[i * 2 + 1])

4438 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),

4439 errmsg("neither namespace name nor URI may be null")));

4442 if (xmlXPathRegisterNs(xpathctx,

4443 (xmlChar *) ns_name,

4444 (xmlChar *) ns_uri) != 0)

4445 ereport(ERROR,

4446 (errmsg("could not register XML namespace with name \"%s\" and URI \"%s\"",

4447 ns_name, ns_uri)));

4448 }

4449 }

4450

4451

4452

4453

4454

4455

4456

4457 xpathcomp = xmlXPathCtxtCompile(xpathctx, xpath_expr);

4458 if (xpathcomp == NULL || xmlerrcxt->err_occurred)

4459 xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,

4460 "invalid XPath expression");

4461

4462

4463

4464

4465

4466

4467

4468

4469 xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);

4470 if (xpathobj == NULL || xmlerrcxt->err_occurred)

4471 xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,

4472 "could not create XPath object");

4473

4474

4475

4476

4477 if (res_nitems != NULL)

4478 *res_nitems = xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);

4479 else

4480 (void) xml_xpathobjtoxmlarray(xpathobj, astate, xmlerrcxt);

4481 }

4483 {

4484 if (xpathobj)

4485 xmlXPathFreeObject(xpathobj);

4486 if (xpathcomp)

4487 xmlXPathFreeCompExpr(xpathcomp);

4488 if (xpathctx)

4489 xmlXPathFreeContext(xpathctx);

4490 if (doc)

4491 xmlFreeDoc(doc);

4492 if (ctxt)

4493 xmlFreeParserCtxt(ctxt);

4494

4496

4498 }

4500

4501 xmlXPathFreeObject(xpathobj);

4502 xmlXPathFreeCompExpr(xpathcomp);

4503 xmlXPathFreeContext(xpathctx);

4504 xmlFreeDoc(doc);

4505 xmlFreeParserCtxt(ctxt);

4506

4508}

4509#endif

4510

4511

4512

4513

4514

4515

4516

4517

4520{

4521#ifdef USE_LIBXML

4526

4528 xpath_internal(xpath_expr_text, data, namespaces,

4529 NULL, astate);

4531#else

4533 return 0;

4534#endif

4535}

4536

4537

4538

4539

4540

4543{

4544#ifdef USE_LIBXML

4547 int res_nitems;

4548

4549 xpath_internal(xpath_expr_text, data, NULL,

4550 &res_nitems, NULL);

4551

4553#else

4555 return 0;

4556#endif

4557}

4558

4559

4560

4561

4562

4563

4566{

4567#ifdef USE_LIBXML

4571 int res_nitems;

4572

4573 xpath_internal(xpath_expr_text, data, namespaces,

4574 &res_nitems, NULL);

4575

4577#else

4579 return 0;

4580#endif

4581}

4582

4583

4584

4585

4586

4587#ifdef USE_LIBXML

4588static bool

4590{

4591 xmlDocPtr doc;

4593

4594

4595

4596

4597 doc = xml_parse(data, xmloption_arg, true,

4599 if (doc)

4600 xmlFreeDoc(doc);

4601

4603}

4604#endif

4605

4608{

4609#ifdef USE_LIBXML

4611

4613#else

4615 return 0;

4616#endif

4617}

4618

4621{

4622#ifdef USE_LIBXML

4624

4626#else

4628 return 0;

4629#endif

4630}

4631

4634{

4635#ifdef USE_LIBXML

4637

4639#else

4641 return 0;

4642#endif

4643}

4644

4645

4646

4647

4648

4649#ifdef USE_LIBXML

4650

4651

4652

4653

4654

4655static inline XmlTableBuilderData *

4657{

4658 XmlTableBuilderData *result;

4659

4661 elog(ERROR, "%s called with invalid TableFuncScanState", fname);

4662 result = (XmlTableBuilderData *) state->opaque;

4663 if (result->magic != XMLTABLE_CONTEXT_MAGIC)

4664 elog(ERROR, "%s called with invalid TableFuncScanState", fname);

4665

4666 return result;

4667}

4668#endif

4669

4670

4671

4672

4673

4674

4675

4676

4677

4678

4679

4680

4681static void

4683{

4684#ifdef USE_LIBXML

4685 volatile xmlParserCtxtPtr ctxt = NULL;

4686 XmlTableBuilderData *xtCxt;

4688

4689 xtCxt = palloc0(sizeof(XmlTableBuilderData));

4690 xtCxt->magic = XMLTABLE_CONTEXT_MAGIC;

4691 xtCxt->natts = natts;

4692 xtCxt->xpathscomp = palloc0(sizeof(xmlXPathCompExprPtr) * natts);

4693

4695

4697 {

4698 xmlInitParser();

4699

4700 ctxt = xmlNewParserCtxt();

4701 if (ctxt == NULL || xmlerrcxt->err_occurred)

4703 "could not allocate parser context");

4704 }

4706 {

4707 if (ctxt != NULL)

4708 xmlFreeParserCtxt(ctxt);

4709

4711

4713 }

4715

4716 xtCxt->xmlerrcxt = xmlerrcxt;

4717 xtCxt->ctxt = ctxt;

4718

4719 state->opaque = xtCxt;

4720#else

4722#endif

4723}

4724

4725

4726

4727

4728

4729static void

4731{

4732#ifdef USE_LIBXML

4733 XmlTableBuilderData *xtCxt;

4735 char *str;

4736 xmlChar *xstr;

4737 int length;

4738 volatile xmlDocPtr doc = NULL;

4739 volatile xmlXPathContextPtr xpathcxt = NULL;

4740

4741 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetDocument");

4742

4743

4744

4745

4746

4748

4749 length = strlen(str);

4750 xstr = pg_xmlCharStrndup(str, length);

4751

4753 {

4754 doc = xmlCtxtReadMemory(xtCxt->ctxt, (char *) xstr, length, NULL, NULL, 0);

4755 if (doc == NULL || xtCxt->xmlerrcxt->err_occurred)

4756 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,

4757 "could not parse XML document");

4758 xpathcxt = xmlXPathNewContext(doc);

4759 if (xpathcxt == NULL || xtCxt->xmlerrcxt->err_occurred)

4761 "could not allocate XPath context");

4762 xpathcxt->node = (xmlNodePtr) doc;

4763 }

4765 {

4766 if (xpathcxt != NULL)

4767 xmlXPathFreeContext(xpathcxt);

4768 if (doc != NULL)

4769 xmlFreeDoc(doc);

4770

4772 }

4774

4775 xtCxt->doc = doc;

4776 xtCxt->xpathcxt = xpathcxt;

4777#else

4779#endif

4780}

4781

4782

4783

4784

4785

4786static void

4788{

4789#ifdef USE_LIBXML

4790 XmlTableBuilderData *xtCxt;

4791

4792 if (name == NULL)

4794 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

4795 errmsg("DEFAULT namespace is not supported")));

4796 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetNamespace");

4797

4798 if (xmlXPathRegisterNs(xtCxt->xpathcxt,

4799 pg_xmlCharStrndup(name, strlen(name)),

4800 pg_xmlCharStrndup(uri, strlen(uri))))

4801 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,

4802 "could not set XML namespace");

4803#else

4805#endif

4806}

4807

4808

4809

4810

4811

4812static void

4814{

4815#ifdef USE_LIBXML

4816 XmlTableBuilderData *xtCxt;

4817 xmlChar *xstr;

4818

4819 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetRowFilter");

4820

4821 if (*path == '\0')

4823 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),

4824 errmsg("row path filter must not be empty string")));

4825

4826 xstr = pg_xmlCharStrndup(path, strlen(path));

4827

4828

4829 Assert(xtCxt->xpathcxt != NULL);

4830

4831 xtCxt->xpathcomp = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);

4832 if (xtCxt->xpathcomp == NULL || xtCxt->xmlerrcxt->err_occurred)

4833 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,

4834 "invalid XPath expression");

4835#else

4837#endif

4838}

4839

4840

4841

4842

4843

4844static void

4846{

4847#ifdef USE_LIBXML

4848 XmlTableBuilderData *xtCxt;

4849 xmlChar *xstr;

4850

4852

4853 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableSetColumnFilter");

4854

4855 if (*path == '\0')

4857 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_XQUERY),

4858 errmsg("column path filter must not be empty string")));

4859

4860 xstr = pg_xmlCharStrndup(path, strlen(path));

4861

4862

4863 Assert(xtCxt->xpathcxt != NULL);

4864

4865 xtCxt->xpathscomp[colnum] = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);

4866 if (xtCxt->xpathscomp[colnum] == NULL || xtCxt->xmlerrcxt->err_occurred)

4867 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,

4868 "invalid XPath expression");

4869#else

4871#endif

4872}

4873

4874

4875

4876

4877

4878

4879static bool

4881{

4882#ifdef USE_LIBXML

4883 XmlTableBuilderData *xtCxt;

4884

4885 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableFetchRow");

4886

4887

4888 xmlSetStructuredErrorFunc(xtCxt->xmlerrcxt, xml_errorHandler);

4889

4890 if (xtCxt->xpathobj == NULL)

4891 {

4892 xtCxt->xpathobj = xmlXPathCompiledEval(xtCxt->xpathcomp, xtCxt->xpathcxt);

4893 if (xtCxt->xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)

4894 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,

4895 "could not create XPath object");

4896

4897 xtCxt->row_count = 0;

4898 }

4899

4900 if (xtCxt->xpathobj->type == XPATH_NODESET)

4901 {

4902 if (xtCxt->xpathobj->nodesetval != NULL)

4903 {

4904 if (xtCxt->row_count++ < xtCxt->xpathobj->nodesetval->nodeNr)

4905 return true;

4906 }

4907 }

4908

4909 return false;

4910#else

4912 return false;

4913#endif

4914}

4915

4916

4917

4918

4919

4920

4921

4922

4923

4926 Oid typid, int32 typmod, bool *isnull)

4927{

4928#ifdef USE_LIBXML

4930 XmlTableBuilderData *xtCxt;

4931 volatile xmlXPathObjectPtr xpathobj = NULL;

4932

4933 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableGetValue");

4934

4935 Assert(xtCxt->xpathobj &&

4936 xtCxt->xpathobj->type == XPATH_NODESET &&

4937 xtCxt->xpathobj->nodesetval != NULL);

4938

4939

4940 xmlSetStructuredErrorFunc(xtCxt->xmlerrcxt, xml_errorHandler);

4941

4942 *isnull = false;

4943

4944 Assert(xtCxt->xpathscomp[colnum] != NULL);

4945

4947 {

4948 xmlNodePtr cur;

4949 char *cstr = NULL;

4950

4951

4952 cur = xtCxt->xpathobj->nodesetval->nodeTab[xtCxt->row_count - 1];

4953 xtCxt->xpathcxt->node = cur;

4954

4955

4956 xpathobj = xmlXPathCompiledEval(xtCxt->xpathscomp[colnum], xtCxt->xpathcxt);

4957 if (xpathobj == NULL || xtCxt->xmlerrcxt->err_occurred)

4958 xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,

4959 "could not create XPath object");

4960

4961

4962

4963

4964

4965

4966

4967

4968 if (xpathobj->type == XPATH_NODESET)

4969 {

4970 int count = 0;

4971

4972 if (xpathobj->nodesetval != NULL)

4973 count = xpathobj->nodesetval->nodeNr;

4974

4975 if (xpathobj->nodesetval == NULL || count == 0)

4976 {

4977 *isnull = true;

4978 }

4979 else

4980 {

4981 if (typid == XMLOID)

4982 {

4983 text *textstr;

4985

4986

4988 for (int i = 0; i < count; i++)

4989 {

4990 textstr =

4991 xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],

4992 xtCxt->xmlerrcxt);

4993

4995 }

4996 cstr = str.data;

4997 }

4998 else

4999 {

5000 xmlChar *str;

5001

5002 if (count > 1)

5004 (errcode(ERRCODE_CARDINALITY_VIOLATION),

5005 errmsg("more than one value returned by column XPath expression")));

5006

5007 str = xmlXPathCastNodeSetToString(xpathobj->nodesetval);

5008 cstr = str ? xml_pstrdup_and_free(str) : "";

5009 }

5010 }

5011 }

5012 else if (xpathobj->type == XPATH_STRING)

5013 {

5014

5015 if (typid == XMLOID)

5016 cstr = escape_xml((char *) xpathobj->stringval);

5017 else

5018 cstr = (char *) xpathobj->stringval;

5019 }

5020 else if (xpathobj->type == XPATH_BOOLEAN)

5021 {

5022 char typcategory;

5023 bool typispreferred;

5024 xmlChar *str;

5025

5026

5028

5029 if (typcategory != TYPCATEGORY_NUMERIC)

5030 str = xmlXPathCastBooleanToString(xpathobj->boolval);

5031 else

5032 str = xmlXPathCastNumberToString(xmlXPathCastBooleanToNumber(xpathobj->boolval));

5033

5034 cstr = xml_pstrdup_and_free(str);

5035 }

5036 else if (xpathobj->type == XPATH_NUMBER)

5037 {

5038 xmlChar *str;

5039

5040 str = xmlXPathCastNumberToString(xpathobj->floatval);

5041 cstr = xml_pstrdup_and_free(str);

5042 }

5043 else

5044 elog(ERROR, "unexpected XPath object type %u", xpathobj->type);

5045

5046

5047

5048

5049

5050 Assert(cstr || *isnull);

5051

5052 if (!*isnull)

5054 cstr,

5055 state->typioparams[colnum],

5056 typmod);

5057 }

5059 {

5060 if (xpathobj != NULL)

5061 xmlXPathFreeObject(xpathobj);

5062 }

5064

5065 return result;

5066#else

5068 return 0;

5069#endif

5070}

5071

5072

5073

5074

5075

5076static void

5078{

5079#ifdef USE_LIBXML

5080 XmlTableBuilderData *xtCxt;

5081

5082 xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableDestroyOpaque");

5083

5084

5085 xmlSetStructuredErrorFunc(xtCxt->xmlerrcxt, xml_errorHandler);

5086

5087 if (xtCxt->xpathscomp != NULL)

5088 {

5089 int i;

5090

5091 for (i = 0; i < xtCxt->natts; i++)

5092 if (xtCxt->xpathscomp[i] != NULL)

5093 xmlXPathFreeCompExpr(xtCxt->xpathscomp[i]);

5094 }

5095

5096 if (xtCxt->xpathobj != NULL)

5097 xmlXPathFreeObject(xtCxt->xpathobj);

5098 if (xtCxt->xpathcomp != NULL)

5099 xmlXPathFreeCompExpr(xtCxt->xpathcomp);

5100 if (xtCxt->xpathcxt != NULL)

5101 xmlXPathFreeContext(xtCxt->xpathcxt);

5102 if (xtCxt->doc != NULL)

5103 xmlFreeDoc(xtCxt->doc);

5104 if (xtCxt->ctxt != NULL)

5105 xmlFreeParserCtxt(xtCxt->ctxt);

5106

5108

5109

5110 xtCxt->magic = 0;

5111 state->opaque = NULL;

5112

5113#else

5115#endif

5116}

#define PG_GETARG_ARRAYTYPE_P(n)

#define DatumGetArrayTypeP(X)

ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)

void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)

void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)

ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)

Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)

void j2date(int jd, int *year, int *month, int *day)

void EncodeDateTime(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)

void EncodeDateOnly(struct pg_tm *tm, int style, char *str)

int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)

#define TextDatumGetCString(d)

#define PointerIsValid(pointer)

#define OidIsValid(objectId)

#define TIMESTAMP_NOT_FINITE(j)

#define POSTGRES_EPOCH_JDATE

#define DATE_NOT_FINITE(j)

static DateADT DatumGetDateADT(Datum X)

char * get_database_name(Oid dbid)

int errmsg_internal(const char *fmt,...)

int errdetail_internal(const char *fmt,...)

int errdetail(const char *fmt,...)

int errhint(const char *fmt,...)

int errcode(int sqlerrcode)

int errmsg(const char *fmt,...)

#define errsave(context,...)

#define ereport(elevel,...)

Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)

char * OidOutputFunctionCall(Oid functionId, Datum val)

Datum Float8GetDatum(float8 X)

#define PG_GETARG_TEXT_PP(n)

#define PG_RETURN_BYTEA_P(x)

#define DatumGetByteaPP(X)

#define PG_GETARG_POINTER(n)

#define PG_RETURN_CSTRING(x)

#define DirectFunctionCall1(func, arg1)

#define PG_GETARG_CSTRING(n)

#define PG_GETARG_NAME(n)

#define PG_RETURN_TEXT_P(x)

#define PG_GETARG_INT32(n)

#define PG_GETARG_BOOL(n)

#define PG_RETURN_DATUM(x)

#define PG_RETURN_BOOL(x)

Assert(PointerIsAligned(start, uint64))

#define HeapTupleIsValid(tuple)

static void * GETSTRUCT(const HeapTupleData *tuple)

if(TABLE==NULL||TABLE_index==NULL)

List * lappend(List *list, void *datum)

List * lappend_oid(List *list, Oid datum)

List * list_append_unique_oid(List *list, Oid datum)

char * get_rel_name(Oid relid)

void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)

void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)

char get_typtype(Oid typid)

Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)

Oid getBaseType(Oid typid)

char * get_namespace_name(Oid nspid)

void get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)

#define type_is_array_domain(typid)

int GetDatabaseEncoding(void)

char * pg_any_to_server(const char *s, int len, int encoding)

unsigned char * pg_do_encoding_conversion(unsigned char *src, int len, int src_encoding, int dest_encoding)

void pg_unicode_to_server(pg_wchar c, unsigned char *s)

int pg_get_client_encoding(void)

char * pg_server_to_any(const char *s, int len, int encoding)

int pg_encoding_mb2wchar_with_len(int encoding, const char *from, pg_wchar *to, int len)

int pg_mblen(const char *mbstr)

char * MemoryContextStrdup(MemoryContext context, const char *string)

void * MemoryContextAlloc(MemoryContext context, Size size)

char * pstrdup(const char *in)

void * repalloc(void *pointer, Size size)

void pfree(void *pointer)

void * palloc0(Size size)

MemoryContext TopMemoryContext

MemoryContext CurrentMemoryContext

#define AllocSetContextCreate

#define ALLOCSET_DEFAULT_SIZES

Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)

Oid exprType(const Node *expr)

#define IsA(nodeptr, _type_)

FormData_pg_attribute * Form_pg_attribute

#define ERRCODE_DATA_CORRUPTED

FormData_pg_class * Form_pg_class

#define forboth(cell1, list1, cell2, list2)

#define list_make2(x1, x2)

FormData_pg_type * Form_pg_type

#define MAX_MULTIBYTE_CHAR_LEN

#define MAX_UNICODE_EQUIVALENT_STRING

#define pg_encoding_to_char

#define pg_char_to_encoding

int pg_strcasecmp(const char *s1, const char *s2)

size_t strnlen(const char *str, size_t maxlen)

int pg_strncasecmp(const char *s1, const char *s2, size_t n)

static bool DatumGetBool(Datum X)

static Datum PointerGetDatum(const void *X)

static Oid DatumGetObjectId(Datum X)

static Datum BoolGetDatum(bool X)

static Datum ObjectIdGetDatum(Oid X)

static char * DatumGetCString(Datum X)

static Datum CStringGetDatum(const char *X)

void pq_sendtext(StringInfo buf, const char *str, int slen)

void pq_begintypsend(StringInfo buf)

const char * pq_getmsgbytes(StringInfo msg, int datalen)

bytea * pq_endtypsend(StringInfo buf)

Datum regclassout(PG_FUNCTION_ARGS)

Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)

const char * SPI_result_code_string(int code)

SPITupleTable * SPI_tuptable

Portal SPI_cursor_find(const char *name)

void SPI_cursor_fetch(Portal portal, bool forward, long count)

Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)

SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)

void SPI_cursor_close(Portal portal)

void * SPI_palloc(Size size)

int SPI_execute(const char *src, bool read_only, long tcount)

Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)

char * SPI_fname(TupleDesc tupdesc, int fnumber)

void destroyStringInfo(StringInfo str)

StringInfo makeStringInfo(void)

void appendStringInfo(StringInfo str, const char *fmt,...)

void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)

void appendStringInfoString(StringInfo str, const char *s)

void appendStringInfoChar(StringInfo str, char ch)

void initStringInfo(StringInfo str)

StringInfoData * StringInfo

#define appendStringInfoCharMacro(str, ch)

void(* InitOpaque)(struct TableFuncScanState *state, int natts)

void ReleaseSysCache(HeapTuple tuple)

HeapTuple SearchSysCache1(int cacheId, Datum key1)

void table_close(Relation relation, LOCKMODE lockmode)

Relation table_open(Oid relationId, LOCKMODE lockmode)

TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)

static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)

struct TupleDescData * TupleDesc

static Timestamp DatumGetTimestamp(Datum X)

#define SET_VARSIZE(PTR, len)

#define VARSIZE_ANY_EXHDR(PTR)

static void appendStringInfoText(StringInfo str, const text *t)

text * cstring_to_text_with_len(const char *s, int len)

text * cstring_to_text(const char *s)

char * text_to_cstring(const text *t)

int pg_encoding_mblen(int encoding, const char *mbstr)

Datum xml_in(PG_FUNCTION_ARGS)

Datum cursor_to_xmlschema(PG_FUNCTION_ARGS)

Datum table_to_xml(PG_FUNCTION_ARGS)

Datum query_to_xmlschema(PG_FUNCTION_ARGS)

Datum database_to_xml(PG_FUNCTION_ARGS)

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

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

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

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

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

Datum texttoxml(PG_FUNCTION_ARGS)

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

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

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

Datum query_to_xml_and_xmlschema(PG_FUNCTION_ARGS)

Datum xmltotext(PG_FUNCTION_ARGS)

Datum schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)

Datum xmlexists(PG_FUNCTION_ARGS)

Datum xmltext(PG_FUNCTION_ARGS)

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

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

Datum database_to_xmlschema(PG_FUNCTION_ARGS)

static List * schema_get_xml_visible_tables(Oid nspid)

Datum schema_to_xmlschema(PG_FUNCTION_ARGS)

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

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

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

Datum xml_send(PG_FUNCTION_ARGS)

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

const TableFuncRoutine XmlTableRoutine

Datum xmlcomment(PG_FUNCTION_ARGS)

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

Datum xmlconcat2(PG_FUNCTION_ARGS)

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

static List * database_get_xml_visible_schemas(void)

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

xmltype * xmlconcat(List *args)

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

char * escape_xml(const char *str)

Datum xml_is_well_formed_document(PG_FUNCTION_ARGS)

Datum query_to_xml(PG_FUNCTION_ARGS)

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

static xmltype * stringinfo_to_xmltype(StringInfo buf)

Datum xml_is_well_formed_content(PG_FUNCTION_ARGS)

#define XML_VISIBLE_SCHEMAS

static List * database_get_xml_visible_tables(void)

bool xml_is_document(xmltype *arg)

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

Datum table_to_xml_and_xmlschema(PG_FUNCTION_ARGS)

Datum xmlvalidate(PG_FUNCTION_ARGS)

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

static xmltype * cstring_to_xmltype(const char *string)

static List * query_to_oid_list(const char *query)

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

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

static void XmlTableDestroyOpaque(struct TableFuncScanState *state)

static const char * map_sql_typecoll_to_xmlschema_types(List *tupdesc_list)

#define PG_XML_DEFAULT_VERSION

Datum table_to_xmlschema(PG_FUNCTION_ARGS)

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

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

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

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

Datum schema_to_xml(PG_FUNCTION_ARGS)

char * map_xml_name_to_sql_identifier(const char *name)

Datum database_to_xml_and_xmlschema(PG_FUNCTION_ARGS)

static bool XmlTableFetchRow(struct TableFuncScanState *state)

Datum cursor_to_xml(PG_FUNCTION_ARGS)

Datum xpath_exists(PG_FUNCTION_ARGS)

Datum xml_is_well_formed(PG_FUNCTION_ARGS)

static char * _SPI_strdup(const char *s)

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

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

Datum xml_out(PG_FUNCTION_ARGS)

Datum xml_recv(PG_FUNCTION_ARGS)

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

Datum xpath(PG_FUNCTION_ARGS)

static void xsd_schema_element_end(StringInfo result)

@ XML_STANDALONE_NO_VALUE

struct PgXmlErrorContext PgXmlErrorContext

PgXmlErrorContext * pg_xml_init(PgXmlStrictness strictness)

#define PG_RETURN_XML_P(x)

void xml_ereport(PgXmlErrorContext *errcxt, int level, int sqlcode, const char *msg)

bool pg_xml_error_occurred(PgXmlErrorContext *errcxt)

static xmltype * DatumGetXmlP(Datum X)

void pg_xml_done(PgXmlErrorContext *errcxt, bool isError)

#define PG_GETARG_XML_P(n)

void pg_xml_init_library(void)

@ PG_XML_STRICTNESS_LEGACY

@ PG_XML_STRICTNESS_WELLFORMED