Re: [HACKERS] patch: function xmltable
| От | Alvaro Herrera |
|---|---|
| Тема | Re: [HACKERS] patch: function xmltable |
| Дата | |
| Msg-id | 20170116233000.aooak7ytomrhvyjo@alvherre.pgsql обсуждение исходный текст |
| Ответ на | Re: [HACKERS] patch: function xmltable (Alvaro Herrera <alvherre@2ndquadrant.com>) |
| Список | pgsql-hackers |
In case this still matters, I think GetValue should look more or less
like this (untested):
/** Return the value for column number 'colnum' for the current row. If column* -1 is requested, return representation
ofthe whole row.** This leaks memory, so be sure to reset often the context in which it's* called.*/
static Datum
XmlTableGetValue(TableExprState *state, int colnum, bool *isnull)
{
#ifdef USE_LIBXMLXmlTableBuilderData *xtCxt;Datum result = (Datum) 0;xmlNodePtr cur;char *cstr =
NULL;volatilexmlXPathObjectPtr xpathobj;
xtCxt = GetXmlTableBuilderPrivateData(state, "XmlTableGetValue");
Assert(xtCxt->xpathobj && xtCxt->xpathobj->type == XPATH_NODESET && xtCxt->xpathobj->nodesetval != NULL);
/* Propagate context related error context to libxml2 */xmlSetStructuredErrorFunc((void *) xtCxt->xmlerrcxt,
xml_errorHandler);
cur = xtCxt->xpathobj->nodesetval->nodeTab[xtCxt->row_count - 1];if (cur->type != XML_ELEMENT_NODE) elog(ERROR,
"unexpectedxmlNode type");
/* Handle whole row case the easy way. */if (colnum == -1){ text *txt;
txt = xml_xmlnodetoxmltype(cur, xtCxt->xmlerrcxt); result = InputFunctionCall(&state->in_functions[0],
text_to_cstring(txt), state->typioparams[0],
-1); *isnull = false;
return result;}
Assert(xtCxt->xpathscomp[colnum] != NULL);
xpathobj = NULL;PG_TRY();{ Form_pg_attribute attr;
attr = state->resultSlot->tts_tupleDescriptor->attrs[colnum];
/* Set current node as entry point for XPath evaluation */ xmlXPathSetContextNode(cur, xtCxt->xpathcxt);
/* Evaluate column path */ xpathobj = xmlXPathCompiledEval(xtCxt->xpathscomp[colnum], xtCxt->xpathcxt); if
(xpathobj== NULL || xtCxt->xmlerrcxt->err_occurred) xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
"could not create XPath object");
if (xpathobj->type == XPATH_NODESET) { int count; Oid targettypid =
attr->atttypid;
if (xpathobj->nodesetval != NULL) count = xpathobj->nodesetval->nodeNr;
/* * There are four possible cases, depending on the number of * nodes returned by the XPath
expressionand the type of the * target column: a) XPath returns no nodes. b) One node is * returned,
andcolumn is of type XML. c) One node, column type * other than XML. d) Multiple nodes are returned.
*/ if (xpathobj->nodesetval == NULL) { *isnull = true; } else if (count == 1 &&
targettypid== XMLOID) { textstr = xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[0],
xtCxt->xmlerrcxt); cstr = text_to_cstring(textstr); } else if
(count== 1) { xmlChar *str;
str = xmlNodeListGetString(xtCxt->doc,
xpathobj->nodesetval->nodeTab[0]->xmlChildrenNode, 1); if (str)
{ PG_TRY(); { cstr = pstrdup(str); }
PG_CATCH(); { xmlFree(str); PG_RE_THROW(); }
PG_END_TRY(); xmlFree(str); } else cstr = pstrdup("");
} else { StringInfoData buf; int i;
Assert(count > 1);
/* * When evaluating the XPath expression returns multiple * nodes, the result is
theconcatenation of them all. * The target type must be XML. */ if (targettypid !=
XMLOID) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION),
errmsg("more than one value returned by column XPath expression")));
initStringInfo(&buf); for (i = 0; i < count; i++) /* worth freeing the text here?
Naahh ... */ appendStringInfoText(&buf,
xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i],
xtCxt->xmlerrcxt)); cstr = buf.data; } } else if (xpathobj->type == XPATH_STRING) {
cstr= (char *) xpathobj->stringval; *isnull = false; } else elog(ERROR, "unexpected XPath object
type%u", xpathobj->type);
/* * By here, either cstr contains the result value, or the isnull flag * has been set. */
Assert(cstr|| *isnull);
if (!*isnull) result = InputFunctionCall(&state->in_functions[colnum],
cstr, state->typioparams[colnum],
attr->atttypmod);}PG_CATCH();{ if (xpathobj != NULL) xmlXPathFreeObject(xpathobj);
PG_RE_THROW();}PG_END_TRY();
if (xpathobj) xmlXPathFreeObject(xpathobj);
return result;
#elseNO_XML_SUPPORT();
#endif /* not USE_LIBXML */
}
--
Álvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
В списке pgsql-hackers по дате отправления: