mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
Fix xmlconcat by properly merging the XML declarations. Add aggregate
function xmlagg.
This commit is contained in:
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.207 2007/01/14 13:11:53 petere Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.208 2007/01/20 09:27:19 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2651,7 +2651,6 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
|||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
Datum value;
|
Datum value;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
char *str;
|
|
||||||
ListCell *arg;
|
ListCell *arg;
|
||||||
ListCell *narg;
|
ListCell *narg;
|
||||||
int i;
|
int i;
|
||||||
@ -2663,20 +2662,22 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
|||||||
switch (xexpr->op)
|
switch (xexpr->op)
|
||||||
{
|
{
|
||||||
case IS_XMLCONCAT:
|
case IS_XMLCONCAT:
|
||||||
initStringInfo(&buf);
|
{
|
||||||
|
List *values = NIL;
|
||||||
|
|
||||||
foreach(arg, xmlExpr->args)
|
foreach(arg, xmlExpr->args)
|
||||||
{
|
{
|
||||||
ExprState *e = (ExprState *) lfirst(arg);
|
ExprState *e = (ExprState *) lfirst(arg);
|
||||||
|
|
||||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||||
if (!isnull)
|
if (!isnull)
|
||||||
|
values = lappend(values, DatumGetPointer(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list_length(values) > 0)
|
||||||
{
|
{
|
||||||
/* we know the value is XML type */
|
|
||||||
str = DatumGetCString(DirectFunctionCall1(xml_out,
|
|
||||||
value));
|
|
||||||
appendStringInfoString(&buf, str);
|
|
||||||
pfree(str);
|
|
||||||
*isNull = false;
|
*isNull = false;
|
||||||
|
return PointerGetDatum(xmlconcat(values));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.19 2007/01/19 16:58:46 petere Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.20 2007/01/20 09:27:19 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -359,6 +359,102 @@ xmlcomment(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: xmlconcat needs to merge the notations and unparsed entities
|
||||||
|
* of the argument values. Not very important in practice, though.
|
||||||
|
*/
|
||||||
|
xmltype *
|
||||||
|
xmlconcat(List *args)
|
||||||
|
{
|
||||||
|
#ifdef USE_LIBXML
|
||||||
|
StringInfoData buf;
|
||||||
|
ListCell *v;
|
||||||
|
|
||||||
|
int global_standalone = 1;
|
||||||
|
xmlChar *global_version = NULL;
|
||||||
|
bool global_version_no_value = false;
|
||||||
|
|
||||||
|
initStringInfo(&buf);
|
||||||
|
foreach(v, args)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
xmlChar *version;
|
||||||
|
int standalone;
|
||||||
|
xmltype *x = DatumGetXmlP(PointerGetDatum(lfirst(v)));
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
len = VARSIZE(x) - VARHDRSZ;
|
||||||
|
str = palloc(len + 1);
|
||||||
|
memcpy(str, VARDATA(x), len);
|
||||||
|
str[len] = '\0';
|
||||||
|
|
||||||
|
parse_xml_decl((xmlChar *) str, &len, &version, NULL, &standalone);
|
||||||
|
|
||||||
|
if (standalone == 0 && global_standalone == 1)
|
||||||
|
global_standalone = 0;
|
||||||
|
if (standalone < 0)
|
||||||
|
global_standalone = -1;
|
||||||
|
|
||||||
|
if (!global_version)
|
||||||
|
global_version = xmlStrdup(version);
|
||||||
|
else if (version && xmlStrcmp(version, global_version) != 0)
|
||||||
|
global_version_no_value = true;
|
||||||
|
|
||||||
|
appendStringInfoString(&buf, str + len);
|
||||||
|
pfree(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!global_version_no_value || global_standalone >= 0)
|
||||||
|
{
|
||||||
|
StringInfoData buf2;
|
||||||
|
|
||||||
|
initStringInfo(&buf2);
|
||||||
|
|
||||||
|
if (!global_version_no_value && global_version)
|
||||||
|
appendStringInfo(&buf2, "<?xml version=\"%s\"", global_version);
|
||||||
|
else
|
||||||
|
appendStringInfo(&buf2, "<?xml version=\"%s\"", PG_XML_DEFAULT_VERSION);
|
||||||
|
|
||||||
|
if (global_standalone == 1)
|
||||||
|
appendStringInfoString(&buf2, " standalone=\"yes\"");
|
||||||
|
else if (global_standalone == 0)
|
||||||
|
appendStringInfoString(&buf2, " standalone=\"no\"");
|
||||||
|
|
||||||
|
appendStringInfoString(&buf2, "?>");
|
||||||
|
|
||||||
|
appendStringInfoString(&buf2, buf.data);
|
||||||
|
buf = buf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringinfo_to_xmltype(&buf);
|
||||||
|
#else
|
||||||
|
NO_XML_SUPPORT();
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XMLAGG support
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
xmlconcat2(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
if (PG_ARGISNULL(0))
|
||||||
|
{
|
||||||
|
if (PG_ARGISNULL(1))
|
||||||
|
PG_RETURN_NULL();
|
||||||
|
else
|
||||||
|
PG_RETURN_XML_P(PG_GETARG_XML_P(1));
|
||||||
|
}
|
||||||
|
else if (PG_ARGISNULL(1))
|
||||||
|
PG_RETURN_XML_P(PG_GETARG_XML_P(0));
|
||||||
|
else
|
||||||
|
PG_RETURN_XML_P(xmlconcat(list_make2(PG_GETARG_XML_P(0), PG_GETARG_XML_P(1))));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
texttoxml(PG_FUNCTION_ARGS)
|
texttoxml(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.372 2007/01/16 21:41:13 neilc Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.373 2007/01/20 09:27:19 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200701161
|
#define CATALOG_VERSION_NO 200701201
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_aggregate.h,v 1.59 2007/01/05 22:19:52 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_aggregate.h,v 1.60 2007/01/20 09:27:19 petere Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -221,6 +221,9 @@ DATA(insert ( 2241 int8or - 0 20 _null_ ));
|
|||||||
DATA(insert ( 2242 bitand - 0 1560 _null_ ));
|
DATA(insert ( 2242 bitand - 0 1560 _null_ ));
|
||||||
DATA(insert ( 2243 bitor - 0 1560 _null_ ));
|
DATA(insert ( 2243 bitor - 0 1560 _null_ ));
|
||||||
|
|
||||||
|
/* xml */
|
||||||
|
DATA(insert ( 2901 xmlconcat2 - 0 142 _null_ ));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* prototypes for functions in pg_aggregate.c
|
* prototypes for functions in pg_aggregate.c
|
||||||
*/
|
*/
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.437 2007/01/16 21:41:13 neilc Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.438 2007/01/20 09:27:19 petere Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The script catalog/genbki.sh reads this file and generates .bki
|
* The script catalog/genbki.sh reads this file and generates .bki
|
||||||
@ -4037,6 +4037,10 @@ DATA(insert OID = 2898 ( xml_recv PGNSP PGUID 12 f f t f s 1 142 "2281" _nu
|
|||||||
DESCR("I/O");
|
DESCR("I/O");
|
||||||
DATA(insert OID = 2899 ( xml_send PGNSP PGUID 12 f f t f s 1 17 "142" _null_ _null_ _null_ xml_send - _null_ ));
|
DATA(insert OID = 2899 ( xml_send PGNSP PGUID 12 f f t f s 1 17 "142" _null_ _null_ _null_ xml_send - _null_ ));
|
||||||
DESCR("I/O");
|
DESCR("I/O");
|
||||||
|
DATA(insert OID = 2900 ( xmlconcat2 PGNSP PGUID 12 f f f f i 2 142 "142 142" _null_ _null_ _null_ xmlconcat2 - _null_ ));
|
||||||
|
DESCR("aggregate transition function");
|
||||||
|
DATA(insert OID = 2901 ( xmlagg PGNSP PGUID 12 t f f f i 1 142 "142" _null_ _null_ _null_ aggregate_dummy - _null_ ));
|
||||||
|
DESCR("concatenate XML values");
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.11 2007/01/19 16:58:46 petere Exp $
|
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.12 2007/01/20 09:27:20 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -30,9 +30,11 @@ extern Datum xml_out(PG_FUNCTION_ARGS);
|
|||||||
extern Datum xml_recv(PG_FUNCTION_ARGS);
|
extern Datum xml_recv(PG_FUNCTION_ARGS);
|
||||||
extern Datum xml_send(PG_FUNCTION_ARGS);
|
extern Datum xml_send(PG_FUNCTION_ARGS);
|
||||||
extern Datum xmlcomment(PG_FUNCTION_ARGS);
|
extern Datum xmlcomment(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum xmlconcat2(PG_FUNCTION_ARGS);
|
||||||
extern Datum texttoxml(PG_FUNCTION_ARGS);
|
extern Datum texttoxml(PG_FUNCTION_ARGS);
|
||||||
extern Datum xmlvalidate(PG_FUNCTION_ARGS);
|
extern Datum xmlvalidate(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
|
extern xmltype *xmlconcat(List *args);
|
||||||
extern xmltype *xmlelement(XmlExprState *xmlExpr, ExprContext *econtext);
|
extern xmltype *xmlelement(XmlExprState *xmlExpr, ExprContext *econtext);
|
||||||
extern xmltype *xmlparse(text *data, bool is_doc, bool preserve_whitespace);
|
extern xmltype *xmlparse(text *data, bool is_doc, bool preserve_whitespace);
|
||||||
extern xmltype *xmlpi(char *target, text *arg, bool arg_is_null, bool *result_is_null);
|
extern xmltype *xmlpi(char *target, text *arg, bool arg_is_null, bool *result_is_null);
|
||||||
|
@ -55,6 +55,12 @@ ERROR: argument of XMLCONCAT must be type xml, not type integer
|
|||||||
SELECT xmlconcat('bad', '<syntax');
|
SELECT xmlconcat('bad', '<syntax');
|
||||||
ERROR: invalid XML content
|
ERROR: invalid XML content
|
||||||
DETAIL: Expected '>'
|
DETAIL: Expected '>'
|
||||||
|
SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
|
||||||
|
xmlconcat
|
||||||
|
---------------------------------------------------
|
||||||
|
<?xml version="1.1" standalone="no"?><foo/><bar/>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT xmlelement(name element,
|
SELECT xmlelement(name element,
|
||||||
xmlattributes (1 as one, 'deuce' as two),
|
xmlattributes (1 as one, 'deuce' as two),
|
||||||
'content');
|
'content');
|
||||||
@ -268,6 +274,24 @@ SELECT xml 'abc' IS NOT DOCUMENT;
|
|||||||
SELECT '<>' IS NOT DOCUMENT;
|
SELECT '<>' IS NOT DOCUMENT;
|
||||||
ERROR: invalid XML content
|
ERROR: invalid XML content
|
||||||
DETAIL: Element name not found
|
DETAIL: Element name not found
|
||||||
|
SELECT xmlagg(data) FROM xmltest;
|
||||||
|
xmlagg
|
||||||
|
--------------------------------------
|
||||||
|
<value>one</value><value>two</value>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlagg(data) FROM xmltest WHERE id > 10;
|
||||||
|
xmlagg
|
||||||
|
--------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlelement(name employees, xmlagg(xmlelement(name name, name))) FROM emp;
|
||||||
|
xmlelement
|
||||||
|
--------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
<employees><name>sharon</name><name>sam</name><name>bill</name><name>jeff</name><name>cim</name><name>linda</name></employees>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- Check mapping SQL identifier to XML name
|
-- Check mapping SQL identifier to XML name
|
||||||
SELECT xmlpi(name ":::_xml_abc135.%-&_");
|
SELECT xmlpi(name ":::_xml_abc135.%-&_");
|
||||||
xmlpi
|
xmlpi
|
||||||
|
@ -33,6 +33,8 @@ SELECT xmlconcat(1, 2);
|
|||||||
ERROR: argument of XMLCONCAT must be type xml, not type integer
|
ERROR: argument of XMLCONCAT must be type xml, not type integer
|
||||||
SELECT xmlconcat('bad', '<syntax');
|
SELECT xmlconcat('bad', '<syntax');
|
||||||
ERROR: no XML support in this installation
|
ERROR: no XML support in this installation
|
||||||
|
SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
|
||||||
|
ERROR: no XML support in this installation
|
||||||
SELECT xmlelement(name element,
|
SELECT xmlelement(name element,
|
||||||
xmlattributes (1 as one, 'deuce' as two),
|
xmlattributes (1 as one, 'deuce' as two),
|
||||||
'content');
|
'content');
|
||||||
@ -123,6 +125,20 @@ SELECT xml 'abc' IS NOT DOCUMENT;
|
|||||||
ERROR: no XML support in this installation
|
ERROR: no XML support in this installation
|
||||||
SELECT '<>' IS NOT DOCUMENT;
|
SELECT '<>' IS NOT DOCUMENT;
|
||||||
ERROR: no XML support in this installation
|
ERROR: no XML support in this installation
|
||||||
|
SELECT xmlagg(data) FROM xmltest;
|
||||||
|
xmlagg
|
||||||
|
--------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlagg(data) FROM xmltest WHERE id > 10;
|
||||||
|
xmlagg
|
||||||
|
--------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlelement(name employees, xmlagg(xmlelement(name name, name))) FROM emp;
|
||||||
|
ERROR: no XML support in this installation
|
||||||
-- Check mapping SQL identifier to XML name
|
-- Check mapping SQL identifier to XML name
|
||||||
SELECT xmlpi(name ":::_xml_abc135.%-&_");
|
SELECT xmlpi(name ":::_xml_abc135.%-&_");
|
||||||
ERROR: no XML support in this installation
|
ERROR: no XML support in this installation
|
||||||
|
@ -24,6 +24,7 @@ SELECT xmlconcat(xmlcomment('hello'),
|
|||||||
SELECT xmlconcat('hello', 'you');
|
SELECT xmlconcat('hello', 'you');
|
||||||
SELECT xmlconcat(1, 2);
|
SELECT xmlconcat(1, 2);
|
||||||
SELECT xmlconcat('bad', '<syntax');
|
SELECT xmlconcat('bad', '<syntax');
|
||||||
|
SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
|
||||||
|
|
||||||
|
|
||||||
SELECT xmlelement(name element,
|
SELECT xmlelement(name element,
|
||||||
@ -97,6 +98,11 @@ SELECT xml 'abc' IS NOT DOCUMENT;
|
|||||||
SELECT '<>' IS NOT DOCUMENT;
|
SELECT '<>' IS NOT DOCUMENT;
|
||||||
|
|
||||||
|
|
||||||
|
SELECT xmlagg(data) FROM xmltest;
|
||||||
|
SELECT xmlagg(data) FROM xmltest WHERE id > 10;
|
||||||
|
SELECT xmlelement(name employees, xmlagg(xmlelement(name name, name))) FROM emp;
|
||||||
|
|
||||||
|
|
||||||
-- Check mapping SQL identifier to XML name
|
-- Check mapping SQL identifier to XML name
|
||||||
|
|
||||||
SELECT xmlpi(name ":::_xml_abc135.%-&_");
|
SELECT xmlpi(name ":::_xml_abc135.%-&_");
|
||||||
|
Reference in New Issue
Block a user