Skip to content

Commit fc568b9

Browse files
committed
Allow for arbitrary data types as content in XMLELEMENT. The original
coercion to type xml was a mistake. Escape values so they are valid XML character data.
1 parent 1b1c6ed commit fc568b9

File tree

5 files changed

+149
-19
lines changed

5 files changed

+149
-19
lines changed

src/backend/parser/parse_expr.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.205 2007/01/08 23:41:56 petere Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.206 2007/01/12 16:29:24 petere Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1455,10 +1455,6 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
14551455
newe = coerce_to_specific_type(pstate, newe, XMLOID,
14561456
"XMLCONCAT");
14571457
break;
1458-
case IS_XMLELEMENT:
1459-
newe = coerce_to_specific_type(pstate, newe, XMLOID,
1460-
"XMLELEMENT");
1461-
break;
14621458
case IS_XMLFOREST:
14631459
newe = coerce_to_specific_type(pstate, newe, XMLOID,
14641460
"XMLFOREST");
@@ -1488,7 +1484,7 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
14881484
newx->args = lappend(newx->args, newe);
14891485
i++;
14901486
}
1491-
1487+
14921488
return (Node *) newx;
14931489
}
14941490

src/backend/utils/adt/xml.c

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.14 2007/01/10 20:33:54 petere Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.15 2007/01/12 16:29:24 petere Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -35,12 +35,16 @@
3535
#include <libxml/xmlwriter.h>
3636
#endif /* USE_LIBXML */
3737

38+
#include "catalog/pg_type.h"
3839
#include "executor/executor.h"
3940
#include "fmgr.h"
4041
#include "libpq/pqformat.h"
4142
#include "mb/pg_wchar.h"
4243
#include "nodes/execnodes.h"
44+
#include "parser/parse_expr.h"
45+
#include "utils/array.h"
4346
#include "utils/builtins.h"
47+
#include "utils/lsyscache.h"
4448
#include "utils/memutils.h"
4549
#include "utils/xml.h"
4650

@@ -66,6 +70,8 @@ static void xml_ereport_by_code(int level, int sqlcode,
6670
static xmlChar *xml_text2xmlChar(text *in);
6771
static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespace);
6872

73+
static char *map_sql_value_to_xml_value(Datum value, Oid type);
74+
6975
#endif /* USE_LIBXML */
7076

7177
#define NO_XML_SUPPORT() \
@@ -284,13 +290,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
284290

285291
value = ExecEvalExpr(e, econtext, &isnull, NULL);
286292
if (!isnull)
287-
{
288-
/* we know the value is XML type */
289-
str = DatumGetCString(DirectFunctionCall1(xml_out,
290-
value));
291-
xmlTextWriterWriteRaw(writer, (xmlChar *) str);
292-
pfree(str);
293-
}
293+
xmlTextWriterWriteRaw(writer, (xmlChar *) map_sql_value_to_xml_value(value, exprType((Node *) e->expr)));
294294
}
295295

296296
xmlTextWriterEndElement(writer);
@@ -1258,3 +1258,87 @@ map_xml_name_to_sql_identifier(char *name)
12581258

12591259
return buf.data;
12601260
}
1261+
1262+
1263+
#ifdef USE_LIBXML
1264+
/*
1265+
* Map SQL value to XML value; see SQL/XML:2003 section 9.16.
1266+
*/
1267+
static char *
1268+
map_sql_value_to_xml_value(Datum value, Oid type)
1269+
{
1270+
StringInfoData buf;
1271+
1272+
initStringInfo(&buf);
1273+
1274+
if (is_array_type(type))
1275+
{
1276+
int i;
1277+
ArrayType *array;
1278+
Oid elmtype;
1279+
int16 elmlen;
1280+
bool elmbyval;
1281+
char elmalign;
1282+
1283+
array = DatumGetArrayTypeP(value);
1284+
1285+
/* TODO: need some code-fu here to remove this limitation */
1286+
if (ARR_NDIM(array) != 1)
1287+
ereport(ERROR,
1288+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1289+
errmsg("only supported for one-dimensional array")));
1290+
1291+
elmtype = ARR_ELEMTYPE(array);
1292+
get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign);
1293+
1294+
for (i = ARR_LBOUND(array)[0];
1295+
i < ARR_LBOUND(array)[0] + ARR_DIMS(array)[0];
1296+
i++)
1297+
{
1298+
Datum subval;
1299+
bool isnull;
1300+
1301+
subval = array_ref(array, 1, &i, -1, elmlen, elmbyval, elmalign, &isnull);
1302+
appendStringInfoString(&buf, "<element>");
1303+
appendStringInfoString(&buf, map_sql_value_to_xml_value(subval, elmtype));
1304+
appendStringInfoString(&buf, "</element>");
1305+
}
1306+
}
1307+
else
1308+
{
1309+
Oid typeOut;
1310+
bool isvarlena;
1311+
char *p, *str;
1312+
1313+
getTypeOutputInfo(type, &typeOut, &isvarlena);
1314+
str = OidOutputFunctionCall(typeOut, value);
1315+
1316+
if (type == XMLOID)
1317+
return str;
1318+
1319+
for (p = str; *p; p += pg_mblen(p))
1320+
{
1321+
switch (*p)
1322+
{
1323+
case '&':
1324+
appendStringInfo(&buf, "&amp;");
1325+
break;
1326+
case '<':
1327+
appendStringInfo(&buf, "&lt;");
1328+
break;
1329+
case '>':
1330+
appendStringInfo(&buf, "&gt;");
1331+
break;
1332+
case '\r':
1333+
appendStringInfo(&buf, "&#x0d;");
1334+
break;
1335+
default:
1336+
appendBinaryStringInfo(&buf, p, pg_mblen(p));
1337+
break;
1338+
}
1339+
}
1340+
}
1341+
1342+
return buf.data;
1343+
}
1344+
#endif /* USE_LIBXML */

