From 9b7304bc25f9e9d3e413b1efd84435ba7f4bd326 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 9 Jun 2009 22:00:57 +0000 Subject: [PATCH] Fix xmlattribute escaping XML special characters twice (bug #4822). Author: Itagaki Takahiro --- src/backend/executor/execQual.c | 4 ++-- src/backend/utils/adt/xml.c | 25 +++++++++++++++++-------- src/include/utils/xml.h | 4 ++-- src/test/regress/expected/xml.out | 6 ++++++ src/test/regress/expected/xml_1.out | 4 ++++ src/test/regress/sql/xml.sql | 1 + 6 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index c7bfe7c76c..65bf01c6a8 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.247 2009/06/04 18:33:07 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.248 2009/06/09 22:00:57 petere Exp $ * *------------------------------------------------------------------------- */ @@ -3243,7 +3243,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext, { appendStringInfo(&buf, "<%s>%s", argname, - map_sql_value_to_xml_value(value, exprType((Node *) e->expr)), + map_sql_value_to_xml_value(value, exprType((Node *) e->expr), true), argname); *isNull = false; } diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 57e9595af8..fca92e867d 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.89 2009/06/08 21:32:33 petere Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.90 2009/06/09 22:00:57 petere Exp $ * *------------------------------------------------------------------------- */ @@ -569,7 +569,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext) if (isnull) str = NULL; else - str = map_sql_value_to_xml_value(value, exprType((Node *) e->expr)); + str = map_sql_value_to_xml_value(value, exprType((Node *) e->expr), false); named_arg_strings = lappend(named_arg_strings, str); i++; } @@ -587,7 +587,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext) if (!isnull) { str = map_sql_value_to_xml_value(value, - exprType((Node *) e->expr)); + exprType((Node *) e->expr), true); arg_strings = lappend(arg_strings, str); } } @@ -1580,9 +1580,18 @@ map_xml_name_to_sql_identifier(char *name) /* * Map SQL value to XML value; see SQL/XML:2003 section 9.16. + * + * When xml_escape_strings is true, then certain characters in string + * values are replaced by entity references (< etc.), as specified + * in SQL/XML:2003 section 9.16 GR 8) ii). This is normally what is + * wanted. The false case is mainly useful when the resulting value + * is used with xmlTextWriterWriteAttribute() to write out an + * attribute, because that function does the escaping itself. The SQL + * standard of 2003 is somewhat buggy in this regard, so we do our + * best to make sense. */ char * -map_sql_value_to_xml_value(Datum value, Oid type) +map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings) { StringInfoData buf; @@ -1616,7 +1625,7 @@ map_sql_value_to_xml_value(Datum value, Oid type) appendStringInfoString(&buf, ""); appendStringInfoString(&buf, map_sql_value_to_xml_value(elem_values[i], - elmtype)); + elmtype, true)); appendStringInfoString(&buf, ""); } @@ -1774,8 +1783,8 @@ map_sql_value_to_xml_value(Datum value, Oid type) getTypeOutputInfo(type, &typeOut, &isvarlena); str = OidOutputFunctionCall(typeOut, value); - /* ... exactly as-is for XML */ - if (type == XMLOID) + /* ... exactly as-is for XML, and when escaping is not wanted */ + if (type == XMLOID || !xml_escape_strings) return str; /* otherwise, translate special characters as needed */ @@ -3183,7 +3192,7 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, appendStringInfo(result, " <%s>%s\n", colname, map_sql_value_to_xml_value(colval, - SPI_gettypeid(SPI_tuptable->tupdesc, i)), + SPI_gettypeid(SPI_tuptable->tupdesc, i), true), colname); } diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h index f11ec721c4..af953f2b35 100644 --- a/src/include/utils/xml.h +++ b/src/include/utils/xml.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.26 2009/05/13 20:27:17 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.27 2009/06/09 22:00:57 petere Exp $ * *------------------------------------------------------------------------- */ @@ -73,7 +73,7 @@ extern text *xmltotext_with_xmloption(xmltype *data, XmlOptionType xmloption_arg extern char *map_sql_identifier_to_xml_name(char *ident, bool fully_escaped, bool escape_period); extern char *map_xml_name_to_sql_identifier(char *name); -extern char *map_sql_value_to_xml_value(Datum value, Oid type); +extern char *map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings); typedef enum { diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index 30b332aecc..ecca5896a7 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -188,6 +188,12 @@ SELECT xmlelement(name foo, xmlattributes('2009-04-09 00:24:37'::timestamp as ba SELECT xmlelement(name foo, xmlattributes('infinity'::timestamp as bar)); ERROR: timestamp out of range DETAIL: XML does not support infinite timestamp values. +SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'br' as funnier)); + xmlelement +------------------------------------------------------------ + +(1 row) + SELECT xmlparse(content 'abc'); xmlparse ---------- diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index c8eb1e425e..d542b0689a 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -160,6 +160,10 @@ SELECT xmlelement(name foo, xmlattributes('infinity'::timestamp as bar)); ERROR: unsupported XML feature DETAIL: This functionality requires the server to be built with libxml support. HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'br' as funnier)); +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. SELECT xmlparse(content 'abc'); ERROR: unsupported XML feature DETAIL: This functionality requires the server to be built with libxml support. diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index 50550aaa35..086eedd270 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -57,6 +57,7 @@ SELECT xmlelement(name foo, bytea 'bar'); SELECT xmlelement(name foo, xmlattributes(true as bar)); SELECT xmlelement(name foo, xmlattributes('2009-04-09 00:24:37'::timestamp as bar)); SELECT xmlelement(name foo, xmlattributes('infinity'::timestamp as bar)); +SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'br' as funnier)); SELECT xmlparse(content 'abc'); -- 2.11.0