mirror of
https://github.com/postgres/postgres.git
synced 2025-07-18 17:42:25 +03:00
What we want in these places is "xmlChar *volatile ptr",
not "volatile xmlChar *ptr". The former means that the
pointer variable itself needs to be treated as volatile,
while the latter says that what it points to is volatile.
Since the point here is to ensure that the pointer variables
don't go crazy after a longjmp, it's the former semantics
that we need. The misplacement of "volatile" also led
to needing to cast away volatile in some places.
Also fix a number of places where variables that are assigned to
within a PG_TRY and then used after it were not initialized or
not marked as volatile. (A few buildfarm members were issuing
"may be used uninitialized" warnings about some of these variables,
which is what drew my attention to this area.) In most cases
these variables were being set as the last step within the PG_TRY
block, which might mean that we could get away without the "volatile"
marking. But doing that seems unsafe and is definitely not per our
coding conventions.
These problems seem to have come in with 732061150
, so no need
for back-patch.
260 lines
6.2 KiB
C
260 lines
6.2 KiB
C
/*
|
|
* contrib/xml2/xslt_proc.c
|
|
*
|
|
* XSLT processing functions (requiring libxslt)
|
|
*
|
|
* John Gray, for Torchbox 2003-04-01
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "fmgr.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/xml.h"
|
|
|
|
#ifdef USE_LIBXSLT
|
|
|
|
/* 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/security.h>
|
|
#include <libxslt/transform.h>
|
|
#include <libxslt/xsltutils.h>
|
|
#endif /* USE_LIBXSLT */
|
|
|
|
|
|
#ifdef USE_LIBXSLT
|
|
|
|
/* declarations to come from xpath.c */
|
|
extern PgXmlErrorContext *pgxml_parser_init(PgXmlStrictness strictness);
|
|
|
|
/* local defs */
|
|
static const char **parse_params(text *paramstr);
|
|
#endif /* USE_LIBXSLT */
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(xslt_process);
|
|
|
|
Datum
|
|
xslt_process(PG_FUNCTION_ARGS)
|
|
{
|
|
#ifdef USE_LIBXSLT
|
|
|
|
text *doct = PG_GETARG_TEXT_PP(0);
|
|
text *ssheet = PG_GETARG_TEXT_PP(1);
|
|
text *volatile result = NULL;
|
|
text *paramstr;
|
|
const char **params;
|
|
PgXmlErrorContext *xmlerrcxt;
|
|
volatile xsltStylesheetPtr stylesheet = NULL;
|
|
volatile xmlDocPtr doctree = NULL;
|
|
volatile xmlDocPtr restree = NULL;
|
|
volatile xsltSecurityPrefsPtr xslt_sec_prefs = NULL;
|
|
volatile xsltTransformContextPtr xslt_ctxt = NULL;
|
|
volatile int resstat = -1;
|
|
xmlChar *volatile resstr = NULL;
|
|
|
|
if (fcinfo->nargs == 3)
|
|
{
|
|
paramstr = PG_GETARG_TEXT_PP(2);
|
|
params = parse_params(paramstr);
|
|
}
|
|
else
|
|
{
|
|
/* No parameters */
|
|
params = (const char **) palloc(sizeof(char *));
|
|
params[0] = NULL;
|
|
}
|
|
|
|
/* Setup parser */
|
|
xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY);
|
|
|
|
PG_TRY();
|
|
{
|
|
xmlDocPtr ssdoc;
|
|
bool xslt_sec_prefs_error;
|
|
int reslen = 0;
|
|
|
|
/* Parse document */
|
|
doctree = xmlReadMemory((char *) VARDATA_ANY(doct),
|
|
VARSIZE_ANY_EXHDR(doct), NULL, NULL,
|
|
XML_PARSE_NOENT);
|
|
|
|
if (doctree == NULL || pg_xml_error_occurred(xmlerrcxt))
|
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
|
"error parsing XML document");
|
|
|
|
/* Same for stylesheet */
|
|
ssdoc = xmlReadMemory((char *) VARDATA_ANY(ssheet),
|
|
VARSIZE_ANY_EXHDR(ssheet), NULL, NULL,
|
|
XML_PARSE_NOENT);
|
|
|
|
if (ssdoc == NULL || pg_xml_error_occurred(xmlerrcxt))
|
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
|
"error parsing stylesheet as XML document");
|
|
|
|
/* After this call we need not free ssdoc separately */
|
|
stylesheet = xsltParseStylesheetDoc(ssdoc);
|
|
|
|
if (stylesheet == NULL || pg_xml_error_occurred(xmlerrcxt))
|
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
|
|
"failed to parse stylesheet");
|
|
|
|
xslt_ctxt = xsltNewTransformContext(stylesheet, doctree);
|
|
|
|
xslt_sec_prefs_error = false;
|
|
if ((xslt_sec_prefs = xsltNewSecurityPrefs()) == NULL)
|
|
xslt_sec_prefs_error = true;
|
|
|
|
if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_FILE,
|
|
xsltSecurityForbid) != 0)
|
|
xslt_sec_prefs_error = true;
|
|
if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_FILE,
|
|
xsltSecurityForbid) != 0)
|
|
xslt_sec_prefs_error = true;
|
|
if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_CREATE_DIRECTORY,
|
|
xsltSecurityForbid) != 0)
|
|
xslt_sec_prefs_error = true;
|
|
if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_NETWORK,
|
|
xsltSecurityForbid) != 0)
|
|
xslt_sec_prefs_error = true;
|
|
if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_NETWORK,
|
|
xsltSecurityForbid) != 0)
|
|
xslt_sec_prefs_error = true;
|
|
if (xsltSetCtxtSecurityPrefs(xslt_sec_prefs, xslt_ctxt) != 0)
|
|
xslt_sec_prefs_error = true;
|
|
|
|
if (xslt_sec_prefs_error)
|
|
ereport(ERROR,
|
|
(errmsg("could not set libxslt security preferences")));
|
|
|
|
restree = xsltApplyStylesheetUser(stylesheet, doctree, params,
|
|
NULL, NULL, xslt_ctxt);
|
|
|
|
if (restree == NULL || pg_xml_error_occurred(xmlerrcxt))
|
|
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY,
|
|
"failed to apply stylesheet");
|
|
|
|
resstat = xsltSaveResultToString((xmlChar **) &resstr, &reslen,
|
|
restree, stylesheet);
|
|
|
|
if (resstat >= 0)
|
|
result = cstring_to_text_with_len((char *) resstr, reslen);
|
|
}
|
|
PG_CATCH();
|
|
{
|
|
if (restree != NULL)
|
|
xmlFreeDoc(restree);
|
|
if (xslt_ctxt != NULL)
|
|
xsltFreeTransformContext(xslt_ctxt);
|
|
if (xslt_sec_prefs != NULL)
|
|
xsltFreeSecurityPrefs(xslt_sec_prefs);
|
|
if (stylesheet != NULL)
|
|
xsltFreeStylesheet(stylesheet);
|
|
if (doctree != NULL)
|
|
xmlFreeDoc(doctree);
|
|
if (resstr != NULL)
|
|
xmlFree(resstr);
|
|
xsltCleanupGlobals();
|
|
|
|
pg_xml_done(xmlerrcxt, true);
|
|
|
|
PG_RE_THROW();
|
|
}
|
|
PG_END_TRY();
|
|
|
|
xmlFreeDoc(restree);
|
|
xsltFreeTransformContext(xslt_ctxt);
|
|
xsltFreeSecurityPrefs(xslt_sec_prefs);
|
|
xsltFreeStylesheet(stylesheet);
|
|
xmlFreeDoc(doctree);
|
|
xsltCleanupGlobals();
|
|
|
|
if (resstr)
|
|
xmlFree(resstr);
|
|
|
|
pg_xml_done(xmlerrcxt, false);
|
|
|
|
/* XXX this is pretty dubious, really ought to throw error instead */
|
|
if (resstat < 0)
|
|
PG_RETURN_NULL();
|
|
|
|
PG_RETURN_TEXT_P(result);
|
|
#else /* !USE_LIBXSLT */
|
|
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
errmsg("xslt_process() is not available without libxslt")));
|
|
PG_RETURN_NULL();
|
|
#endif /* USE_LIBXSLT */
|
|
}
|
|
|
|
#ifdef USE_LIBXSLT
|
|
|
|
static const char **
|
|
parse_params(text *paramstr)
|
|
{
|
|
char *pos;
|
|
char *pstr;
|
|
char *nvsep = "=";
|
|
char *itsep = ",";
|
|
const char **params;
|
|
int max_params;
|
|
int nparams;
|
|
|
|
pstr = text_to_cstring(paramstr);
|
|
|
|
max_params = 20; /* must be even! */
|
|
params = (const char **) palloc((max_params + 1) * sizeof(char *));
|
|
nparams = 0;
|
|
|
|
pos = pstr;
|
|
|
|
while (*pos != '\0')
|
|
{
|
|
if (nparams >= max_params)
|
|
{
|
|
max_params *= 2;
|
|
params = (const char **) repalloc(params,
|
|
(max_params + 1) * sizeof(char *));
|
|
}
|
|
params[nparams++] = pos;
|
|
pos = strstr(pos, nvsep);
|
|
if (pos != NULL)
|
|
{
|
|
*pos = '\0';
|
|
pos++;
|
|
}
|
|
else
|
|
{
|
|
/* No equal sign, so ignore this "parameter" */
|
|
nparams--;
|
|
break;
|
|
}
|
|
|
|
/* since max_params is even, we still have nparams < max_params */
|
|
params[nparams++] = pos;
|
|
pos = strstr(pos, itsep);
|
|
if (pos != NULL)
|
|
{
|
|
*pos = '\0';
|
|
pos++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
/* Add the terminator marker; we left room for it in the palloc's */
|
|
params[nparams] = NULL;
|
|
|
|
return params;
|
|
}
|
|
|
|
#endif /* USE_LIBXSLT */
|