From 3a32ba2f3f54378e3e06366a5ff06e339984f065 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Mon, 8 Jan 2007 23:41:57 +0000
Subject: [PATCH] Prevent duplicate attribute names in XMLELEMENT.

---
 src/backend/parser/parse_expr.c     | 22 +++++++++++++++++++---
 src/test/regress/expected/xml.out   |  4 +++-
 src/test/regress/expected/xml_1.out |  2 ++
 src/test/regress/sql/xml.sql        |  1 +
 4 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index c15858fc7a..033dd6c75c 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.204 2007/01/05 22:19:34 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.205 2007/01/08 23:41:56 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1415,8 +1415,8 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 					 x->op == IS_XMLELEMENT
-					 ? errmsg("unnamed attribute value must be a column reference")
-					 : errmsg("unnamed element value must be a column reference")));
+					 ? errmsg("unnamed XML attribute value must be a column reference")
+					 : errmsg("unnamed XML element value must be a column reference")));
 			argname = NULL;		/* keep compiler quiet */
 		}
 
@@ -1424,6 +1424,22 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 		newx->arg_names = lappend(newx->arg_names, makeString(argname));
 	}
 
+	if (x->op == IS_XMLELEMENT)
+	{
+		foreach(lc, newx->arg_names)
+		{
+			ListCell	*lc2;
+
+			for_each_cell(lc2, lnext(lc))
+			{
+				if (strcmp(strVal(lfirst(lc)), strVal(lfirst(lc2))) == 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("XML attribute name \"%s\" appears more than once", strVal(lfirst(lc)))));
+			}
+		}
+	}
+
 	/* The other arguments are of varying types depending on the function */
 	newx->args = NIL;
 	i = 0;
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index c0ec868bf8..4179233e99 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -65,7 +65,7 @@ SELECT xmlelement(name element,
 
 SELECT xmlelement(name element,
                   xmlattributes ('unnamed and wrong'));
-ERROR:  unnamed attribute value must be a column reference
+ERROR:  unnamed XML attribute value must be a column reference
 SELECT xmlelement(name element, xmlelement(name nested, 'stuff'));
                 xmlelement                 
 -------------------------------------------
@@ -85,6 +85,8 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
 
 SELECT xmlelement(name wrong, 37);
 ERROR:  argument of XMLELEMENT must be type xml, not type integer
+SELECT xmlelement(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
+ERROR:  XML attribute name "a" appears more than once
 SELECT xmlparse(content 'abc');
  xmlparse 
 ----------
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 5a1a6ac031..8ef963b8e9 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -46,6 +46,8 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
 ERROR:  no XML support in this installation
 SELECT xmlelement(name wrong, 37);
 ERROR:  no XML support in this installation
+SELECT xmlelement(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
+ERROR:  no XML support in this installation
 SELECT xmlparse(content 'abc');
 ERROR:  no XML support in this installation
 SELECT xmlparse(content '<abc>x</abc>');
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index ae7d633c1c..d3a1e6104b 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -38,6 +38,7 @@ SELECT xmlelement(name element, xmlelement(name nested, 'stuff'));
 SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
 
 SELECT xmlelement(name wrong, 37);
+SELECT xmlelement(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
 
 
 SELECT xmlparse(content 'abc');