Commit 5e512971 authored by Tom Lane's avatar Tom Lane

Some code review for xml.c:

Add some more xml_init() calls that might not be necessary, but seem like a
good idea to avoid possible problems like we saw in xmlelement().
Fix unsafe assumption that you can keep using the tupledesc of a relcache
entry you don't have open.
Add missing error checks for SearchSysCache failure.
Get rid of handwritten array traversal in xpath() and O(N^2), broken-for-nulls
array access code in map_sql_value_to_xml_value(), in favor of using
deconstruct_array.
Manually adjust a lot of line breaks in places where the code is otherwise
gonna look pretty awful after pg_indent hacks it up (original author seems to
have liked to lay out code for a 200-column window).
parent 85f807d7
...@@ -7,7 +7,7 @@ ...@@ -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.50 2007/11/05 22:23:07 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.51 2007/11/06 03:06:28 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -86,27 +86,38 @@ static void *xml_palloc(size_t size); ...@@ -86,27 +86,38 @@ static void *xml_palloc(size_t size);
static void *xml_repalloc(void *ptr, size_t size); static void *xml_repalloc(void *ptr, size_t size);
static void xml_pfree(void *ptr); static void xml_pfree(void *ptr);
static char *xml_pstrdup(const char *string); static char *xml_pstrdup(const char *string);
static void xml_ereport(int level, int sqlcode, static void xml_ereport(int level, int sqlcode, const char *msg);
const char *msg);
static void xml_errorHandler(void *ctxt, const char *msg, ...); static void xml_errorHandler(void *ctxt, const char *msg, ...);
static void xml_ereport_by_code(int level, int sqlcode, static void xml_ereport_by_code(int level, int sqlcode,
const char *msg, int errcode); const char *msg, int errcode);
static xmlChar *xml_text2xmlChar(text *in); static xmlChar *xml_text2xmlChar(text *in);
static int parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **encoding, int *standalone); static int parse_xml_decl(const xmlChar *str, size_t *lenp,
static bool print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone); xmlChar **version, xmlChar **encoding, int *standalone);
static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding); static bool print_xml_decl(StringInfo buf, const xmlChar *version,
pg_enc encoding, int standalone);
static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg,
bool preserve_whitespace, xmlChar *encoding);
static text *xml_xmlnodetoxmltype(xmlNodePtr cur); static text *xml_xmlnodetoxmltype(xmlNodePtr cur);
#endif /* USE_LIBXML */ #endif /* USE_LIBXML */
static StringInfo query_to_xml_internal(const char *query, char *tablename, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level); static StringInfo query_to_xml_internal(const char *query, char *tablename,
static const char * map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tableforest, const char *targetns); const char *xmlschema, bool nulls, bool tableforest,
static const char * map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool tableforest, const char *targetns); const char *targetns, bool top_level);
static const char * map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tableforest, const char *targetns); static const char *map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid,
bool nulls, bool tableforest, const char *targetns);
static const char *map_sql_schema_to_xmlschema_types(Oid nspid,
List *relid_list, bool nulls,
bool tableforest, const char *targetns);
static const char *map_sql_catalog_to_xmlschema_types(List *nspid_list,
bool nulls, bool tableforest,
const char *targetns);
static const char * map_sql_type_to_xml_name(Oid typeoid, int typmod); static const char * map_sql_type_to_xml_name(Oid typeoid, int typmod);
static const char * map_sql_typecoll_to_xmlschema_types(List *tupdesc_list); static const char * map_sql_typecoll_to_xmlschema_types(List *tupdesc_list);
static const char * map_sql_type_to_xmlschema_type(Oid typeoid, int typmod); static const char * map_sql_type_to_xmlschema_type(Oid typeoid, int typmod);
static void SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool nulls, bool tableforest, const char *targetns, bool top_level); static void SPI_sql_row_to_xmlelement(int rownum, StringInfo result,
char *tablename, bool nulls, bool tableforest,
const char *targetns, bool top_level);
#define NO_XML_SUPPORT() \ #define NO_XML_SUPPORT() \
ereport(ERROR, \ ereport(ERROR, \
...@@ -194,7 +205,8 @@ xml_out_internal(xmltype *x, pg_enc target_encoding) ...@@ -194,7 +205,8 @@ xml_out_internal(xmltype *x, pg_enc target_encoding)
str[len] = '\0'; str[len] = '\0';
#ifdef USE_LIBXML #ifdef USE_LIBXML
if ((res_code = parse_xml_decl((xmlChar *) str, &len, &version, &encoding, &standalone)) == 0) if ((res_code = parse_xml_decl((xmlChar *) str,
&len, &version, &encoding, &standalone)) == 0)
{ {
StringInfoData buf; StringInfoData buf;
...@@ -388,17 +400,23 @@ xmlcomment(PG_FUNCTION_ARGS) ...@@ -388,17 +400,23 @@ xmlcomment(PG_FUNCTION_ARGS)
{ {
#ifdef USE_LIBXML #ifdef USE_LIBXML
text *arg = PG_GETARG_TEXT_P(0); text *arg = PG_GETARG_TEXT_P(0);
char *argdata = VARDATA(arg);
int len = VARSIZE(arg) - VARHDRSZ; int len = VARSIZE(arg) - VARHDRSZ;
StringInfoData buf; StringInfoData buf;
int i; int i;
/* check for "--" in string or "-" at the end */ /* check for "--" in string or "-" at the end */
for (i = 1; i < len; i++) for (i = 1; i < len; i++)
if ((VARDATA(arg)[i] == '-' && VARDATA(arg)[i - 1] == '-') {
|| (VARDATA(arg)[i] == '-' && i == len - 1)) if (argdata[i] == '-' && argdata[i - 1] == '-')
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_XML_COMMENT), (errcode(ERRCODE_INVALID_XML_COMMENT),
errmsg("invalid XML comment"))); errmsg("invalid XML comment")));
}
if (len > 0 && argdata[len - 1] == '-')
ereport(ERROR,
(errcode(ERRCODE_INVALID_XML_COMMENT),
errmsg("invalid XML comment")));
initStringInfo(&buf); initStringInfo(&buf);
appendStringInfo(&buf, "<!--"); appendStringInfo(&buf, "<!--");
...@@ -422,20 +440,19 @@ xmltype * ...@@ -422,20 +440,19 @@ xmltype *
xmlconcat(List *args) xmlconcat(List *args)
{ {
#ifdef USE_LIBXML #ifdef USE_LIBXML
StringInfoData buf;
ListCell *v;
int global_standalone = 1; int global_standalone = 1;
xmlChar *global_version = NULL; xmlChar *global_version = NULL;
bool global_version_no_value = false; bool global_version_no_value = false;
StringInfoData buf;
ListCell *v;
initStringInfo(&buf); initStringInfo(&buf);
foreach(v, args) foreach(v, args)
{ {
xmltype *x = DatumGetXmlP(PointerGetDatum(lfirst(v)));
size_t len; size_t len;
xmlChar *version; xmlChar *version;
int standalone; int standalone;
xmltype *x = DatumGetXmlP(PointerGetDatum(lfirst(v)));
char *str; char *str;
len = VARSIZE(x) - VARHDRSZ; len = VARSIZE(x) - VARHDRSZ;
...@@ -468,7 +485,7 @@ xmlconcat(List *args) ...@@ -468,7 +485,7 @@ xmlconcat(List *args)
initStringInfo(&buf2); initStringInfo(&buf2);
print_xml_decl(&buf2, print_xml_decl(&buf2,
(!global_version_no_value && global_version) ? global_version : NULL, (!global_version_no_value) ? global_version : NULL,
0, 0,
global_standalone); global_standalone);
...@@ -500,7 +517,8 @@ xmlconcat2(PG_FUNCTION_ARGS) ...@@ -500,7 +517,8 @@ xmlconcat2(PG_FUNCTION_ARGS)
else if (PG_ARGISNULL(1)) else if (PG_ARGISNULL(1))
PG_RETURN_XML_P(PG_GETARG_XML_P(0)); PG_RETURN_XML_P(PG_GETARG_XML_P(0));
else else
PG_RETURN_XML_P(xmlconcat(list_make2(PG_GETARG_XML_P(0), PG_GETARG_XML_P(1)))); PG_RETURN_XML_P(xmlconcat(list_make2(PG_GETARG_XML_P(0),
PG_GETARG_XML_P(1))));
} }
...@@ -680,8 +698,7 @@ xmlpi(char *target, text *arg, bool arg_is_null, bool *result_is_null) ...@@ -680,8 +698,7 @@ xmlpi(char *target, text *arg, bool arg_is_null, bool *result_is_null)
{ {
char *string; char *string;
string = DatumGetCString(DirectFunctionCall1(textout, string = _textout(arg);
PointerGetDatum(arg)));
if (strstr(string, "?>") != NULL) if (strstr(string, "?>") != NULL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION), (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
...@@ -971,17 +988,24 @@ xml_init(void) ...@@ -971,17 +988,24 @@ xml_init(void)
* to complete this. * to complete this.
*/ */
#define CHECK_XML_SPACE(p) if (!xmlIsBlank_ch(*(p))) return XML_ERR_SPACE_REQUIRED #define CHECK_XML_SPACE(p) \
#define SKIP_XML_SPACE(p) while (xmlIsBlank_ch(*(p))) (p)++ do { \
if (!xmlIsBlank_ch(*(p))) \
return XML_ERR_SPACE_REQUIRED; \
} while (0)
#define SKIP_XML_SPACE(p) \
while (xmlIsBlank_ch(*(p))) (p)++
static int static int
parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **encoding, int *standalone) parse_xml_decl(const xmlChar *str,size_t *lenp,
xmlChar **version, xmlChar **encoding, int *standalone)
{ {
const xmlChar *p; const xmlChar *p;
const xmlChar *save_p; const xmlChar *save_p;
size_t len; size_t len;
p = str; xml_init();
if (version) if (version)
*version = NULL; *version = NULL;
...@@ -990,6 +1014,8 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **en ...@@ -990,6 +1014,8 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **en
if (standalone) if (standalone)
*standalone = -1; *standalone = -1;
p = str;
if (xmlStrncmp(p, (xmlChar *)"<?xml", 5) != 0) if (xmlStrncmp(p, (xmlChar *)"<?xml", 5) != 0)
goto finished; goto finished;
...@@ -1119,8 +1145,11 @@ finished: ...@@ -1119,8 +1145,11 @@ finished:
* which is the default version specified in SQL:2003. * which is the default version specified in SQL:2003.
*/ */
static bool static bool
print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone) print_xml_decl(StringInfo buf, const xmlChar *version,
pg_enc encoding, int standalone)
{ {
xml_init();
if ((version && strcmp((char *) version, PG_XML_DEFAULT_VERSION) != 0) if ((version && strcmp((char *) version, PG_XML_DEFAULT_VERSION) != 0)
|| (encoding && encoding != PG_UTF8) || (encoding && encoding != PG_UTF8)
|| standalone != -1) || standalone != -1)
...@@ -1133,11 +1162,14 @@ print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int stan ...@@ -1133,11 +1162,14 @@ print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int stan
appendStringInfo(buf, " version=\"%s\"", PG_XML_DEFAULT_VERSION); appendStringInfo(buf, " version=\"%s\"", PG_XML_DEFAULT_VERSION);
if (encoding && encoding != PG_UTF8) if (encoding && encoding != PG_UTF8)
{
/* /*
* XXX might be useful to convert this to IANA names * XXX might be useful to convert this to IANA names
* (ISO-8859-1 instead of LATIN1 etc.); needs field experience * (ISO-8859-1 instead of LATIN1 etc.); needs field experience
*/ */
appendStringInfo(buf, " encoding=\"%s\"", pg_encoding_to_char(encoding)); appendStringInfo(buf, " encoding=\"%s\"",
pg_encoding_to_char(encoding));
}
if (standalone == 1) if (standalone == 1)
appendStringInfoString(buf, " standalone=\"yes\""); appendStringInfoString(buf, " standalone=\"yes\"");
...@@ -1155,10 +1187,12 @@ print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int stan ...@@ -1155,10 +1187,12 @@ print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int stan
/* /*
* Convert a C string to XML internal representation * Convert a C string to XML internal representation
* *
* TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c) * TODO maybe, libxml2's xmlreader is better? (do not construct DOM,
* yet do not use SAX - see xml_reader.c)
*/ */
static xmlDocPtr static xmlDocPtr
xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding) xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
xmlChar *encoding)
{ {
int32 len; int32 len;
xmlChar *string; xmlChar *string;
...@@ -1305,8 +1339,7 @@ xml_pstrdup(const char *string) ...@@ -1305,8 +1339,7 @@ xml_pstrdup(const char *string)
* any, as detail. * any, as detail.
*/ */
static void static void
xml_ereport(int level, int sqlcode, xml_ereport(int level, int sqlcode, const char *msg)
const char *msg)
{ {
char *detail; char *detail;
...@@ -1458,7 +1491,8 @@ is_valid_xml_namechar(pg_wchar c) ...@@ -1458,7 +1491,8 @@ is_valid_xml_namechar(pg_wchar c)
* Map SQL identifier to XML name; see SQL/XML:2003 section 9.1. * Map SQL identifier to XML name; see SQL/XML:2003 section 9.1.
*/ */
char * char *
map_sql_identifier_to_xml_name(char *ident, bool fully_escaped, bool escape_period) map_sql_identifier_to_xml_name(char *ident, bool fully_escaped,
bool escape_period)
{ {
#ifdef USE_LIBXML #ifdef USE_LIBXML
StringInfoData buf; StringInfoData buf;
...@@ -1592,36 +1626,38 @@ map_sql_value_to_xml_value(Datum value, Oid type) ...@@ -1592,36 +1626,38 @@ map_sql_value_to_xml_value(Datum value, Oid type)
if (type_is_array(type)) if (type_is_array(type))
{ {
int i;
ArrayType *array; ArrayType *array;
Oid elmtype; Oid elmtype;
int16 elmlen; int16 elmlen;
bool elmbyval; bool elmbyval;
char elmalign; char elmalign;
int num_elems;
Datum *elem_values;
bool *elem_nulls;
int i;
array = DatumGetArrayTypeP(value); 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); elmtype = ARR_ELEMTYPE(array);
get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign); get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign);
for (i = ARR_LBOUND(array)[0]; deconstruct_array(array, elmtype,
i < ARR_LBOUND(array)[0] + ARR_DIMS(array)[0]; elmlen, elmbyval, elmalign,
i++) &elem_values, &elem_nulls,
{ &num_elems);
Datum subval;
bool isnull;
subval = array_ref(array, 1, &i, -1, elmlen, elmbyval, elmalign, &isnull); for (i = 0; i < num_elems; i++)
{
if (elem_nulls[i])
continue;
appendStringInfoString(&buf, "<element>"); appendStringInfoString(&buf, "<element>");
appendStringInfoString(&buf, map_sql_value_to_xml_value(subval, elmtype)); appendStringInfoString(&buf,
map_sql_value_to_xml_value(elem_values[i],
elmtype));
appendStringInfoString(&buf, "</element>"); appendStringInfoString(&buf, "</element>");
} }
pfree(elem_values);
pfree(elem_nulls);
} }
else else
{ {
...@@ -1719,6 +1755,8 @@ map_sql_value_to_xml_value(Datum value, Oid type) ...@@ -1719,6 +1755,8 @@ map_sql_value_to_xml_value(Datum value, Oid type)
xmlTextWriterPtr writer; xmlTextWriterPtr writer;
char *result; char *result;
xml_init();
buf = xmlBufferCreate(); buf = xmlBufferCreate();
writer = xmlNewTextWriterMemory(buf, 0); writer = xmlNewTextWriterMemory(buf, 0);
...@@ -1825,13 +1863,15 @@ query_to_oid_list(const char *query) ...@@ -1825,13 +1863,15 @@ query_to_oid_list(const char *query)
for (i = 0; i < SPI_processed; i++) for (i = 0; i < SPI_processed; i++)
{ {
Oid oid; Datum oid;
bool isnull; bool isnull;
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull)); oid = SPI_getbinval(SPI_tuptable->vals[i],
if (isnull) SPI_tuptable->tupdesc,
continue; 1,
list = lappend_oid(list, oid); &isnull);
if (!isnull)
list = lappend_oid(list, DatumGetObjectId(oid));
} }
return list; return list;
...@@ -1854,9 +1894,9 @@ schema_get_xml_visible_tables(Oid nspid) ...@@ -1854,9 +1894,9 @@ schema_get_xml_visible_tables(Oid nspid)
* Including the system schemas is probably not useful for a database * Including the system schemas is probably not useful for a database
* mapping. * mapping.
*/ */
#define XML_VISIBLE_SCHEMAS_EXCLUDE "nspname LIKE 'pg_%' ESCAPE '' OR nspname = 'information_schema'" #define XML_VISIBLE_SCHEMAS_EXCLUDE "(nspname ~ '^pg_' OR nspname = 'information_schema')"
#define XML_VISIBLE_SCHEMAS "SELECT oid FROM pg_catalog.pg_namespace WHERE pg_catalog.has_schema_privilege (oid, 'USAGE') AND NOT (" XML_VISIBLE_SCHEMAS_EXCLUDE ")" #define XML_VISIBLE_SCHEMAS "SELECT oid FROM pg_catalog.pg_namespace WHERE pg_catalog.has_schema_privilege (oid, 'USAGE') AND NOT " XML_VISIBLE_SCHEMAS_EXCLUDE
static List * static List *
...@@ -1880,13 +1920,19 @@ database_get_xml_visible_tables(void) ...@@ -1880,13 +1920,19 @@ database_get_xml_visible_tables(void)
*/ */
static StringInfo static StringInfo
table_to_xml_internal(Oid relid, bool nulls, bool tableforest, const char *targetns, bool top_level) table_to_xml_internal(Oid relid,
const char *xmlschema, bool nulls, bool tableforest,
const char *targetns, bool top_level)
{ {
StringInfoData query; StringInfoData query;
initStringInfo(&query); initStringInfo(&query);
appendStringInfo(&query, "SELECT * FROM %s", DatumGetCString(DirectFunctionCall1(regclassout, ObjectIdGetDatum(relid)))); appendStringInfo(&query, "SELECT * FROM %s",
return query_to_xml_internal(query.data, get_rel_name(relid), NULL, nulls, tableforest, targetns, top_level); DatumGetCString(DirectFunctionCall1(regclassout,
ObjectIdGetDatum(relid))));
return query_to_xml_internal(query.data, get_rel_name(relid),
xmlschema, nulls, tableforest,
targetns, top_level);
} }
...@@ -1898,7 +1944,9 @@ table_to_xml(PG_FUNCTION_ARGS) ...@@ -1898,7 +1944,9 @@ table_to_xml(PG_FUNCTION_ARGS)
bool tableforest = PG_GETARG_BOOL(2); bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3)); const char *targetns = _textout(PG_GETARG_TEXT_P(3));
PG_RETURN_XML_P(stringinfo_to_xmltype(table_to_xml_internal(relid, nulls, tableforest, targetns, true))); PG_RETURN_XML_P(stringinfo_to_xmltype(table_to_xml_internal(relid, NULL,
nulls, tableforest,
targetns, true)));
} }
...@@ -1910,7 +1958,9 @@ query_to_xml(PG_FUNCTION_ARGS) ...@@ -1910,7 +1958,9 @@ query_to_xml(PG_FUNCTION_ARGS)
bool tableforest = PG_GETARG_BOOL(2); bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3)); const char *targetns = _textout(PG_GETARG_TEXT_P(3));
PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL, NULL, nulls, tableforest, targetns, true))); PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL,
NULL, nulls, tableforest,
targetns, true)));
} }
...@@ -1938,7 +1988,8 @@ cursor_to_xml(PG_FUNCTION_ARGS) ...@@ -1938,7 +1988,8 @@ cursor_to_xml(PG_FUNCTION_ARGS)
SPI_cursor_fetch(portal, true, count); SPI_cursor_fetch(portal, true, count);
for (i = 0; i < SPI_processed; i++) for (i = 0; i < SPI_processed; i++)
SPI_sql_row_to_xmlelement(i, &result, NULL, nulls, tableforest, targetns, true); SPI_sql_row_to_xmlelement(i, &result, NULL, nulls,
tableforest, targetns, true);
SPI_finish(); SPI_finish();
...@@ -1957,9 +2008,11 @@ cursor_to_xml(PG_FUNCTION_ARGS) ...@@ -1957,9 +2008,11 @@ cursor_to_xml(PG_FUNCTION_ARGS)
* namespace declarations are omitted, because they supposedly already * namespace declarations are omitted, because they supposedly already
* appeared earlier in the output. Repeating them is not wrong, but * appeared earlier in the output. Repeating them is not wrong, but
* it looks ugly. * it looks ugly.
*/ */
static void static void
xmldata_root_element_start(StringInfo result, const char *eltname, const char *xmlschema, const char *targetns, bool top_level) xmldata_root_element_start(StringInfo result, const char *eltname,
const char *xmlschema, const char *targetns,
bool top_level)
{ {
/* This isn't really wrong but currently makes no sense. */ /* This isn't really wrong but currently makes no sense. */
Assert(top_level || !xmlschema); Assert(top_level || !xmlschema);
...@@ -1991,7 +2044,9 @@ xmldata_root_element_end(StringInfo result, const char *eltname) ...@@ -1991,7 +2044,9 @@ xmldata_root_element_end(StringInfo result, const char *eltname)
static StringInfo static StringInfo
query_to_xml_internal(const char *query, char *tablename, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level) query_to_xml_internal(const char *query, char *tablename,
const char *xmlschema, bool nulls, bool tableforest,
const char *targetns, bool top_level)
{ {
StringInfo result; StringInfo result;
char *xmltn; char *xmltn;
...@@ -2011,13 +2066,15 @@ query_to_xml_internal(const char *query, char *tablename, const char *xmlschema, ...@@ -2011,13 +2066,15 @@ query_to_xml_internal(const char *query, char *tablename, const char *xmlschema,
errmsg("invalid query"))); errmsg("invalid query")));
if (!tableforest) if (!tableforest)
xmldata_root_element_start(result, xmltn, xmlschema, targetns, top_level); xmldata_root_element_start(result, xmltn, xmlschema,
targetns, top_level);
if (xmlschema) if (xmlschema)
appendStringInfo(result, "%s\n\n", xmlschema); appendStringInfo(result, "%s\n\n", xmlschema);
for(i = 0; i < SPI_processed; i++) for(i = 0; i < SPI_processed; i++)
SPI_sql_row_to_xmlelement(i, result, tablename, nulls, tableforest, targetns, top_level); SPI_sql_row_to_xmlelement(i, result, tablename, nulls,
tableforest, targetns, top_level);
if (!tableforest) if (!tableforest)
xmldata_root_element_end(result, xmltn); xmldata_root_element_end(result, xmltn);
...@@ -2035,12 +2092,12 @@ table_to_xmlschema(PG_FUNCTION_ARGS) ...@@ -2035,12 +2092,12 @@ table_to_xmlschema(PG_FUNCTION_ARGS)
bool nulls = PG_GETARG_BOOL(1); bool nulls = PG_GETARG_BOOL(1);
bool tableforest = PG_GETARG_BOOL(2); bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3)); const char *targetns = _textout(PG_GETARG_TEXT_P(3));
const char *result; const char *result;
Relation rel; Relation rel;
rel = heap_open(relid, AccessShareLock); rel = heap_open(relid, AccessShareLock);
result = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls, tableforest, targetns); result = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls,
tableforest, targetns);
heap_close(rel, NoLock); heap_close(rel, NoLock);
PG_RETURN_XML_P(cstring_to_xmltype(result)); PG_RETURN_XML_P(cstring_to_xmltype(result));
...@@ -2054,7 +2111,6 @@ query_to_xmlschema(PG_FUNCTION_ARGS) ...@@ -2054,7 +2111,6 @@ query_to_xmlschema(PG_FUNCTION_ARGS)
bool nulls = PG_GETARG_BOOL(1); bool nulls = PG_GETARG_BOOL(1);
bool tableforest = PG_GETARG_BOOL(2); bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3)); const char *targetns = _textout(PG_GETARG_TEXT_P(3));
const char *result; const char *result;
SPIPlanPtr plan; SPIPlanPtr plan;
Portal portal; Portal portal;
...@@ -2062,7 +2118,9 @@ query_to_xmlschema(PG_FUNCTION_ARGS) ...@@ -2062,7 +2118,9 @@ query_to_xmlschema(PG_FUNCTION_ARGS)
SPI_connect(); SPI_connect();
plan = SPI_prepare(query, 0, NULL); plan = SPI_prepare(query, 0, NULL);
portal = SPI_cursor_open(NULL, plan, NULL, NULL, true); portal = SPI_cursor_open(NULL, plan, NULL, NULL, true);
result = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc, InvalidOid, nulls, tableforest, targetns)); result = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc,
InvalidOid, nulls,
tableforest, targetns));
SPI_cursor_close(portal); SPI_cursor_close(portal);
SPI_finish(); SPI_finish();
...@@ -2077,7 +2135,6 @@ cursor_to_xmlschema(PG_FUNCTION_ARGS) ...@@ -2077,7 +2135,6 @@ cursor_to_xmlschema(PG_FUNCTION_ARGS)
bool nulls = PG_GETARG_BOOL(1); bool nulls = PG_GETARG_BOOL(1);
bool tableforest = PG_GETARG_BOOL(2); bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3)); const char *targetns = _textout(PG_GETARG_TEXT_P(3));
const char *xmlschema; const char *xmlschema;
Portal portal; Portal portal;
...@@ -2088,7 +2145,9 @@ cursor_to_xmlschema(PG_FUNCTION_ARGS) ...@@ -2088,7 +2145,9 @@ cursor_to_xmlschema(PG_FUNCTION_ARGS)
(errcode(ERRCODE_UNDEFINED_CURSOR), (errcode(ERRCODE_UNDEFINED_CURSOR),
errmsg("cursor \"%s\" does not exist", name))); errmsg("cursor \"%s\" does not exist", name)));
xmlschema = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc, InvalidOid, nulls, tableforest, targetns)); xmlschema = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc,
InvalidOid, nulls,
tableforest, targetns));
SPI_finish(); SPI_finish();
PG_RETURN_XML_P(cstring_to_xmltype(xmlschema)); PG_RETURN_XML_P(cstring_to_xmltype(xmlschema));
...@@ -2102,19 +2161,17 @@ table_to_xml_and_xmlschema(PG_FUNCTION_ARGS) ...@@ -2102,19 +2161,17 @@ table_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
bool nulls = PG_GETARG_BOOL(1); bool nulls = PG_GETARG_BOOL(1);
bool tableforest = PG_GETARG_BOOL(2); bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3)); const char *targetns = _textout(PG_GETARG_TEXT_P(3));
StringInfoData query;
Relation rel; Relation rel;
const char *xmlschema; const char *xmlschema;
rel = heap_open(relid, AccessShareLock); rel = heap_open(relid, AccessShareLock);
xmlschema = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls, tableforest, targetns); xmlschema = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls,
tableforest, targetns);
heap_close(rel, NoLock); heap_close(rel, NoLock);
initStringInfo(&query); PG_RETURN_XML_P(stringinfo_to_xmltype(table_to_xml_internal(relid,
appendStringInfo(&query, "SELECT * FROM %s", DatumGetCString(DirectFunctionCall1(regclassout, ObjectIdGetDatum(relid)))); xmlschema, nulls, tableforest,
targetns, true)));
PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query.data, get_rel_name(relid), xmlschema, nulls, tableforest, targetns, true)));
} }
...@@ -2133,11 +2190,14 @@ query_to_xml_and_xmlschema(PG_FUNCTION_ARGS) ...@@ -2133,11 +2190,14 @@ query_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
SPI_connect(); SPI_connect();
plan = SPI_prepare(query, 0, NULL); plan = SPI_prepare(query, 0, NULL);
portal = SPI_cursor_open(NULL, plan, NULL, NULL, true); portal = SPI_cursor_open(NULL, plan, NULL, NULL, true);
xmlschema = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc, InvalidOid, nulls, tableforest, targetns)); xmlschema = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc,
InvalidOid, nulls, tableforest, targetns));
SPI_cursor_close(portal); SPI_cursor_close(portal);
SPI_finish(); SPI_finish();
PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL, xmlschema, nulls, tableforest, targetns, true))); PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL,
xmlschema, nulls, tableforest,
targetns, true)));
} }
...@@ -2147,14 +2207,16 @@ query_to_xml_and_xmlschema(PG_FUNCTION_ARGS) ...@@ -2147,14 +2207,16 @@ query_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
*/ */
static StringInfo static StringInfo
schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level) schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls,
bool tableforest, const char *targetns, bool top_level)
{ {
StringInfo result; StringInfo result;
char *xmlsn; char *xmlsn;
List *relid_list; List *relid_list;
ListCell *cell; ListCell *cell;
xmlsn = map_sql_identifier_to_xml_name(get_namespace_name(nspid), true, false); xmlsn = map_sql_identifier_to_xml_name(get_namespace_name(nspid),
true, false);
result = makeStringInfo(); result = makeStringInfo();
xmldata_root_element_start(result, xmlsn, xmlschema, targetns, top_level); xmldata_root_element_start(result, xmlsn, xmlschema, targetns, top_level);
...@@ -2173,7 +2235,8 @@ schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, bool tablef ...@@ -2173,7 +2235,8 @@ schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, bool tablef
Oid relid = lfirst_oid(cell); Oid relid = lfirst_oid(cell);
StringInfo subres; StringInfo subres;
subres = table_to_xml_internal(relid, nulls, tableforest, targetns, false); subres = table_to_xml_internal(relid, NULL, nulls, tableforest,
targetns, false);
appendStringInfoString(result, subres->data); appendStringInfoString(result, subres->data);
appendStringInfoChar(result, '\n'); appendStringInfoChar(result, '\n');
...@@ -2202,7 +2265,8 @@ schema_to_xml(PG_FUNCTION_ARGS) ...@@ -2202,7 +2265,8 @@ schema_to_xml(PG_FUNCTION_ARGS)
schemaname = NameStr(*name); schemaname = NameStr(*name);
nspid = LookupExplicitNamespace(schemaname); nspid = LookupExplicitNamespace(schemaname);
PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xml_internal(nspid, NULL, nulls, tableforest, targetns, true))); PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xml_internal(nspid, NULL,
nulls, tableforest, targetns, true)));
} }
...@@ -2229,13 +2293,13 @@ xsd_schema_element_start(StringInfo result, const char *targetns) ...@@ -2229,13 +2293,13 @@ xsd_schema_element_start(StringInfo result, const char *targetns)
static void static void
xsd_schema_element_end(StringInfo result) xsd_schema_element_end(StringInfo result)
{ {
appendStringInfoString(result, appendStringInfoString(result, "</xsd:schema>");
"</xsd:schema>");
} }
static StringInfo static StringInfo
schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tableforest, const char *targetns) schema_to_xmlschema_internal(const char *schemaname, bool nulls,
bool tableforest, const char *targetns)
{ {
Oid nspid; Oid nspid;
List *relid_list; List *relid_list;
...@@ -2259,7 +2323,7 @@ schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tablefores ...@@ -2259,7 +2323,7 @@ schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tablefores
Relation rel; Relation rel;
rel = heap_open(lfirst_oid(cell), AccessShareLock); rel = heap_open(lfirst_oid(cell), AccessShareLock);
tupdesc_list = lappend(tupdesc_list, rel->rd_att); tupdesc_list = lappend(tupdesc_list, CreateTupleDescCopy(rel->rd_att));
heap_close(rel, NoLock); heap_close(rel, NoLock);
} }
...@@ -2267,7 +2331,8 @@ schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tablefores ...@@ -2267,7 +2331,8 @@ schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tablefores
map_sql_typecoll_to_xmlschema_types(tupdesc_list)); map_sql_typecoll_to_xmlschema_types(tupdesc_list));
appendStringInfoString(result, appendStringInfoString(result,
map_sql_schema_to_xmlschema_types(nspid, relid_list, nulls, tableforest, targetns)); map_sql_schema_to_xmlschema_types(nspid, relid_list,
nulls, tableforest, targetns));
xsd_schema_element_end(result); xsd_schema_element_end(result);
...@@ -2285,7 +2350,8 @@ schema_to_xmlschema(PG_FUNCTION_ARGS) ...@@ -2285,7 +2350,8 @@ schema_to_xmlschema(PG_FUNCTION_ARGS)
bool tableforest = PG_GETARG_BOOL(2); bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3)); const char *targetns = _textout(PG_GETARG_TEXT_P(3));
PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xmlschema_internal(NameStr(*name), nulls, tableforest, targetns))); PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xmlschema_internal(NameStr(*name),
nulls, tableforest, targetns)));
} }
...@@ -2296,7 +2362,6 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS) ...@@ -2296,7 +2362,6 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
bool nulls = PG_GETARG_BOOL(1); bool nulls = PG_GETARG_BOOL(1);
bool tableforest = PG_GETARG_BOOL(2); bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3)); const char *targetns = _textout(PG_GETARG_TEXT_P(3));
char *schemaname; char *schemaname;
Oid nspid; Oid nspid;
StringInfo xmlschema; StringInfo xmlschema;
...@@ -2304,9 +2369,12 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS) ...@@ -2304,9 +2369,12 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
schemaname = NameStr(*name); schemaname = NameStr(*name);
nspid = LookupExplicitNamespace(schemaname); nspid = LookupExplicitNamespace(schemaname);
xmlschema = schema_to_xmlschema_internal(schemaname, nulls, tableforest, targetns); xmlschema = schema_to_xmlschema_internal(schemaname, nulls,
tableforest, targetns);
PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xml_internal(nspid, xmlschema->data, nulls, tableforest, targetns, true))); PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xml_internal(nspid,
xmlschema->data, nulls,
tableforest, targetns, true)));
} }
...@@ -2316,14 +2384,16 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS) ...@@ -2316,14 +2384,16 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
*/ */
static StringInfo static StringInfo
database_to_xml_internal(const char *xmlschema, bool nulls, bool tableforest, const char *targetns) database_to_xml_internal(const char *xmlschema, bool nulls,
bool tableforest, const char *targetns)
{ {
StringInfo result; StringInfo result;
List *nspid_list; List *nspid_list;
ListCell *cell; ListCell *cell;
char *xmlcn; char *xmlcn;
xmlcn = map_sql_identifier_to_xml_name(get_database_name(MyDatabaseId), true, false); xmlcn = map_sql_identifier_to_xml_name(get_database_name(MyDatabaseId),
true, false);
result = makeStringInfo(); result = makeStringInfo();
xmldata_root_element_start(result, xmlcn, xmlschema, targetns, true); xmldata_root_element_start(result, xmlcn, xmlschema, targetns, true);
...@@ -2342,7 +2412,8 @@ database_to_xml_internal(const char *xmlschema, bool nulls, bool tableforest, co ...@@ -2342,7 +2412,8 @@ database_to_xml_internal(const char *xmlschema, bool nulls, bool tableforest, co
Oid nspid = lfirst_oid(cell); Oid nspid = lfirst_oid(cell);
StringInfo subres; StringInfo subres;
subres = schema_to_xml_internal(nspid, NULL, nulls, tableforest, targetns, false); subres = schema_to_xml_internal(nspid, NULL, nulls,
tableforest, targetns, false);
appendStringInfoString(result, subres->data); appendStringInfoString(result, subres->data);
appendStringInfoChar(result, '\n'); appendStringInfoChar(result, '\n');
...@@ -2364,12 +2435,14 @@ database_to_xml(PG_FUNCTION_ARGS) ...@@ -2364,12 +2435,14 @@ database_to_xml(PG_FUNCTION_ARGS)
bool tableforest = PG_GETARG_BOOL(1); bool tableforest = PG_GETARG_BOOL(1);
const char *targetns = _textout(PG_GETARG_TEXT_P(2)); const char *targetns = _textout(PG_GETARG_TEXT_P(2));
PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xml_internal(NULL, nulls, tableforest, targetns))); PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xml_internal(NULL, nulls,
tableforest, targetns)));
} }
static StringInfo static StringInfo
database_to_xmlschema_internal(bool nulls, bool tableforest, const char *targetns) database_to_xmlschema_internal(bool nulls, bool tableforest,
const char *targetns)
{ {
List *relid_list; List *relid_list;
List *nspid_list; List *nspid_list;
...@@ -2392,7 +2465,7 @@ database_to_xmlschema_internal(bool nulls, bool tableforest, const char *targetn ...@@ -2392,7 +2465,7 @@ database_to_xmlschema_internal(bool nulls, bool tableforest, const char *targetn
Relation rel; Relation rel;
rel = heap_open(lfirst_oid(cell), AccessShareLock); rel = heap_open(lfirst_oid(cell), AccessShareLock);
tupdesc_list = lappend(tupdesc_list, rel->rd_att); tupdesc_list = lappend(tupdesc_list, CreateTupleDescCopy(rel->rd_att));
heap_close(rel, NoLock); heap_close(rel, NoLock);
} }
...@@ -2417,7 +2490,8 @@ database_to_xmlschema(PG_FUNCTION_ARGS) ...@@ -2417,7 +2490,8 @@ database_to_xmlschema(PG_FUNCTION_ARGS)
bool tableforest = PG_GETARG_BOOL(1); bool tableforest = PG_GETARG_BOOL(1);
const char *targetns = _textout(PG_GETARG_TEXT_P(2)); const char *targetns = _textout(PG_GETARG_TEXT_P(2));
PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xmlschema_internal(nulls, tableforest, targetns))); PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xmlschema_internal(nulls,
tableforest, targetns)));
} }
...@@ -2427,12 +2501,12 @@ database_to_xml_and_xmlschema(PG_FUNCTION_ARGS) ...@@ -2427,12 +2501,12 @@ database_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
bool nulls = PG_GETARG_BOOL(0); bool nulls = PG_GETARG_BOOL(0);
bool tableforest = PG_GETARG_BOOL(1); bool tableforest = PG_GETARG_BOOL(1);
const char *targetns = _textout(PG_GETARG_TEXT_P(2)); const char *targetns = _textout(PG_GETARG_TEXT_P(2));
StringInfo xmlschema; StringInfo xmlschema;
xmlschema = database_to_xmlschema_internal(nulls, tableforest, targetns); xmlschema = database_to_xmlschema_internal(nulls, tableforest, targetns);
PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xml_internal(xmlschema->data, nulls, tableforest, targetns))); PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xml_internal(xmlschema->data,
nulls, tableforest, targetns)));
} }
...@@ -2448,13 +2522,17 @@ map_multipart_sql_identifier_to_xml_name(char *a, char *b, char *c, char *d) ...@@ -2448,13 +2522,17 @@ map_multipart_sql_identifier_to_xml_name(char *a, char *b, char *c, char *d)
initStringInfo(&result); initStringInfo(&result);
if (a) if (a)
appendStringInfo(&result, "%s", map_sql_identifier_to_xml_name(a, true, true)); appendStringInfo(&result, "%s",
map_sql_identifier_to_xml_name(a, true, true));
if (b) if (b)
appendStringInfo(&result, ".%s", map_sql_identifier_to_xml_name(b, true, true)); appendStringInfo(&result, ".%s",
map_sql_identifier_to_xml_name(b, true, true));
if (c) if (c)
appendStringInfo(&result, ".%s", map_sql_identifier_to_xml_name(c, true, true)); appendStringInfo(&result, ".%s",
map_sql_identifier_to_xml_name(c, true, true));
if (d) if (d)
appendStringInfo(&result, ".%s", map_sql_identifier_to_xml_name(d, true, true)); appendStringInfo(&result, ".%s",
map_sql_identifier_to_xml_name(d, true, true));
return result.data; return result.data;
} }
...@@ -2468,7 +2546,8 @@ map_multipart_sql_identifier_to_xml_name(char *a, char *b, char *c, char *d) ...@@ -2468,7 +2546,8 @@ map_multipart_sql_identifier_to_xml_name(char *a, char *b, char *c, char *d)
* 9.6. * 9.6.
*/ */
static const char * static const char *
map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tableforest, const char *targetns) map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls,
bool tableforest, const char *targetns)
{ {
int i; int i;
char *xmltn; char *xmltn;
...@@ -2478,12 +2557,20 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef ...@@ -2478,12 +2557,20 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
initStringInfo(&result); initStringInfo(&result);
if (relid) if (OidIsValid(relid))
{ {
HeapTuple tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relid), 0, 0, 0); HeapTuple tuple;
Form_pg_class reltuple = (Form_pg_class) GETSTRUCT(tuple); Form_pg_class reltuple;
tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for relation %u", relid);
reltuple = (Form_pg_class) GETSTRUCT(tuple);
xmltn = map_sql_identifier_to_xml_name(NameStr(reltuple->relname), true, false); xmltn = map_sql_identifier_to_xml_name(NameStr(reltuple->relname),
true, false);
tabletypename = map_multipart_sql_identifier_to_xml_name("TableType", tabletypename = map_multipart_sql_identifier_to_xml_name("TableType",
get_database_name(MyDatabaseId), get_database_name(MyDatabaseId),
...@@ -2521,7 +2608,8 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef ...@@ -2521,7 +2608,8 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
for (i = 0; i < tupdesc->natts; i++) for (i = 0; i < tupdesc->natts; i++)
appendStringInfo(&result, appendStringInfo(&result,
" <xsd:element name=\"%s\" type=\"%s\"%s></xsd:element>\n", " <xsd:element name=\"%s\" type=\"%s\"%s></xsd:element>\n",
map_sql_identifier_to_xml_name(NameStr(tupdesc->attrs[i]->attname), true, false), map_sql_identifier_to_xml_name(NameStr(tupdesc->attrs[i]->attname),
true, false),
map_sql_type_to_xml_name(tupdesc->attrs[i]->atttypid, -1), map_sql_type_to_xml_name(tupdesc->attrs[i]->atttypid, -1),
nulls ? " nillable=\"true\"" : " minOccurs=\"0\""); nulls ? " nillable=\"true\"" : " minOccurs=\"0\"");
...@@ -2559,20 +2647,26 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef ...@@ -2559,20 +2647,26 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
* 9.7. * 9.7.
*/ */
static const char * static const char *
map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool tableforest, const char *targetns) map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls,
bool tableforest, const char *targetns)
{ {
char *dbname;
char *nspname;
char *xmlsn; char *xmlsn;
char *schematypename; char *schematypename;
StringInfoData result; StringInfoData result;
ListCell *cell; ListCell *cell;
dbname = get_database_name(MyDatabaseId);
nspname = get_namespace_name(nspid);
initStringInfo(&result); initStringInfo(&result);
xmlsn = map_sql_identifier_to_xml_name(get_namespace_name(nspid), true, false); xmlsn = map_sql_identifier_to_xml_name(nspname, true, false);
schematypename = map_multipart_sql_identifier_to_xml_name("SchemaType", schematypename = map_multipart_sql_identifier_to_xml_name("SchemaType",
get_database_name(MyDatabaseId), dbname,
get_namespace_name(nspid), nspname,
NULL); NULL);
appendStringInfo(&result, appendStringInfo(&result,
...@@ -2587,11 +2681,12 @@ map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool ...@@ -2587,11 +2681,12 @@ map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool
foreach (cell, relid_list) foreach (cell, relid_list)
{ {
Oid relid = lfirst_oid(cell); Oid relid = lfirst_oid(cell);
char *xmltn = map_sql_identifier_to_xml_name(get_rel_name(relid), true, false); char *relname = get_rel_name(relid);
char *xmltn = map_sql_identifier_to_xml_name(relname, true, false);
char *tabletypename = map_multipart_sql_identifier_to_xml_name(tableforest ? "RowType" : "TableType", char *tabletypename = map_multipart_sql_identifier_to_xml_name(tableforest ? "RowType" : "TableType",
get_database_name(MyDatabaseId), dbname,
get_namespace_name(nspid), nspname,
get_rel_name(relid)); relname);
if (!tableforest) if (!tableforest)
appendStringInfo(&result, appendStringInfo(&result,
...@@ -2625,19 +2720,23 @@ map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool ...@@ -2625,19 +2720,23 @@ map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool
* 9.8. * 9.8.
*/ */
static const char * static const char *
map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tableforest, const char *targetns) map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls,
bool tableforest, const char *targetns)
{ {
char *dbname;
char *xmlcn; char *xmlcn;
char *catalogtypename; char *catalogtypename;
StringInfoData result; StringInfoData result;
ListCell *cell; ListCell *cell;
dbname = get_database_name(MyDatabaseId);
initStringInfo(&result); initStringInfo(&result);
xmlcn = map_sql_identifier_to_xml_name(get_database_name(MyDatabaseId), true, false); xmlcn = map_sql_identifier_to_xml_name(dbname, true, false);
catalogtypename = map_multipart_sql_identifier_to_xml_name("CatalogType", catalogtypename = map_multipart_sql_identifier_to_xml_name("CatalogType",
get_database_name(MyDatabaseId), dbname,
NULL, NULL,
NULL); NULL);
...@@ -2649,10 +2748,11 @@ map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tablefores ...@@ -2649,10 +2748,11 @@ map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tablefores
foreach (cell, nspid_list) foreach (cell, nspid_list)
{ {
Oid nspid = lfirst_oid(cell); Oid nspid = lfirst_oid(cell);
char *xmlsn = map_sql_identifier_to_xml_name(get_namespace_name(nspid), true, false); char *nspname = get_namespace_name(nspid);
char *xmlsn = map_sql_identifier_to_xml_name(nspname, true, false);
char *schematypename = map_multipart_sql_identifier_to_xml_name("SchemaType", char *schematypename = map_multipart_sql_identifier_to_xml_name("SchemaType",
get_database_name(MyDatabaseId), dbname,
get_namespace_name(nspid), nspname,
NULL); NULL);
appendStringInfo(&result, appendStringInfo(&result,
...@@ -2755,8 +2855,15 @@ map_sql_type_to_xml_name(Oid typeoid, int typmod) ...@@ -2755,8 +2855,15 @@ map_sql_type_to_xml_name(Oid typeoid, int typmod)
break; break;
default: default:
{ {
HeapTuple tuple = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), 0, 0, 0); HeapTuple tuple;
Form_pg_type typtuple = (Form_pg_type) GETSTRUCT(tuple); Form_pg_type typtuple;
tuple = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typeoid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for type %u", typeoid);
typtuple = (Form_pg_type) GETSTRUCT(tuple);
appendStringInfoString(&result, appendStringInfoString(&result,
map_multipart_sql_identifier_to_xml_name((typtuple->typtype == TYPTYPE_DOMAIN) ? "Domain" : "UDT", map_multipart_sql_identifier_to_xml_name((typtuple->typtype == TYPTYPE_DOMAIN) ? "Domain" : "UDT",
...@@ -2976,7 +3083,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod) ...@@ -2976,7 +3083,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
" <xsd:restriction base=\"xsd:date\">\n" " <xsd:restriction base=\"xsd:date\">\n"
" <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}\"/>\n" " <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}\"/>\n"
" </xsd:restriction>\n"); " </xsd:restriction>\n");
break; break;
default: default:
if (get_typtype(typeoid) == TYPTYPE_DOMAIN) if (get_typtype(typeoid) == TYPTYPE_DOMAIN)
...@@ -2990,6 +3097,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod) ...@@ -2990,6 +3097,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
" <xsd:restriction base=\"%s\">\n", " <xsd:restriction base=\"%s\">\n",
map_sql_type_to_xml_name(base_typeoid, base_typmod)); map_sql_type_to_xml_name(base_typeoid, base_typmod));
} }
break;
} }
appendStringInfo(&result, appendStringInfo(&result,
"</xsd:simpleType>\n"); "</xsd:simpleType>\n");
...@@ -3004,7 +3112,9 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod) ...@@ -3004,7 +3112,9 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
* SPI cursor. See also SQL/XML:2003 section 9.12. * SPI cursor. See also SQL/XML:2003 section 9.12.
*/ */
static void static void
SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool nulls, bool tableforest, const char *targetns, bool top_level) SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename,
bool nulls, bool tableforest,
const char *targetns, bool top_level)
{ {
int i; int i;
char *xmltn; char *xmltn;
...@@ -3030,9 +3140,12 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n ...@@ -3030,9 +3140,12 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
Datum colval; Datum colval;
bool isnull; bool isnull;
colname = map_sql_identifier_to_xml_name(SPI_fname(SPI_tuptable->tupdesc, i), true, false); colname = map_sql_identifier_to_xml_name(SPI_fname(SPI_tuptable->tupdesc, i),
colval = SPI_getbinval(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i, &isnull); true, false);
colval = SPI_getbinval(SPI_tuptable->vals[rownum],
SPI_tuptable->tupdesc,
i,
&isnull);
if (isnull) if (isnull)
{ {
if (nulls) if (nulls)
...@@ -3040,7 +3153,9 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n ...@@ -3040,7 +3153,9 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
} }
else else
appendStringInfo(result, " <%s>%s</%s>\n", appendStringInfo(result, " <%s>%s</%s>\n",
colname, map_sql_value_to_xml_value(colval, SPI_gettypeid(SPI_tuptable->tupdesc, i)), colname,
map_sql_value_to_xml_value(colval,
SPI_gettypeid(SPI_tuptable->tupdesc, i)),
colname); colname);
} }
...@@ -3060,9 +3175,10 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n ...@@ -3060,9 +3175,10 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
#ifdef USE_LIBXML #ifdef USE_LIBXML
/* /*
* Convert XML node to text (dump subtree in case of element, return value otherwise) * Convert XML node to text (dump subtree in case of element,
* return value otherwise)
*/ */
text * static text *
xml_xmlnodetoxmltype(xmlNodePtr cur) xml_xmlnodetoxmltype(xmlNodePtr cur)
{ {
xmlChar *str; xmlChar *str;
...@@ -3093,9 +3209,10 @@ xml_xmlnodetoxmltype(xmlNodePtr cur) ...@@ -3093,9 +3209,10 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
/* /*
* Evaluate XPath expression and return array of XML values. * Evaluate XPath expression and return array of XML values.
* As we have no support of XQuery sequences yet, this functions seems *
* As we have no support of XQuery sequences yet, this function seems
* to be the most useful one (array of XML functions plays a role of * to be the most useful one (array of XML functions plays a role of
* some kind of substritution for XQuery sequences). * some kind of substitution for XQuery sequences).
* *
* Workaround here: we parse XML data in different way to allow XPath for * Workaround here: we parse XML data in different way to allow XPath for
* fragments (see "XPath for fragment" TODO comment inside). * fragments (see "XPath for fragment" TODO comment inside).
...@@ -3107,13 +3224,13 @@ xpath(PG_FUNCTION_ARGS) ...@@ -3107,13 +3224,13 @@ xpath(PG_FUNCTION_ARGS)
text *xpath_expr_text = PG_GETARG_TEXT_P(0); text *xpath_expr_text = PG_GETARG_TEXT_P(0);
xmltype *data = PG_GETARG_XML_P(1); xmltype *data = PG_GETARG_XML_P(1);
ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2); ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
ArrayBuildState *astate = NULL; ArrayBuildState *astate = NULL;
xmlParserCtxtPtr ctxt = NULL; xmlParserCtxtPtr ctxt = NULL;
xmlDocPtr doc = NULL; xmlDocPtr doc = NULL;
xmlXPathContextPtr xpathctx = NULL; xmlXPathContextPtr xpathctx = NULL;
xmlXPathCompExprPtr xpathcomp = NULL; xmlXPathCompExprPtr xpathcomp = NULL;
xmlXPathObjectPtr xpathobj = NULL; xmlXPathObjectPtr xpathobj = NULL;
char *datastr;
int32 len; int32 len;
int32 xpath_len; int32 xpath_len;
xmlChar *string; xmlChar *string;
...@@ -3121,14 +3238,14 @@ xpath(PG_FUNCTION_ARGS) ...@@ -3121,14 +3238,14 @@ xpath(PG_FUNCTION_ARGS)
int i; int i;
int res_nitems; int res_nitems;
int ndim; int ndim;
Datum *ns_names_uris;
bool *ns_names_uris_nulls;
int ns_count; int ns_count;
char **ns_names;
char **ns_uris;
/* /*
* Namespace mappings are passed as text[]. If an empty array is * Namespace mappings are passed as text[]. If an empty array is
* passed (ndim = 0, "0-dimentional"), then there are no namespace * passed (ndim = 0, "0-dimensional"), then there are no namespace
* mappings. Else, a 2-dimentional array with length of the * mappings. Else, a 2-dimensional array with length of the
* second axis being equal to 2 should be passed, i.e., every * second axis being equal to 2 should be passed, i.e., every
* subarray contains 2 elements, the first element defining the * subarray contains 2 elements, the first element defining the
* name, the second one the URI. Example: ARRAY[ARRAY['myns', * name, the second one the URI. Example: ARRAY[ARRAY['myns',
...@@ -3137,71 +3254,39 @@ xpath(PG_FUNCTION_ARGS) ...@@ -3137,71 +3254,39 @@ xpath(PG_FUNCTION_ARGS)
ndim = ARR_NDIM(namespaces); ndim = ARR_NDIM(namespaces);
if (ndim != 0) if (ndim != 0)
{ {
bits8 *bitmap;
int bitmask;
int16 typlen;
bool typbyval;
char typalign;
char *ptr;
int *dims; int *dims;
dims = ARR_DIMS(namespaces); dims = ARR_DIMS(namespaces);
if (ndim != 2 || dims[1] != 2) if (ndim != 2 || dims[1] != 2)
ereport(ERROR, (errmsg("invalid array for XML namespace mapping"), ereport(ERROR,
errdetail("The array must be two-dimensional with length of the second axis equal to 2."), (errcode(ERRCODE_DATA_EXCEPTION),
errcode(ERRCODE_DATA_EXCEPTION))); errmsg("invalid array for XML namespace mapping"),
errdetail("The array must be two-dimensional with length of the second axis equal to 2.")));
Assert(ARR_ELEMTYPE(namespaces) == TEXTOID); Assert(ARR_ELEMTYPE(namespaces) == TEXTOID);
ns_count = ArrayGetNItems(ndim, dims) / 2; /* number of NS mappings */ deconstruct_array(namespaces, TEXTOID, -1, false, 'i',
get_typlenbyvalalign(ARR_ELEMTYPE(namespaces), &ns_names_uris, &ns_names_uris_nulls,
&typlen, &typbyval, &typalign); &ns_count);
ns_names = palloc(ns_count * sizeof(char *));
ns_uris = palloc(ns_count * sizeof(char *));
ptr = ARR_DATA_PTR(namespaces);
bitmap = ARR_NULLBITMAP(namespaces);
bitmask = 1;
for (i = 0; i < ns_count * 2; i++)
{
if (bitmap && (*bitmap & bitmask) == 0)
ereport(ERROR, (errmsg("neither namespace name nor URI may be null")));
else
{
if (i % 2 == 0)
ns_names[i / 2] = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(ptr)));
else
ns_uris[i / 2] = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(ptr)));
ptr = att_addlength_pointer(ptr, typlen, ptr);
ptr = (char *) att_align_nominal(ptr, typalign);
}
/* advance bitmap pointer if any */ Assert((ns_count % 2) == 0); /* checked above */
if (bitmap) ns_count /= 2; /* count pairs only */
{
bitmask <<= 1;
if (bitmask == 0x100)
{
bitmap++;
bitmask = 1;
}
}
}
} }
else else
{ {
ns_names_uris = NULL;
ns_names_uris_nulls = NULL;
ns_count = 0; ns_count = 0;
ns_names = NULL;
ns_uris = NULL;
} }
datastr = VARDATA(data);
len = VARSIZE(data) - VARHDRSZ; len = VARSIZE(data) - VARHDRSZ;
xpath_len = VARSIZE(xpath_expr_text) - VARHDRSZ; xpath_len = VARSIZE(xpath_expr_text) - VARHDRSZ;
if (xpath_len == 0) if (xpath_len == 0)
ereport(ERROR, (errmsg("empty XPath expression"), ereport(ERROR,
errcode(ERRCODE_DATA_EXCEPTION))); (errcode(ERRCODE_DATA_EXCEPTION),
errmsg("empty XPath expression")));
/* /*
* To handle both documents and fragments, regardless of the fact * To handle both documents and fragments, regardless of the fact
...@@ -3210,10 +3295,12 @@ xpath(PG_FUNCTION_ARGS) ...@@ -3210,10 +3295,12 @@ xpath(PG_FUNCTION_ARGS)
* extend the XPath expression accordingly. To do it, throw away * extend the XPath expression accordingly. To do it, throw away
* the XML prolog, if any. * the XML prolog, if any.
*/ */
if ((len > 4) && xmlStrncmp((xmlChar *) VARDATA(data), (xmlChar *) "<?xml", 5) == 0) if (len >= 5 &&
xmlStrncmp((xmlChar *) datastr, (xmlChar *) "<?xml", 5) == 0)
{ {
i = 5; i = 5;
while ((i < len) && (('?' != (VARDATA(data))[i - 1]) || ('>' != (VARDATA(data))[i]))) while (i < len &&
!(datastr[i - 1] == '?' && datastr[i] == '>'))
i++; i++;
if (i == len) if (i == len)
...@@ -3221,14 +3308,17 @@ xpath(PG_FUNCTION_ARGS) ...@@ -3221,14 +3308,17 @@ xpath(PG_FUNCTION_ARGS)
"could not parse XML data"); "could not parse XML data");
++i; ++i;
string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data) + i, len - i); string = xmlStrncatNew((xmlChar *) "<x>",
(xmlChar *) datastr + i, len - i);
} }
else else
string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data), len); string = xmlStrncatNew((xmlChar *) "<x>",
(xmlChar *) datastr, len);
string = xmlStrncat(string, (xmlChar *) "</x>", 5); string = xmlStrncat(string, (xmlChar *) "</x>", 5);
len += 7; len += 7;
xpath_expr = xmlStrncatNew((xmlChar *) "/x", (xmlChar *) VARDATA(xpath_expr_text), xpath_len); xpath_expr = xmlStrncatNew((xmlChar *) "/x",
(xmlChar *) VARDATA(xpath_expr_text), xpath_len);
xpath_len += 2; xpath_len += 2;
xml_init(); xml_init();
...@@ -3259,21 +3349,38 @@ xpath(PG_FUNCTION_ARGS) ...@@ -3259,21 +3349,38 @@ xpath(PG_FUNCTION_ARGS)
"could not find root XML element"); "could not find root XML element");
/* register namespaces, if any */ /* register namespaces, if any */
if ((ns_count > 0) && ns_names && ns_uris) if (ns_count > 0)
{
for (i = 0; i < ns_count; i++) for (i = 0; i < ns_count; i++)
if (0 != xmlXPathRegisterNs(xpathctx, (xmlChar *) ns_names[i], (xmlChar *) ns_uris[i])) {
char *ns_name;
char *ns_uri;
if (ns_names_uris_nulls[i * 2] ||
ns_names_uris_nulls[i * 2 + 1])
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("neither namespace name nor URI may be null")));
ns_name = _textout(ns_names_uris[i * 2]);
ns_uri = _textout(ns_names_uris[i * 2 + 1]);
if (xmlXPathRegisterNs(xpathctx,
(xmlChar *) ns_name,
(xmlChar *) ns_uri) != 0)
ereport(ERROR, /* is this an internal error??? */
(errmsg("could not register XML namespace with name \"%s\" and URI \"%s\"", (errmsg("could not register XML namespace with name \"%s\" and URI \"%s\"",
ns_names[i], ns_uris[i]))); ns_name, ns_uri)));
}
}
xpathcomp = xmlXPathCompile(xpath_expr); xpathcomp = xmlXPathCompile(xpath_expr);
if (xpathcomp == NULL) if (xpathcomp == NULL) /* TODO: show proper XPath error details */
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR, xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
"invalid XPath expression"); /* TODO: show proper XPath error details */ "invalid XPath expression");
xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx); xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
if (xpathobj == NULL) if (xpathobj == NULL) /* TODO: reason? */
ereport(ERROR, (errmsg("could not create XPath object"))); /* TODO: reason? */ ereport(ERROR,
(errmsg("could not create XPath object")));
xmlXPathFreeCompExpr(xpathcomp); xmlXPathFreeCompExpr(xpathcomp);
xpathcomp = NULL; xpathcomp = NULL;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment