*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.205 2007/01/08 23:41:56 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.206 2007/01/12 16:29:24 petere Exp $
*
*-------------------------------------------------------------------------
*/
newe = coerce_to_specific_type(pstate, newe, XMLOID,
"XMLCONCAT");
break;
- case IS_XMLELEMENT:
- newe = coerce_to_specific_type(pstate, newe, XMLOID,
- "XMLELEMENT");
- break;
case IS_XMLFOREST:
newe = coerce_to_specific_type(pstate, newe, XMLOID,
"XMLFOREST");
newx->args = lappend(newx->args, newe);
i++;
}
-
+
return (Node *) newx;
}
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.14 2007/01/10 20:33:54 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.15 2007/01/12 16:29:24 petere Exp $
*
*-------------------------------------------------------------------------
*/
#include <libxml/xmlwriter.h>
#endif /* USE_LIBXML */
+#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "fmgr.h"
#include "libpq/pqformat.h"
#include "mb/pg_wchar.h"
#include "nodes/execnodes.h"
+#include "parser/parse_expr.h"
+#include "utils/array.h"
#include "utils/builtins.h"
+#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/xml.h"
static xmlChar *xml_text2xmlChar(text *in);
static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespace);
+static char *map_sql_value_to_xml_value(Datum value, Oid type);
+
#endif /* USE_LIBXML */
#define NO_XML_SUPPORT() \
value = ExecEvalExpr(e, econtext, &isnull, NULL);
if (!isnull)
- {
- /* we know the value is XML type */
- str = DatumGetCString(DirectFunctionCall1(xml_out,
- value));
- xmlTextWriterWriteRaw(writer, (xmlChar *) str);
- pfree(str);
- }
+ xmlTextWriterWriteRaw(writer, (xmlChar *) map_sql_value_to_xml_value(value, exprType((Node *) e->expr)));
}
xmlTextWriterEndElement(writer);
return buf.data;
}
+
+
+#ifdef USE_LIBXML
+/*
+ * Map SQL value to XML value; see SQL/XML:2003 section 9.16.
+ */
+static char *
+map_sql_value_to_xml_value(Datum value, Oid type)
+{
+ StringInfoData buf;
+
+ initStringInfo(&buf);
+
+ if (is_array_type(type))
+ {
+ int i;
+ ArrayType *array;
+ Oid elmtype;
+ int16 elmlen;
+ bool elmbyval;
+ char elmalign;
+
+ array = DatumGetArrayTypeP(value);
+
+ /* TODO: need some code-fu here to remove this limitation */
+ if (ARR_NDIM(array) != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("only supported for one-dimensional array")));
+
+ elmtype = ARR_ELEMTYPE(array);
+ get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign);
+
+ for (i = ARR_LBOUND(array)[0];
+ i < ARR_LBOUND(array)[0] + ARR_DIMS(array)[0];
+ i++)
+ {
+ Datum subval;
+ bool isnull;
+
+ subval = array_ref(array, 1, &i, -1, elmlen, elmbyval, elmalign, &isnull);
+ appendStringInfoString(&buf, "<element>");
+ appendStringInfoString(&buf, map_sql_value_to_xml_value(subval, elmtype));
+ appendStringInfoString(&buf, "</element>");
+ }
+ }
+ else
+ {
+ Oid typeOut;
+ bool isvarlena;
+ char *p, *str;
+
+ getTypeOutputInfo(type, &typeOut, &isvarlena);
+ str = OidOutputFunctionCall(typeOut, value);
+
+ if (type == XMLOID)
+ return str;
+
+ for (p = str; *p; p += pg_mblen(p))
+ {
+ switch (*p)
+ {
+ case '&':
+ appendStringInfo(&buf, "&");
+ break;
+ case '<':
+ appendStringInfo(&buf, "<");
+ break;
+ case '>':
+ appendStringInfo(&buf, ">");
+ break;
+ case '\r':
+ appendStringInfo(&buf, "
");
+ break;
+ default:
+ appendBinaryStringInfo(&buf, p, pg_mblen(p));
+ break;
+ }
+ }
+ }
+
+ return buf.data;
+}
+#endif /* USE_LIBXML */
<employee><name>linda</name><age>19</age><pay>100</pay></employee>
(6 rows)
-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 xmlelement(name num, 37);
+ xmlelement
+---------------
+ <num>37</num>
+(1 row)
+
+SELECT xmlelement(name foo, text 'bar');
+ xmlelement
+----------------
+ <foo>bar</foo>
+(1 row)
+
+SELECT xmlelement(name foo, xml 'bar');
+ xmlelement
+----------------
+ <foo>bar</foo>
+(1 row)
+
+SELECT xmlelement(name foo, text 'b<a/>r');
+ xmlelement
+-------------------------
+ <foo>b<a/>r</foo>
+(1 row)
+
+SELECT xmlelement(name foo, xml 'b<a/>r');
+ xmlelement
+-------------------
+ <foo>b<a/>r</foo>
+(1 row)
+
+SELECT xmlelement(name foo, array[1, 2, 3]);
+ xmlelement
+-------------------------------------------------------------------------
+ <foo><element>1</element><element>2</element><element>3</element></foo>
+(1 row)
+
SELECT xmlparse(content 'abc');
xmlparse
----------
ERROR: no XML support in this installation
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 xmlelement(name num, 37);
+ERROR: no XML support in this installation
+SELECT xmlelement(name foo, text 'bar');
+ERROR: no XML support in this installation
+SELECT xmlelement(name foo, xml 'bar');
+ERROR: no XML support in this installation
+SELECT xmlelement(name foo, text 'b<a/>r');
+ERROR: no XML support in this installation
+SELECT xmlelement(name foo, xml 'b<a/>r');
+ERROR: no XML support in this installation
+SELECT xmlelement(name foo, array[1, 2, 3]);
+ERROR: no XML support in this installation
SELECT xmlparse(content 'abc');
ERROR: no XML support in this installation
SELECT xmlparse(content '<abc>x</abc>');
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 xmlelement(name num, 37);
+SELECT xmlelement(name foo, text 'bar');
+SELECT xmlelement(name foo, xml 'bar');
+SELECT xmlelement(name foo, text 'b<a/>r');
+SELECT xmlelement(name foo, xml 'b<a/>r');
+SELECT xmlelement(name foo, array[1, 2, 3]);
+
SELECT xmlparse(content 'abc');
SELECT xmlparse(content '<abc>x</abc>');