diff options
Diffstat (limited to 'src/backend/utils/adt/xml.c')
-rw-r--r-- | src/backend/utils/adt/xml.c | 521 |
1 files changed, 314 insertions, 207 deletions
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 5f5654c232a..9e9d0e1af55 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.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; |