PostgreSQL Source Code: contrib/xml2/xpath.c Source File (original) (raw)
1
2
3
4
5
6
8
16
17
18
19#include <libxml/xpath.h>
20#include <libxml/tree.h>
21#include <libxml/xmlmemory.h>
22#include <libxml/xmlerror.h>
23#include <libxml/parserInternals.h>
24
26 .name = "xml2",
27 .version = PG_VERSION
28);
29
30
31
33
34
35
36typedef struct
37{
42
43
44
46 xmlChar *toptagname, xmlChar *septagname,
47 xmlChar *plainsep);
48
50 xmlChar *septag, xmlChar *plainsep);
51
53
56
58
59
60
61
62
63
64
65
68{
70
71
73
74
75
76
77 xmlInitParser();
78
79 return xmlerrcxt;
80}
81
82
83
84
86
89{
92 xmlChar *ts,
93 *tt;
94
96
97 tt = xmlEncodeSpecialChars(NULL, ts);
98
100
102
103 xmlFree(tt);
104
106}
107
108
109
110
111
112
113
114
115
116
117
118
119static xmlChar *
121 xmlChar *toptagname,
122 xmlChar *septagname,
123 xmlChar *plainsep)
124{
125 xmlBufferPtr buf;
126 xmlChar *result;
127 int i;
128
129 buf = xmlBufferCreate();
130
131 if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
132 {
133 xmlBufferWriteChar(buf, "<");
134 xmlBufferWriteCHAR(buf, toptagname);
135 xmlBufferWriteChar(buf, ">");
136 }
137 if (nodeset != NULL)
138 {
139 for (i = 0; i < nodeset->nodeNr; i++)
140 {
141 if (plainsep != NULL)
142 {
143 xmlBufferWriteCHAR(buf,
144 xmlXPathCastNodeToString(nodeset->nodeTab[i]));
145
146
147 if (i < (nodeset->nodeNr) - 1)
148 xmlBufferWriteChar(buf, (char *) plainsep);
149 }
150 else
151 {
152 if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
153 {
154 xmlBufferWriteChar(buf, "<");
155 xmlBufferWriteCHAR(buf, septagname);
156 xmlBufferWriteChar(buf, ">");
157 }
158 xmlNodeDump(buf,
159 nodeset->nodeTab[i]->doc,
160 nodeset->nodeTab[i],
161 1, 0);
162
163 if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
164 {
165 xmlBufferWriteChar(buf, "</");
166 xmlBufferWriteCHAR(buf, septagname);
167 xmlBufferWriteChar(buf, ">");
168 }
169 }
170 }
171 }
172
173 if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
174 {
175 xmlBufferWriteChar(buf, "</");
176 xmlBufferWriteCHAR(buf, toptagname);
177 xmlBufferWriteChar(buf, ">");
178 }
179 result = xmlStrdup(buf->content);
180 xmlBufferFree(buf);
181 return result;
182}
183
184
185
186
187
188static xmlChar *
190{
192}
193
194
195
196
197
198
199
201
204{
211 xmlXPathObjectPtr res;
213
215
217
219
221
223
224 if (xpres == NULL)
227}
228
229
230
231
232
234
237{
243 xmlXPathObjectPtr res;
245
247
249
251
253
255
256 if (xpres == NULL)
259}
260
261
263
266{
272 xmlXPathObjectPtr res;
274
276
277
278
279
280
281
282
283 xpath = (xmlChar *) palloc(pathsize + 9);
284 memcpy(xpath, "string(", 7);
286 xpath[pathsize + 7] = ')';
287 xpath[pathsize + 8] = '\0';
288
290
292
294
296
297 if (xpres == NULL)
300}
301
302
304
307{
312 xmlXPathObjectPtr res;
314
316
318
320
321 if (res == NULL)
323
324 fRes = xmlXPathCastToNumber(res);
325
327
328 if (xmlXPathIsNaN(fRes))
330
332}
333
334
336
339{
343 int bRes;
344 xmlXPathObjectPtr res;
346
348
350
352
353 if (res == NULL)
355
356 bRes = xmlXPathCastToBoolean(res);
357
359
361}
362
363
364
365
366
367static xmlXPathObjectPtr
369{
372 xmlXPathCompExprPtr comppath;
373
374 workspace->doctree = NULL;
375 workspace->ctxt = NULL;
376 workspace->res = NULL;
377
379
381 {
383 docsize, NULL, NULL,
384 XML_PARSE_NOENT);
385 if (workspace->doctree != NULL)
386 {
387 workspace->ctxt = xmlXPathNewContext(workspace->doctree);
388 workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
389
390
391 comppath = xmlXPathCtxtCompile(workspace->ctxt, xpath);
392 if (comppath == NULL)
393 xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
394 "XPath Syntax Error");
395
396
397 workspace->res = xmlXPathCompiledEval(comppath, workspace->ctxt);
398
399 xmlXPathFreeCompExpr(comppath);
400 }
401 }
403 {
405
407
409 }
411
412 if (workspace->res == NULL)
414
416
417 return workspace->res;
418}
419
420
421static void
423{
424 if (workspace->res)
425 xmlXPathFreeObject(workspace->res);
426 workspace->res = NULL;
427 if (workspace->ctxt)
428 xmlXPathFreeContext(workspace->ctxt);
429 workspace->ctxt = NULL;
431 xmlFreeDoc(workspace->doctree);
432 workspace->doctree = NULL;
433}
434
437 xmlChar *toptag,
438 xmlChar *septag,
439 xmlChar *plainsep)
440{
441 xmlChar *xpresstr;
443
444 if (res == NULL)
445 return NULL;
446
447 switch (res->type)
448 {
449 case XPATH_NODESET:
451 toptag,
452 septag, plainsep);
453 break;
454
455 case XPATH_STRING:
456 xpresstr = xmlStrdup(res->stringval);
457 break;
458
459 default:
460 elog(NOTICE, "unsupported XQuery result: %d", res->type);
461 xpresstr = xmlStrdup((const xmlChar *) "");
462 }
463
464
466
467
468 xmlFree(xpresstr);
469
470 return xpres;
471}
472
473
474
475
476
478
481{
482
488
489
493
494
497
499 xmlChar **xpaths;
500 char *pos;
501 const char *pathsep = "|";
502
503 int numpaths;
504 int ret;
506 int j;
507 int rownr;
508
509 bool had_values;
512 volatile xmlDocPtr doctree = NULL;
513
515
516
519 (errcode(ERRCODE_SYNTAX_ERROR),
520 errmsg("xpath_table must have at least one output column")));
521
522
523
524
525
526
527
528
529
531
533 xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *));
534
535
536
537
538
539
540 numpaths = 0;
541 pos = xpathset;
542 while (numpaths < (rsinfo->setDesc->natts - 1))
543 {
544 xpaths[numpaths++] = (xmlChar *) pos;
545 pos = strstr(pos, pathsep);
546 if (pos != NULL)
547 {
548 *pos = '\0';
549 pos++;
550 }
551 else
552 break;
553 }
554
555
557
558
559 appendStringInfo(&query_buf, "SELECT %s, %s FROM %s WHERE %s",
560 pkeyfield,
561 xmlfield,
563 condition);
564
566
568 elog(ERROR, "xpath_table: SPI execution failed for query %s",
569 query_buf.data);
570
573 spi_tupdesc = tuptable->tupdesc;
574
575
576
577
578
579
580 if (spi_tupdesc->natts != 2)
581 {
583 errmsg("expression returning multiple columns is not valid in parameter list"),
584 errdetail("Expected two columns in SPI result, got %d.", spi_tupdesc->natts)));
585 }
586
587
588
589
590
592
594 {
595
597
598 for (i = 0; i < proc; i++)
599 {
600 char *pkey;
601 char *xmldoc;
602 xmlXPathContextPtr ctxt;
603 xmlXPathObjectPtr res;
604 xmlChar *resstr;
605 xmlXPathCompExprPtr comppath;
607
608
609 spi_tuple = tuptable->vals[i];
610 pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
611 xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2);
612
613
614
615
616
617
620
621
623
624
625 if (xmldoc)
626 doctree = xmlReadMemory(xmldoc, strlen(xmldoc),
627 NULL, NULL,
628 XML_PARSE_NOENT);
629 else
630 doctree = NULL;
631
632 if (doctree == NULL)
633 {
634
638 }
639 else
640 {
641
642 rownr = 0;
643
644 do
645 {
646
647 had_values = false;
648 for (j = 0; j < numpaths; j++)
649 {
650 ctxt = xmlXPathNewContext(doctree);
651 ctxt->node = xmlDocGetRootElement(doctree);
652
653
654 comppath = xmlXPathCtxtCompile(ctxt, xpaths[j]);
655 if (comppath == NULL)
657 ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
658 "XPath Syntax Error");
659
660
661 res = xmlXPathCompiledEval(comppath, ctxt);
662 xmlXPathFreeCompExpr(comppath);
663
664 if (res != NULL)
665 {
666 switch (res->type)
667 {
668 case XPATH_NODESET:
669
670 if (res->nodesetval != NULL &&
671 rownr < res->nodesetval->nodeNr)
672 {
673 resstr = xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]);
674 had_values = true;
675 }
676 else
677 resstr = NULL;
678
679 break;
680
681 case XPATH_STRING:
682 resstr = xmlStrdup(res->stringval);
683 break;
684
685 default:
686 elog(NOTICE, "unsupported XQuery result: %d", res->type);
687 resstr = xmlStrdup((const xmlChar *) "");
688 }
689
690
691
692
693
694 values[j + 1] = (char *) resstr;
695 }
696 xmlXPathFreeContext(ctxt);
697 }
698
699
700 if (had_values)
701 {
705 }
706
707 rownr++;
708 } while (had_values);
709 }
710
711 if (doctree != NULL)
712 xmlFreeDoc(doctree);
713 doctree = NULL;
714
715 if (pkey)
717 if (xmldoc)
719 }
720 }
722 {
723 if (doctree != NULL)
724 xmlFreeDoc(doctree);
725
727
729 }
731
732 if (doctree != NULL)
733 xmlFreeDoc(doctree);
734
736
738
739
740
741
742
743
744
745
746 return (Datum) 0;
747}
static Datum values[MAXATTR]
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
#define PG_GETARG_TEXT_PP(n)
#define PG_RETURN_TEXT_P(x)
#define PG_RETURN_FLOAT4(x)
#define PG_RETURN_BOOL(x)
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
#define MAT_SRF_USE_EXPECTED_DESC
void heap_freetuple(HeapTuple htup)
void pfree(void *pointer)
SPITupleTable * SPI_tuptable
int SPI_exec(const char *src, long tcount)
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
void appendStringInfo(StringInfo str, const char *fmt,...)
void initStringInfo(StringInfo str)
Tuplestorestate * setResult
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
#define VARSIZE_ANY_EXHDR(PTR)
text * cstring_to_text(const char *s)
char * text_to_cstring(const text *t)
Datum xpath(PG_FUNCTION_ARGS)
struct PgXmlErrorContext PgXmlErrorContext
PgXmlErrorContext * pg_xml_init(PgXmlStrictness strictness)
void xml_ereport(PgXmlErrorContext *errcxt, int level, int sqlcode, const char *msg)
void pg_xml_done(PgXmlErrorContext *errcxt, bool isError)
@ PG_XML_STRICTNESS_LEGACY
static text * pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag, xmlChar *septag, xmlChar *plainsep)
Datum xpath_bool(PG_FUNCTION_ARGS)
Datum xpath_number(PG_FUNCTION_ARGS)
Datum xpath_table(PG_FUNCTION_ARGS)
static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
static xmlChar * pgxml_texttoxmlchar(text *textstring)
PgXmlErrorContext * pgxml_parser_init(PgXmlStrictness strictness)
Datum xpath_string(PG_FUNCTION_ARGS)
static void cleanup_workspace(xpath_workspace *workspace)
Datum xml_encode_special_chars(PG_FUNCTION_ARGS)
Datum xpath_list(PG_FUNCTION_ARGS)
static xmlChar * pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlChar *toptagname, xmlChar *septagname, xmlChar *plainsep)
PG_MODULE_MAGIC_EXT(.name="xml2",.version=PG_VERSION)
Datum xpath_nodeset(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(xml_encode_special_chars)