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 по дате отправления: