From fc568b9d8f6b30d0a5573b73c719e23fa0a6a979 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 12 Jan 2007 16:29:24 +0000 Subject: 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. --- src/backend/utils/adt/xml.c | 100 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 8 deletions(-) (limited to 'src/backend/utils/adt/xml.c') diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 5616259b29e..3689c9203e8 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -35,12 +35,16 @@ #include #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" @@ -66,6 +70,8 @@ static void xml_ereport_by_code(int level, int sqlcode, 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() \ @@ -284,13 +290,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext) 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); @@ -1258,3 +1258,87 @@ map_xml_name_to_sql_identifier(char *name) 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, ""); + appendStringInfoString(&buf, map_sql_value_to_xml_value(subval, elmtype)); + appendStringInfoString(&buf, ""); + } + } + 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 */ -- cgit v1.2.3