pg_xpath_returnvalue.v3.patch
application/octet-stream
Filename: pg_xpath_returnvalue.v3.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v3
| File | + | − |
|---|---|---|
| src/backend/utils/adt/xml.c | 0 | 0 |
| src/test/regress/expected/xml_1.out | 0 | 0 |
| src/test/regress/expected/xml.out | 0 | 0 |
| src/test/regress/sql/xml.sql | 0 | 0 |
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 702b9e3..105d2ac 100644
*** a/src/backend/utils/adt/xml.c
--- b/src/backend/utils/adt/xml.c
*************** static bool print_xml_decl(StringInfo bu
*** 109,114 ****
--- 109,116 ----
static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg,
bool preserve_whitespace, int encoding);
static text *xml_xmlnodetoxmltype(xmlNodePtr cur);
+ static int xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
+ ArrayBuildState **astate);
#endif /* USE_LIBXML */
static StringInfo query_to_xml_internal(const char *query, char *tablename,
*************** xml_xmlnodetoxmltype(xmlNodePtr cur)
*** 3293,3298 ****
--- 3295,3391 ----
return result;
}
+
+ /*
+ * Convert XML XPath object (the result of evaluating a XPath expression)
+ * to an array of xml values. Nodesets are converted to an array containg
+ * the node's textual representation. Primitive values (float, double, string)
+ * are converted to a single-element array containg the value's string
+ * representation.
+ */
+ static int
+ xml_xpathobjtoxmlarray(xmlXPathObjectPtr xpathobj,
+ ArrayBuildState **astate)
+ {
+ int i;
+ Datum datum;
+ char* result_str;
+
+ if (astate != NULL)
+ *astate = NULL;
+
+ switch (xpathobj->type) {
+ /* For node sets, we append all the node's textual representations
+ * to the array
+ */
+ case XPATH_NODESET:
+ if (xpathobj->nodesetval != NULL)
+ {
+ int nitems = 0;
+
+ for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
+ {
+ ++nitems;
+ if (astate == NULL)
+ continue;
+
+ datum = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
+ *astate = accumArrayResult(*astate, datum,
+ false, XMLOID,
+ CurrentMemoryContext);
+ }
+
+ return nitems;
+ }
+ else
+ {
+ return 0;
+ }
+
+ /* For scalar values, we encode the value in XML and return a
+ * single-element array
+ */
+
+ case XPATH_BOOLEAN:
+ if (astate == NULL)
+ return 1;
+
+ datum = BoolGetDatum(xpathobj->boolval);
+ result_str = map_sql_value_to_xml_value(datum, BOOLOID, true);
+ goto single;
+
+ case XPATH_NUMBER:
+ if (astate == NULL)
+ return 1;
+
+ datum = Float8GetDatum(xpathobj->floatval);
+ result_str = map_sql_value_to_xml_value(datum, FLOAT8OID, true);
+ goto single;
+
+ case XPATH_STRING:
+ if (astate == NULL)
+ return 1;
+
+ datum = CStringGetDatum((char *) xpathobj->stringval);
+ result_str = map_sql_value_to_xml_value(datum, CSTRINGOID, true);
+ goto single;
+
+ single:
+ datum = PointerGetDatum(cstring_to_xmltype(result_str));
+ *astate = accumArrayResult(*astate, datum,
+ false, XMLOID,
+ CurrentMemoryContext);
+ return 1;
+
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("xpath expression result type %d is unsupported",
+ xpathobj->type)));
+
+ return 0; /* Prevent compiler warning */
+ }
+ }
#endif
*************** xpath_internal(text *xpath_expr_text, xm
*** 3447,3473 ****
if (xpathobj == NULL) /* TODO: reason? */
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
"could not create XPath object");
!
! /* return empty array in cases when nothing is found */
! if (xpathobj->nodesetval == NULL)
! *res_nitems = 0;
else
! *res_nitems = xpathobj->nodesetval->nodeNr;
!
! if (*res_nitems && astate)
! {
! *astate = NULL;
! for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
! {
! Datum elem;
! bool elemisnull = false;
!
! elem = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
! *astate = accumArrayResult(*astate, elem,
! elemisnull, XMLOID,
! CurrentMemoryContext);
! }
! }
}
PG_CATCH();
{
--- 3540,3550 ----
if (xpathobj == NULL) /* TODO: reason? */
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
"could not create XPath object");
!
! if (res_nitems != NULL)
! *res_nitems = xml_xpathobjtoxmlarray(xpathobj, astate);
else
! xml_xpathobjtoxmlarray(xpathobj, astate);
}
PG_CATCH();
{
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index eaa5a74..d279522 100644
*** a/src/test/regress/expected/xml.out
--- b/src/test/regress/expected/xml.out
*************** SELECT xpath('//b', '<a>one <b>two</b> t
*** 502,507 ****
--- 502,543 ----
{<b>two</b>,<b>etc</b>}
(1 row)
+ SELECT xpath('''<<invalid>>''', '<root/>');
+ xpath
+ ---------------------------
+ {<<invalid>>}
+ (1 row)
+
+ SELECT xpath('count(//*)', '<root><sub/><sub/></root>');
+ xpath
+ -------
+ {3}
+ (1 row)
+
+ SELECT xpath('count(//*)=0', '<root><sub/><sub/></root>');
+ xpath
+ ---------
+ {false}
+ (1 row)
+
+ SELECT xpath('count(//*)=3', '<root><sub/><sub/></root>');
+ xpath
+ --------
+ {true}
+ (1 row)
+
+ SELECT xpath('name(/*)', '<root><sub/><sub/></root>');
+ xpath
+ --------
+ {root}
+ (1 row)
+
+ SELECT xpath('/nosuchtag', '<root/>');
+ xpath
+ -------
+ {}
+ (1 row)
+
-- Test xmlexists and xpath_exists
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
xmlexists
*************** SELECT xmlexists('//town[text() = ''Cwmb
*** 515,520 ****
--- 551,562 ----
t
(1 row)
+ SELECT xmlexists('count(/nosuchtag)' PASSING BY REF '<root/>');
+ xmlexists
+ -----------
+ t
+ (1 row)
+
SELECT xpath_exists('//town[text() = ''Toronto'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
xpath_exists
--------------
*************** SELECT xpath_exists('//town[text() = ''C
*** 527,532 ****
--- 569,580 ----
t
(1 row)
+ SELECT xpath_exists('count(/nosuchtag)', '<root/>'::xml);
+ xpath_exists
+ --------------
+ t
+ (1 row)
+
INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
INSERT INTO xmltest VALUES (5, '<menu><beers><name>Molson</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
INSERT INTO xmltest VALUES (6, '<myns:menu xmlns:myns="http://myns.com"><myns:beers><myns:name>Budvar</myns:name><myns:cost>free</myns:cost><myns:name>Carling</myns:name><myns:cost>lots</myns:cost></myns:beers></myns:menu>'::xml);
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 711b435..dac98d2 100644
*** a/src/test/regress/expected/xml_1.out
--- b/src/test/regress/expected/xml_1.out
*************** LINE 1: SELECT xpath('//b', '<a>one <b>t
*** 456,461 ****
--- 456,497 ----
^
DETAIL: This functionality requires the server to be built with libxml support.
HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xpath('''<<invalid>>''', '<root/>');
+ ERROR: unsupported XML feature
+ LINE 1: SELECT xpath('''<<invalid>>''', '<root/>');
+ ^
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xpath('count(//*)', '<root><sub/><sub/></root>');
+ ERROR: unsupported XML feature
+ LINE 1: SELECT xpath('count(//*)', '<root><sub/><sub/></root>');
+ ^
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xpath('count(//*)=0', '<root><sub/><sub/></root>');
+ ERROR: unsupported XML feature
+ LINE 1: SELECT xpath('count(//*)=0', '<root><sub/><sub/></root>');
+ ^
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xpath('count(//*)=3', '<root><sub/><sub/></root>');
+ ERROR: unsupported XML feature
+ LINE 1: SELECT xpath('count(//*)=3', '<root><sub/><sub/></root>');
+ ^
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xpath('name(/*)', '<root><sub/><sub/></root>');
+ ERROR: unsupported XML feature
+ LINE 1: SELECT xpath('name(/*)', '<root><sub/><sub/></root>');
+ ^
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xpath('/nosuchtag', '<root/>');
+ ERROR: unsupported XML feature
+ LINE 1: SELECT xpath('/nosuchtag', '<root/>');
+ ^
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
-- Test xmlexists and xpath_exists
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
ERROR: unsupported XML feature
*************** LINE 1: ...sts('//town[text() = ''Cwmbra
*** 469,474 ****
--- 505,516 ----
^
DETAIL: This functionality requires the server to be built with libxml support.
HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlexists('count(/nosuchtag)' PASSING BY REF '<root/>');
+ ERROR: unsupported XML feature
+ LINE 1: ...LECT xmlexists('count(/nosuchtag)' PASSING BY REF '<root/>')...
+ ^
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
SELECT xpath_exists('//town[text() = ''Toronto'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
ERROR: unsupported XML feature
LINE 1: ...ELECT xpath_exists('//town[text() = ''Toronto'']','<towns><t...
*************** LINE 1: ...ELECT xpath_exists('//town[te
*** 481,486 ****
--- 523,534 ----
^
DETAIL: This functionality requires the server to be built with libxml support.
HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xpath_exists('count(/nosuchtag)', '<root/>'::xml);
+ ERROR: unsupported XML feature
+ LINE 1: SELECT xpath_exists('count(/nosuchtag)', '<root/>'::xml);
+ ^
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
ERROR: unsupported XML feature
LINE 1: INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</n...
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index 717a1e7..fd9c6a7 100644
*** a/src/test/regress/sql/xml.sql
--- b/src/test/regress/sql/xml.sql
*************** SELECT xpath('', '<!-- error -->');
*** 163,174 ****
--- 163,182 ----
SELECT xpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
+ SELECT xpath('''<<invalid>>''', '<root/>');
+ SELECT xpath('count(//*)', '<root><sub/><sub/></root>');
+ SELECT xpath('count(//*)=0', '<root><sub/><sub/></root>');
+ SELECT xpath('count(//*)=3', '<root><sub/><sub/></root>');
+ SELECT xpath('name(/*)', '<root><sub/><sub/></root>');
+ SELECT xpath('/nosuchtag', '<root/>');
-- Test xmlexists and xpath_exists
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
SELECT xmlexists('//town[text() = ''Cwmbran'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
+ SELECT xmlexists('count(/nosuchtag)' PASSING BY REF '<root/>');
SELECT xpath_exists('//town[text() = ''Toronto'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
SELECT xpath_exists('//town[text() = ''Cwmbran'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
+ SELECT xpath_exists('count(/nosuchtag)', '<root/>'::xml);
INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
INSERT INTO xmltest VALUES (5, '<menu><beers><name>Molson</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);