diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index ef8090274764f876d23df48703866e2978287e1e..2c697152e0a91d8596f45e60147f416578f7bc5b 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.102 2007/01/16 18:26:02 alvherre Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.103 2007/01/19 16:58:45 petere Exp $ --> <chapter Id="runtime-config"> <title>Server Configuration</title> @@ -3502,6 +3502,33 @@ SELECT * FROM parent WHERE key = 2400; </listitem> </varlistentry> + <varlistentry id="guc-xmlbinary" xreflabel="xmlbinary"> + <term><varname>xmlbinary</varname> (<type>string</type>)</term> + <indexterm> + <primary><varname>xmlbinary</> configuration parameter</primary> + </indexterm> + <listitem> + <para> + Sets how binary values are to be encoded in XML. This applies + for example when <type>bytea</type> values are converted to + XML by the functions <function>xmlelement</function> or + <function>xmlforest</function>. Possible values are + <literal>base64</literal> and <literal>hex</literal>, which + are both defined in the XML Schema standard. The default is + <literal>base64</literal>. For further information about + XML-related functions, see <xref linkend="functions-xml">. + </para> + + <para> + The actual choice here is mostly a matter of taste, + constrained only by possible restrictions in client + applications. Both methods support all possible values, + although the hex encoding will be somewhat larger than the + base64 encoding. + </para> + </listitem> + </varlistentry> + </variablelist> </sect2> <sect2 id="runtime-config-client-format"> diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 03bbda97ddf544e445336b6377ffb08d98118077..5f3fafe1e702c44131a89b71f5db1e5bfeb12d8e 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.18 2007/01/18 13:59:11 petere Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.19 2007/01/19 16:58:46 petere Exp $ * *------------------------------------------------------------------------- */ @@ -73,6 +73,8 @@ static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespac #endif /* USE_LIBXML */ +XmlBinaryType xmlbinary; + #define NO_XML_SUPPORT() \ ereport(ERROR, \ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ @@ -1500,6 +1502,28 @@ map_sql_value_to_xml_value(Datum value, Oid type) if (type == XMLOID) return str; +#ifdef USE_LIBXML + if (type == BYTEAOID) + { + xmlBufferPtr buf; + xmlTextWriterPtr writer; + char *result; + + buf = xmlBufferCreate(); + writer = xmlNewTextWriterMemory(buf, 0); + + if (xmlbinary == XMLBINARY_BASE64) + xmlTextWriterWriteBase64(writer, VARDATA(value), 0, VARSIZE(value) - VARHDRSZ); + else + xmlTextWriterWriteBinHex(writer, VARDATA(value), 0, VARSIZE(value) - VARHDRSZ); + + xmlFreeTextWriter(writer); + result = pstrdup((const char *) xmlBufferContent(buf)); + xmlBufferFree(buf); + return result; + } +#endif /* USE_LIBXML */ + for (p = str; *p; p += pg_mblen(p)) { switch (*p) diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index d04bacc58eec23edc061cde097c464bed6d25af9..7962c992acc6c0ee5b96d2e7d3b28293fe8c5aa1 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut <peter_e@gmx.net>. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.368 2007/01/16 18:26:02 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.369 2007/01/19 16:58:46 petere Exp $ * *-------------------------------------------------------------------- */ @@ -61,6 +61,7 @@ #include "utils/pg_locale.h" #include "utils/ps_status.h" #include "utils/tzparser.h" +#include "utils/xml.h" #ifndef PG_KRB_SRVTAB #define PG_KRB_SRVTAB "" @@ -142,6 +143,7 @@ static bool assign_transaction_read_only(bool newval, bool doit, GucSource sourc static const char *assign_canonical_path(const char *newval, bool doit, GucSource source); static const char *assign_backslash_quote(const char *newval, bool doit, GucSource source); static const char *assign_timezone_abbreviations(const char *newval, bool doit, GucSource source); +static const char *assign_xmlbinary(const char *newval, bool doit, GucSource source); static bool assign_tcp_keepalives_idle(int newval, bool doit, GucSource source); static bool assign_tcp_keepalives_interval(int newval, bool doit, GucSource source); @@ -229,6 +231,7 @@ static char *timezone_abbreviations_string; static char *XactIsoLevel_string; static char *data_directory; static char *custom_variable_classes; +static char *xmlbinary_string; static int max_function_args; static int max_index_keys; static int max_identifier_length; @@ -2279,6 +2282,15 @@ static struct config_string ConfigureNamesString[] = NULL, assign_canonical_path, NULL }, + { + {"xmlbinary", PGC_USERSET, CLIENT_CONN_STATEMENT, + gettext_noop("Sets how binary values are to be encoded in XML."), + gettext_noop("Valid values are BASE64 and HEX.") + }, + &xmlbinary_string, + "base64", assign_xmlbinary, NULL + }, + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL @@ -6475,6 +6487,24 @@ pg_timezone_abbrev_initialize(void) } } +static const char * +assign_xmlbinary(const char *newval, bool doit, GucSource source) +{ + XmlBinaryType xb; + + if (pg_strcasecmp(newval, "base64") == 0) + xb = XMLBINARY_BASE64; + else if (pg_strcasecmp(newval, "hex") == 0) + xb = XMLBINARY_HEX; + else + return NULL; /* reject */ + + if (doit) + xmlbinary = xb; + + return newval; +} + static bool assign_tcp_keepalives_idle(int newval, bool doit, GucSource source) { diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h index 9e576bdecbecefe9eac1effb1b3174cb91747498..ec39368891a548037e87d26b9c75668e839fa9ba 100644 --- a/src/include/utils/xml.h +++ b/src/include/utils/xml.h @@ -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/include/utils/xml.h,v 1.10 2007/01/14 13:11:54 petere Exp $ + * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.11 2007/01/19 16:58:46 petere Exp $ * *------------------------------------------------------------------------- */ @@ -43,4 +43,12 @@ extern char *map_sql_identifier_to_xml_name(char *ident, bool fully_escaped); extern char *map_xml_name_to_sql_identifier(char *name); extern char *map_sql_value_to_xml_value(Datum value, Oid type); +typedef enum +{ + XMLBINARY_BASE64, + XMLBINARY_HEX +} XmlBinaryType; + +extern XmlBinaryType xmlbinary; + #endif /* XML_H */ diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index db03e43f2abc671c5d20419839baf5b1be2e509b..cfac9105d96caa150968cbbb820145a6b7678294 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -121,6 +121,20 @@ SELECT xmlelement(name foo, array[1, 2, 3]); <foo><element>1</element><element>2</element><element>3</element></foo> (1 row) +SET xmlbinary TO base64; +SELECT xmlelement(name foo, bytea 'bar'); + xmlelement +----------------- + <foo>YmFy</foo> +(1 row) + +SET xmlbinary TO hex; +SELECT xmlelement(name foo, bytea 'bar'); + xmlelement +------------------- + <foo>626172</foo> +(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 4534ae98cc573842c71bd71c7b19ab3565e26a9a..b25df3d24b90830842200286f84daede7343f7f1 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -58,6 +58,12 @@ 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 +SET xmlbinary TO base64; +SELECT xmlelement(name foo, bytea 'bar'); +ERROR: no XML support in this installation +SET xmlbinary TO hex; +SELECT xmlelement(name foo, bytea 'bar'); +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 4492a62cdb0ce3afa4521ed7531645e224ee000f..804cd2c2d676e4ed2f4f196bf6f705b8e503730b 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -45,6 +45,10 @@ 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]); +SET xmlbinary TO base64; +SELECT xmlelement(name foo, bytea 'bar'); +SET xmlbinary TO hex; +SELECT xmlelement(name foo, bytea 'bar'); SELECT xmlparse(content 'abc');