1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-21 12:05:57 +03:00
postgres/contrib/xml2/xslt_proc.c
Tom Lane 4f146ab3e7 Back-patch today's memory management fixups in contrib/xml2.
Prior to 8.3, these changes are not critical for compatibility with core
Postgres, since core had no libxml2 calls then.  However there is still
a risk if contrib/xml2 is used along with libxml2 functionality in Perl
or other loadable modules.  So back-patch to all versions.

Also back-patch addition of regression tests.  I'm not sure how many of
the cases are interesting without the interaction with core xml code,
but a silly regression test is still better than none at all.
2010-03-01 03:41:11 +00:00

185 lines
3.5 KiB
C

/* XSLT processing functions (requiring libxslt) */
/* John Gray, for Torchbox 2003-04-01 */
#include "postgres.h"
#include "fmgr.h"
#include "executor/spi.h"
#include "funcapi.h"
#include "miscadmin.h"
/* libxml includes */
#include <libxml/xpath.h>
#include <libxml/tree.h>
#include <libxml/xmlmemory.h>
/* libxslt includes */
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
/* externally accessible functions */
Datum xslt_process(PG_FUNCTION_ARGS);
/* declarations to come from xpath.c */
extern void elog_error(const char *explain, bool force);
extern void pgxml_parser_init(void);
/* local defs */
static void parse_params(const char **params, text *paramstr);
#define MAXPARAMS 20 /* must be even, see parse_params() */
#define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
PG_FUNCTION_INFO_V1(xslt_process);
Datum
xslt_process(PG_FUNCTION_ARGS)
{
const char *params[MAXPARAMS + 1]; /* +1 for the terminator */
xsltStylesheetPtr stylesheet = NULL;
xmlDocPtr doctree;
xmlDocPtr restree;
xmlDocPtr ssdoc = NULL;
xmlChar *resstr;
int resstat;
int reslen;
text *doct = PG_GETARG_TEXT_P(0);
text *ssheet = PG_GETARG_TEXT_P(1);
text *paramstr;
text *tres;
if (fcinfo->nargs == 3)
{
paramstr = PG_GETARG_TEXT_P(2);
parse_params(params, paramstr);
}
else
/* No parameters */
params[0] = NULL;
/* Setup parser */
pgxml_parser_init();
/* Check to see if document is a file or a literal */
if (VARDATA(doct)[0] == '<')
doctree = xmlParseMemory((char *) VARDATA(doct), VARSIZE(doct) - VARHDRSZ);
else
doctree = xmlParseFile(GET_STR(doct));
if (doctree == NULL)
{
xmlCleanupParser();
elog_error("error parsing XML document", false);
PG_RETURN_NULL();
}
/* Same for stylesheet */
if (VARDATA(ssheet)[0] == '<')
{
ssdoc = xmlParseMemory((char *) VARDATA(ssheet),
VARSIZE(ssheet) - VARHDRSZ);
if (ssdoc == NULL)
{
xmlFreeDoc(doctree);
xmlCleanupParser();
elog_error("error parsing stylesheet as XML document", false);
PG_RETURN_NULL();
}
stylesheet = xsltParseStylesheetDoc(ssdoc);
}
else
stylesheet = xsltParseStylesheetFile((xmlChar *) GET_STR(ssheet));
if (stylesheet == NULL)
{
xmlFreeDoc(doctree);
xsltCleanupGlobals();
xmlCleanupParser();
elog_error("failed to parse stylesheet", false);
PG_RETURN_NULL();
}
restree = xsltApplyStylesheet(stylesheet, doctree, params);
resstat = xsltSaveResultToString(&resstr, &reslen, restree, stylesheet);
xsltFreeStylesheet(stylesheet);
xmlFreeDoc(restree);
xmlFreeDoc(doctree);
xsltCleanupGlobals();
xmlCleanupParser();
if (resstat < 0)
PG_RETURN_NULL();
tres = palloc(reslen + VARHDRSZ);
memcpy(VARDATA(tres), resstr, reslen);
SET_VARSIZE(tres, reslen + VARHDRSZ);
PG_RETURN_TEXT_P(tres);
}
static void
parse_params(const char **params, text *paramstr)
{
char *pos;
char *pstr;
int i;
char *nvsep = "=";
char *itsep = ",";
pstr = GET_STR(paramstr);
pos = pstr;
for (i = 0; i < MAXPARAMS; i++)
{
params[i] = pos;
pos = strstr(pos, nvsep);
if (pos != NULL)
{
*pos = '\0';
pos++;
}
else
{
/* No equal sign, so ignore this "parameter" */
/* We'll reset params[i] to NULL below the loop */
break;
}
/* Value */
i++;
/* since MAXPARAMS is even, we still have i < MAXPARAMS */
params[i] = pos;
pos = strstr(pos, itsep);
if (pos != NULL)
{
*pos = '\0';
pos++;
}
else
{
i++;
break;
}
}
params[i] = NULL;
}