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 @@
* 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.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);
static void *xml_repalloc(void *ptr, size_t size);
static void xml_pfree(void *ptr);
static char *xml_pstrdup(const char *string);
static void xml_ereport(int level, int sqlcode,
const char *msg);
static void xml_ereport(int level, int sqlcode, const char *msg);
static void xml_errorHandler(void *ctxt, const char *msg, ...);
static void xml_ereport_by_code(int level, int sqlcode,
const char *msg, int errcode);
static xmlChar *xml_text2xmlChar(text *in);
static int parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **encoding, int *standalone);
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 int parse_xml_decl(const xmlChar *str, size_t *lenp,
xmlChar **version, xmlChar **encoding, int *standalone);
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);
#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 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 StringInfo query_to_xml_internal(const char *query, char *tablename,
const char *xmlschema, bool nulls, bool tableforest,
const char *targetns, bool top_level);
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_typecoll_to_xmlschema_types(List *tupdesc_list);
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() \
ereport(ERROR, \
......@@ -194,7 +205,8 @@ xml_out_internal(xmltype *x, pg_enc target_encoding)
str[len] = '\0';
#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;
......@@ -388,17 +400,23 @@ xmlcomment(PG_FUNCTION_ARGS)
{
#ifdef USE_LIBXML
text *arg = PG_GETARG_TEXT_P(0);
char *argdata = VARDATA(arg);
int len = VARSIZE(arg) - VARHDRSZ;
StringInfoData buf;
int i;
/* check for "--" in string or "-" at the end */
for (i = 1; i < len; i++)
if ((VARDATA(arg)[i] == '-' && VARDATA(arg)[i - 1] == '-')
|| (VARDATA(arg)[i] == '-' && i == len - 1))
ereport(ERROR,
(errcode(ERRCODE_INVALID_XML_COMMENT),
errmsg("invalid XML comment")));
{
if (argdata[i] == '-' && argdata[i - 1] == '-')
ereport(ERROR,
(errcode(ERRCODE_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);
appendStringInfo(&buf, "<!--");
......@@ -422,20 +440,19 @@ 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;
StringInfoData buf;
ListCell *v;
initStringInfo(&buf);
foreach(v, args)
{
xmltype *x = DatumGetXmlP(PointerGetDatum(lfirst(v)));
size_t len;
xmlChar *version;
int standalone;
xmltype *x = DatumGetXmlP(PointerGetDatum(lfirst(v)));
char *str;
len = VARSIZE(x) - VARHDRSZ;
......@@ -468,7 +485,7 @@ xmlconcat(List *args)
initStringInfo(&buf2);
print_xml_decl(&buf2,
(!global_version_no_value && global_version) ? global_version : NULL,
(!global_version_no_value) ? global_version : NULL,
0,
global_standalone);
......@@ -500,7 +517,8 @@ xmlconcat2(PG_FUNCTION_ARGS)
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))));
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)
{
char *string;
string = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(arg)));
string = _textout(arg);
if (strstr(string, "?>") != NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
......@@ -971,17 +988,24 @@ xml_init(void)
* to complete this.
*/
#define CHECK_XML_SPACE(p) if (!xmlIsBlank_ch(*(p))) return XML_ERR_SPACE_REQUIRED
#define SKIP_XML_SPACE(p) while (xmlIsBlank_ch(*(p))) (p)++
#define CHECK_XML_SPACE(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
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 *save_p;
size_t len;
p = str;
xml_init();
if (version)
*version = NULL;
......@@ -990,6 +1014,8 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **en
if (standalone)
*standalone = -1;
p = str;
if (xmlStrncmp(p, (xmlChar *)"<?xml", 5) != 0)
goto finished;
......@@ -1119,8 +1145,11 @@ finished:
* which is the default version specified in SQL:2003.
*/
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)
|| (encoding && encoding != PG_UTF8)
|| standalone != -1)
......@@ -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);
if (encoding && encoding != PG_UTF8)
{
/*
* XXX might be useful to convert this to IANA names
* (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)
appendStringInfoString(buf, " standalone=\"yes\"");
......@@ -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
*
* 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
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;
xmlChar *string;
......@@ -1305,8 +1339,7 @@ xml_pstrdup(const char *string)
* any, as detail.
*/
static void
xml_ereport(int level, int sqlcode,
const char *msg)
xml_ereport(int level, int sqlcode, const char *msg)
{
char *detail;
......@@ -1458,7 +1491,8 @@ is_valid_xml_namechar(pg_wchar c)
* Map SQL identifier to XML name; see SQL/XML:2003 section 9.1.
*/
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
StringInfoData buf;
......@@ -1592,36 +1626,38 @@ map_sql_value_to_xml_value(Datum value, Oid type)
if (type_is_array(type))
{
int i;
ArrayType *array;
Oid elmtype;
int16 elmlen;
bool elmbyval;
char elmalign;
int num_elems;
Datum *elem_values;
bool *elem_nulls;
int i;
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;
deconstruct_array(array, elmtype,
elmlen, elmbyval, elmalign,
&elem_values, &elem_nulls,
&num_elems);
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, map_sql_value_to_xml_value(subval, elmtype));
appendStringInfoString(&buf,
map_sql_value_to_xml_value(elem_values[i],
elmtype));
appendStringInfoString(&buf, "</element>");
}
pfree(elem_values);
pfree(elem_nulls);
}
else
{
......@@ -1719,6 +1755,8 @@ map_sql_value_to_xml_value(Datum value, Oid type)
xmlTextWriterPtr writer;
char *result;
xml_init();
buf = xmlBufferCreate();
writer = xmlNewTextWriterMemory(buf, 0);
......@@ -1825,13 +1863,15 @@ query_to_oid_list(const char *query)
for (i = 0; i < SPI_processed; i++)
{
Oid oid;
Datum oid;
bool isnull;
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull));
if (isnull)
continue;
list = lappend_oid(list, oid);
oid = SPI_getbinval(SPI_tuptable->vals[i],
SPI_tuptable->tupdesc,
1,
&isnull);
if (!isnull)
list = lappend_oid(list, DatumGetObjectId(oid));
}
return list;
......@@ -1854,9 +1894,9 @@ schema_get_xml_visible_tables(Oid nspid)
* Including the system schemas is probably not useful for a database
* 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 *
......@@ -1880,13 +1920,19 @@ database_get_xml_visible_tables(void)
*/
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;
initStringInfo(&query);
appendStringInfo(&query, "SELECT * FROM %s", DatumGetCString(DirectFunctionCall1(regclassout, ObjectIdGetDatum(relid))));
return query_to_xml_internal(query.data, get_rel_name(relid), NULL, nulls, tableforest, targetns, top_level);
appendStringInfo(&query, "SELECT * FROM %s",
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)
bool tableforest = PG_GETARG_BOOL(2);
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)
bool tableforest = PG_GETARG_BOOL(2);
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)
SPI_cursor_fetch(portal, true, count);
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();
......@@ -1957,9 +2008,11 @@ cursor_to_xml(PG_FUNCTION_ARGS)
* namespace declarations are omitted, because they supposedly already
* appeared earlier in the output. Repeating them is not wrong, but
* it looks ugly.
*/
*/
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. */
Assert(top_level || !xmlschema);
......@@ -1991,7 +2044,9 @@ xmldata_root_element_end(StringInfo result, const char *eltname)
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;
char *xmltn;
......@@ -2011,13 +2066,15 @@ query_to_xml_internal(const char *query, char *tablename, const char *xmlschema,
errmsg("invalid query")));
if (!tableforest)
xmldata_root_element_start(result, xmltn, xmlschema, targetns, top_level);
xmldata_root_element_start(result, xmltn, xmlschema,
targetns, top_level);
if (xmlschema)
appendStringInfo(result, "%s\n\n", xmlschema);
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)
xmldata_root_element_end(result, xmltn);
......@@ -2035,12 +2092,12 @@ table_to_xmlschema(PG_FUNCTION_ARGS)
bool nulls = PG_GETARG_BOOL(1);
bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3));
const char *result;
Relation rel;
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);
PG_RETURN_XML_P(cstring_to_xmltype(result));
......@@ -2054,7 +2111,6 @@ query_to_xmlschema(PG_FUNCTION_ARGS)
bool nulls = PG_GETARG_BOOL(1);
bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3));
const char *result;
SPIPlanPtr plan;
Portal portal;
......@@ -2062,7 +2118,9 @@ query_to_xmlschema(PG_FUNCTION_ARGS)
SPI_connect();
plan = SPI_prepare(query, 0, NULL);
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_finish();
......@@ -2077,7 +2135,6 @@ cursor_to_xmlschema(PG_FUNCTION_ARGS)
bool nulls = PG_GETARG_BOOL(1);
bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3));
const char *xmlschema;
Portal portal;
......@@ -2088,7 +2145,9 @@ cursor_to_xmlschema(PG_FUNCTION_ARGS)
(errcode(ERRCODE_UNDEFINED_CURSOR),
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();
PG_RETURN_XML_P(cstring_to_xmltype(xmlschema));
......@@ -2102,19 +2161,17 @@ table_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
bool nulls = PG_GETARG_BOOL(1);
bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3));
StringInfoData query;
Relation rel;
const char *xmlschema;
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);
initStringInfo(&query);
appendStringInfo(&query, "SELECT * FROM %s", DatumGetCString(DirectFunctionCall1(regclassout, ObjectIdGetDatum(relid))));
PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query.data, get_rel_name(relid), xmlschema, nulls, tableforest, targetns, true)));
PG_RETURN_XML_P(stringinfo_to_xmltype(table_to_xml_internal(relid,
xmlschema, nulls, tableforest,
targetns, true)));
}
......@@ -2133,11 +2190,14 @@ query_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
SPI_connect();
plan = SPI_prepare(query, 0, NULL);
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_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)
*/
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;
char *xmlsn;
List *relid_list;
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();
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
Oid relid = lfirst_oid(cell);
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);
appendStringInfoChar(result, '\n');
......@@ -2202,7 +2265,8 @@ schema_to_xml(PG_FUNCTION_ARGS)
schemaname = NameStr(*name);
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)
static void
xsd_schema_element_end(StringInfo result)
{
appendStringInfoString(result,
"</xsd:schema>");
appendStringInfoString(result, "</xsd:schema>");
}
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;
List *relid_list;
......@@ -2259,7 +2323,7 @@ schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tablefores
Relation rel;
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);
}
......@@ -2267,7 +2331,8 @@ schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tablefores
map_sql_typecoll_to_xmlschema_types(tupdesc_list));
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);
......@@ -2285,7 +2350,8 @@ schema_to_xmlschema(PG_FUNCTION_ARGS)
bool tableforest = PG_GETARG_BOOL(2);
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)
bool nulls = PG_GETARG_BOOL(1);
bool tableforest = PG_GETARG_BOOL(2);
const char *targetns = _textout(PG_GETARG_TEXT_P(3));
char *schemaname;
Oid nspid;
StringInfo xmlschema;
......@@ -2304,9 +2369,12 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
schemaname = NameStr(*name);
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)
*/
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;
List *nspid_list;
ListCell *cell;
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();
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
Oid nspid = lfirst_oid(cell);
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);
appendStringInfoChar(result, '\n');
......@@ -2364,12 +2435,14 @@ database_to_xml(PG_FUNCTION_ARGS)
bool tableforest = PG_GETARG_BOOL(1);
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
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 *nspid_list;
......@@ -2392,7 +2465,7 @@ database_to_xmlschema_internal(bool nulls, bool tableforest, const char *targetn
Relation rel;
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);
}
......@@ -2417,7 +2490,8 @@ database_to_xmlschema(PG_FUNCTION_ARGS)
bool tableforest = PG_GETARG_BOOL(1);
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)
bool nulls = PG_GETARG_BOOL(0);
bool tableforest = PG_GETARG_BOOL(1);
const char *targetns = _textout(PG_GETARG_TEXT_P(2));
StringInfo xmlschema;
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)
initStringInfo(&result);
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)
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)
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)
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;
}
......@@ -2468,7 +2546,8 @@ map_multipart_sql_identifier_to_xml_name(char *a, char *b, char *c, char *d)
* 9.6.
*/
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;
char *xmltn;
......@@ -2478,12 +2557,20 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
initStringInfo(&result);
if (relid)
if (OidIsValid(relid))
{
HeapTuple tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relid), 0, 0, 0);
Form_pg_class reltuple = (Form_pg_class) GETSTRUCT(tuple);
HeapTuple 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",
get_database_name(MyDatabaseId),
......@@ -2521,7 +2608,8 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
for (i = 0; i < tupdesc->natts; i++)
appendStringInfo(&result,
" <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),
nulls ? " nillable=\"true\"" : " minOccurs=\"0\"");
......@@ -2559,20 +2647,26 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
* 9.7.
*/
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 *schematypename;
StringInfoData result;
ListCell *cell;
dbname = get_database_name(MyDatabaseId);
nspname = get_namespace_name(nspid);
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",
get_database_name(MyDatabaseId),
get_namespace_name(nspid),
dbname,
nspname,
NULL);
appendStringInfo(&result,
......@@ -2587,11 +2681,12 @@ map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool
foreach (cell, relid_list)
{
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",
get_database_name(MyDatabaseId),
get_namespace_name(nspid),
get_rel_name(relid));
dbname,
nspname,
relname);
if (!tableforest)
appendStringInfo(&result,
......@@ -2625,19 +2720,23 @@ map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool
* 9.8.
*/
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 *catalogtypename;
StringInfoData result;
ListCell *cell;
dbname = get_database_name(MyDatabaseId);
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",
get_database_name(MyDatabaseId),
dbname,
NULL,
NULL);
......@@ -2649,10 +2748,11 @@ map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tablefores
foreach (cell, nspid_list)
{
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",
get_database_name(MyDatabaseId),
get_namespace_name(nspid),
dbname,
nspname,
NULL);
appendStringInfo(&result,
......@@ -2755,8 +2855,15 @@ map_sql_type_to_xml_name(Oid typeoid, int typmod)
break;
default:
{
HeapTuple tuple = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), 0, 0, 0);
Form_pg_type typtuple = (Form_pg_type) GETSTRUCT(tuple);
HeapTuple 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,
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)
" <xsd:restriction base=\"xsd:date\">\n"
" <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}\"/>\n"
" </xsd:restriction>\n");
break;
break;
default:
if (get_typtype(typeoid) == TYPTYPE_DOMAIN)
......@@ -2990,6 +3097,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
" <xsd:restriction base=\"%s\">\n",
map_sql_type_to_xml_name(base_typeoid, base_typmod));
}
break;
}
appendStringInfo(&result,
"</xsd:simpleType>\n");
......@@ -3004,7 +3112,9 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
* SPI cursor. See also SQL/XML:2003 section 9.12.
*/
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;
char *xmltn;
......@@ -3030,9 +3140,12 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
Datum colval;
bool isnull;
colname = map_sql_identifier_to_xml_name(SPI_fname(SPI_tuptable->tupdesc, i), true, false);
colval = SPI_getbinval(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i, &isnull);
colname = map_sql_identifier_to_xml_name(SPI_fname(SPI_tuptable->tupdesc, i),
true, false);
colval = SPI_getbinval(SPI_tuptable->vals[rownum],
SPI_tuptable->tupdesc,
i,
&isnull);
if (isnull)
{
if (nulls)
......@@ -3040,7 +3153,9 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
}
else
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);
}
......@@ -3060,9 +3175,10 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
#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)
{
xmlChar *str;
......@@ -3093,9 +3209,10 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
/*
* 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
* 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
* fragments (see "XPath for fragment" TODO comment inside).
......@@ -3107,13 +3224,13 @@ xpath(PG_FUNCTION_ARGS)
text *xpath_expr_text = PG_GETARG_TEXT_P(0);
xmltype *data = PG_GETARG_XML_P(1);
ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
ArrayBuildState *astate = NULL;
xmlParserCtxtPtr ctxt = NULL;
xmlDocPtr doc = NULL;
xmlXPathContextPtr xpathctx = NULL;
xmlXPathCompExprPtr xpathcomp = NULL;
xmlXPathObjectPtr xpathobj = NULL;
char *datastr;
int32 len;
int32 xpath_len;
xmlChar *string;
......@@ -3121,14 +3238,14 @@ xpath(PG_FUNCTION_ARGS)
int i;
int res_nitems;
int ndim;
Datum *ns_names_uris;
bool *ns_names_uris_nulls;
int ns_count;
char **ns_names;
char **ns_uris;
/*
* Namespace mappings are passed as text[]. If an empty array is
* passed (ndim = 0, "0-dimentional"), then there are no namespace
* mappings. Else, a 2-dimentional array with length of the
* passed (ndim = 0, "0-dimensional"), then there are no namespace
* mappings. Else, a 2-dimensional array with length of the
* second axis being equal to 2 should be passed, i.e., every
* subarray contains 2 elements, the first element defining the
* name, the second one the URI. Example: ARRAY[ARRAY['myns',
......@@ -3137,71 +3254,39 @@ xpath(PG_FUNCTION_ARGS)
ndim = ARR_NDIM(namespaces);
if (ndim != 0)
{
bits8 *bitmap;
int bitmask;
int16 typlen;
bool typbyval;
char typalign;
char *ptr;
int *dims;
dims = ARR_DIMS(namespaces);
if (ndim != 2 || dims[1] != 2)
ereport(ERROR, (errmsg("invalid array for XML namespace mapping"),
errdetail("The array must be two-dimensional with length of the second axis equal to 2."),
errcode(ERRCODE_DATA_EXCEPTION)));
ereport(ERROR,
(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);
ns_count = ArrayGetNItems(ndim, dims) / 2; /* number of NS mappings */
get_typlenbyvalalign(ARR_ELEMTYPE(namespaces),
&typlen, &typbyval, &typalign);
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);
}
deconstruct_array(namespaces, TEXTOID, -1, false, 'i',
&ns_names_uris, &ns_names_uris_nulls,
&ns_count);
/* advance bitmap pointer if any */
if (bitmap)
{
bitmask <<= 1;
if (bitmask == 0x100)
{
bitmap++;
bitmask = 1;
}
}
}
Assert((ns_count % 2) == 0); /* checked above */
ns_count /= 2; /* count pairs only */
}
else
{
ns_names_uris = NULL;
ns_names_uris_nulls = NULL;
ns_count = 0;
ns_names = NULL;
ns_uris = NULL;
}
datastr = VARDATA(data);
len = VARSIZE(data) - VARHDRSZ;
xpath_len = VARSIZE(xpath_expr_text) - VARHDRSZ;
if (xpath_len == 0)
ereport(ERROR, (errmsg("empty XPath expression"),
errcode(ERRCODE_DATA_EXCEPTION)));
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("empty XPath expression")));
/*
* To handle both documents and fragments, regardless of the fact
......@@ -3210,10 +3295,12 @@ xpath(PG_FUNCTION_ARGS)
* extend the XPath expression accordingly. To do it, throw away
* 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;
while ((i < len) && (('?' != (VARDATA(data))[i - 1]) || ('>' != (VARDATA(data))[i])))
while (i < len &&
!(datastr[i - 1] == '?' && datastr[i] == '>'))
i++;
if (i == len)
......@@ -3221,14 +3308,17 @@ xpath(PG_FUNCTION_ARGS)
"could not parse XML data");
++i;
string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data) + i, len - i);
string = xmlStrncatNew((xmlChar *) "<x>",
(xmlChar *) datastr + i, len - i);
}
else
string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data), len);
string = xmlStrncatNew((xmlChar *) "<x>",
(xmlChar *) datastr, len);
string = xmlStrncat(string, (xmlChar *) "</x>", 5);
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;
xml_init();
......@@ -3259,21 +3349,38 @@ xpath(PG_FUNCTION_ARGS)
"could not find root XML element");
/* register namespaces, if any */
if ((ns_count > 0) && ns_names && ns_uris)
if (ns_count > 0)
{
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,
(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\"",
ns_names[i], ns_uris[i])));
ns_name, ns_uri)));
}
}
xpathcomp = xmlXPathCompile(xpath_expr);
if (xpathcomp == NULL)
if (xpathcomp == NULL) /* TODO: show proper XPath error details */
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
"invalid XPath expression"); /* TODO: show proper XPath error details */
"invalid XPath expression");
xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
if (xpathobj == NULL)
ereport(ERROR, (errmsg("could not create XPath object"))); /* TODO: reason? */
if (xpathobj == NULL) /* TODO: reason? */
ereport(ERROR,
(errmsg("could not create XPath object")));
xmlXPathFreeCompExpr(xpathcomp);
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