src/test/regress/expected/xml.out

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,44 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
8383
<employee><name>linda</name><age>19</age><pay>100</pay></employee>
8484
(6 rows)
8585

86-
SELECT xmlelement(name wrong, 37);
87-
ERROR: argument of XMLELEMENT must be type xml, not type integer
8886
SELECT xmlelement(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
8987
ERROR: XML attribute name "a" appears more than once
88+
SELECT xmlelement(name num, 37);
89+
xmlelement
90+
---------------
91+
<num>37</num>
92+
(1 row)
93+
94+
SELECT xmlelement(name foo, text 'bar');
95+
xmlelement
96+
----------------
97+
<foo>bar</foo>
98+
(1 row)
99+
100+
SELECT xmlelement(name foo, xml 'bar');
101+
xmlelement
102+
----------------
103+
<foo>bar</foo>
104+
(1 row)
105+
106+
SELECT xmlelement(name foo, text 'b<a/>r');
107+
xmlelement
108+
-------------------------
109+
<foo>b&lt;a/&gt;r</foo>
110+
(1 row)
111+
112+
SELECT xmlelement(name foo, xml 'b<a/>r');
113+
xmlelement
114+
-------------------
115+
<foo>b<a/>r</foo>
116+
(1 row)
117+
118+
SELECT xmlelement(name foo, array[1, 2, 3]);
119+
xmlelement
120+
-------------------------------------------------------------------------
121+
<foo><element>1</element><element>2</element><element>3</element></foo>
122+
(1 row)
123+
90124
SELECT xmlparse(content 'abc');
91125
xmlparse
92126
----------

src/test/regress/expected/xml_1.out

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,20 @@ SELECT xmlelement(name element, xmlelement(name nested, 'stuff'));
4444
ERROR: no XML support in this installation
4545
SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
4646
ERROR: no XML support in this installation
47-
SELECT xmlelement(name wrong, 37);
48-
ERROR: no XML support in this installation
4947
SELECT xmlelement(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
5048
ERROR: no XML support in this installation
49+
SELECT xmlelement(name num, 37);
50+
ERROR: no XML support in this installation
51+
SELECT xmlelement(name foo, text 'bar');
52+
ERROR: no XML support in this installation
53+
SELECT xmlelement(name foo, xml 'bar');
54+
ERROR: no XML support in this installation
55+
SELECT xmlelement(name foo, text 'b<a/>r');
56+
ERROR: no XML support in this installation
57+
SELECT xmlelement(name foo, xml 'b<a/>r');
58+
ERROR: no XML support in this installation
59+
SELECT xmlelement(name foo, array[1, 2, 3]);
60+
ERROR: no XML support in this installation
5161
SELECT xmlparse(content 'abc');
5262
ERROR: no XML support in this installation
5363
SELECT xmlparse(content '<abc>x</abc>');

src/test/regress/sql/xml.sql

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,15 @@ SELECT xmlelement(name element, xmlelement(name nested, 'stuff'));
3737

3838
SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
3939

40-
SELECT xmlelement(name wrong, 37);
4140
SELECT xmlelement(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
4241

42+
SELECT xmlelement(name num, 37);
43+
SELECT xmlelement(name foo, text 'bar');
44+
SELECT xmlelement(name foo, xml 'bar');
45+
SELECT xmlelement(name foo, text 'b<a/>r');
46+
SELECT xmlelement(name foo, xml 'b<a/>r');
47+
SELECT xmlelement(name foo, array[1, 2, 3]);
48+
4349

4450
SELECT xmlparse(content 'abc');
4551
SELECT xmlparse(content '<abc>x</abc>');

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy