Pavel Stehule <pavel.steh...@gmail.com> writes:
> 2010/11/26 Itagaki Takahiro <itagaki.takah...@gmail.com>:
>> Why did you change doctree and ctxt to global variables?
>> I'm not sure why /* xmlFreeDoc(doctree); */ is commented out
>> at the end of pgxml_xpath(), but is it enough to enable the code?

> I am thinking, so you must not to call xmlFreeDoc(doctree) early.
> Probably xmlXPathCastToXXX reading a doctree.

Those static variables are really ugly, and what's more this patch only
stops some of the leakage.  Per experimentation, the result object from
pgxml_xpath has to be freed too, once it's been safely converted to
whatever the end result type is.  You can see this by watching

select sum(xpath_number('<data>' || generate_series || '</data>','/data')) from
generate_series(1,500000);

which still shows leakage with the submitted patch.  I cleaned it up
as per attached, which doesn't show any leakage.

                        regards, tom lane

diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c
index 0df7647..e92ab66 100644
*** a/contrib/xml2/xpath.c
--- b/contrib/xml2/xpath.c
*************** Datum		xpath_table(PG_FUNCTION_ARGS);
*** 40,45 ****
--- 40,54 ----
  
  void		pgxml_parser_init(void);
  
+ /* workspace for pgxml_xpath() */
+ 
+ typedef struct
+ {
+ 	xmlDocPtr	doctree;
+ 	xmlXPathContextPtr ctxt;
+ 	xmlXPathObjectPtr res;
+ } xpath_workspace;
+ 
  /* local declarations */
  
  static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
*************** static text *pgxml_result_to_text(xmlXPa
*** 51,57 ****
  
  static xmlChar *pgxml_texttoxmlchar(text *textstring);
  
! static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath);
  
  
  /*
--- 60,69 ----
  
  static xmlChar *pgxml_texttoxmlchar(text *textstring);
  
! static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath,
! 									 xpath_workspace *workspace);
! 
! static void cleanup_workspace(xpath_workspace *workspace);
  
  
  /*
*************** PG_FUNCTION_INFO_V1(xpath_nodeset);
*** 221,245 ****
  Datum
  xpath_nodeset(PG_FUNCTION_ARGS)
  {
! 	xmlChar    *xpath,
! 			   *toptag,
! 			   *septag;
! 	int32		pathsize;
! 	text	   *xpathsupp,
! 			   *xpres;
! 
! 	/* PG_GETARG_TEXT_P(0) is document buffer */
! 	xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
  
! 	toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
! 	septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3));
  
! 	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
  
! 	xpath = pgxml_texttoxmlchar(xpathsupp);
  
! 	xpres = pgxml_result_to_text(pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
! 								 toptag, septag, NULL);
  
  	pfree(xpath);
  
--- 233,254 ----
  Datum
  xpath_nodeset(PG_FUNCTION_ARGS)
  {
! 	text	   *document = PG_GETARG_TEXT_P(0);
! 	text	   *xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
! 	xmlChar    *toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
! 	xmlChar    *septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3));
! 	xmlChar    *xpath;
! 	text	   *xpres;
! 	xmlXPathObjectPtr res;
! 	xpath_workspace workspace;
  
! 	xpath = pgxml_texttoxmlchar(xpathsupp);
  
! 	res = pgxml_xpath(document, xpath, &workspace);
  
! 	xpres = pgxml_result_to_text(res, toptag, septag, NULL);
  
! 	cleanup_workspace(&workspace);
  
  	pfree(xpath);
  
*************** PG_FUNCTION_INFO_V1(xpath_list);
*** 257,279 ****
  Datum
  xpath_list(PG_FUNCTION_ARGS)
  {
! 	xmlChar    *xpath,
! 			   *plainsep;
! 	int32		pathsize;
! 	text	   *xpathsupp,
! 			   *xpres;
! 
! 	/* PG_GETARG_TEXT_P(0) is document buffer */
! 	xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
  
! 	plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
  
! 	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
  
! 	xpath = pgxml_texttoxmlchar(xpathsupp);
  
! 	xpres = pgxml_result_to_text(pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
! 								 NULL, NULL, plainsep);
  
  	pfree(xpath);
  
--- 266,286 ----
  Datum
  xpath_list(PG_FUNCTION_ARGS)
  {
! 	text	   *document = PG_GETARG_TEXT_P(0);
! 	text	   *xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
! 	xmlChar    *plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
! 	xmlChar    *xpath;
! 	text	   *xpres;
! 	xmlXPathObjectPtr res;
! 	xpath_workspace workspace;
  
! 	xpath = pgxml_texttoxmlchar(xpathsupp);
  
! 	res = pgxml_xpath(document, xpath, &workspace);
  
! 	xpres = pgxml_result_to_text(res, NULL, NULL, plainsep);
  
! 	cleanup_workspace(&workspace);
  
  	pfree(xpath);
  
*************** PG_FUNCTION_INFO_V1(xpath_string);
*** 288,300 ****
  Datum
  xpath_string(PG_FUNCTION_ARGS)
  {
  	xmlChar    *xpath;
  	int32		pathsize;
! 	text	   *xpathsupp,
! 			   *xpres;
! 
! 	/* PG_GETARG_TEXT_P(0) is document buffer */
! 	xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
  
  	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
  
--- 295,307 ----
  Datum
  xpath_string(PG_FUNCTION_ARGS)
  {
+ 	text	   *document = PG_GETARG_TEXT_P(0);
+ 	text	   *xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
  	xmlChar    *xpath;
  	int32		pathsize;
! 	text	   *xpres;
! 	xmlXPathObjectPtr res;
! 	xpath_workspace workspace;
  
  	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
  
*************** xpath_string(PG_FUNCTION_ARGS)
*** 305,317 ****
  	/* We could try casting to string using the libxml function? */
  
  	xpath = (xmlChar *) palloc(pathsize + 9);
- 	memcpy((char *) (xpath + 7), VARDATA(xpathsupp), pathsize);
  	strncpy((char *) xpath, "string(", 7);
  	xpath[pathsize + 7] = ')';
  	xpath[pathsize + 8] = '\0';
  
! 	xpres = pgxml_result_to_text(pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
! 								 NULL, NULL, NULL);
  
  	pfree(xpath);
  
--- 312,327 ----
  	/* We could try casting to string using the libxml function? */
  
  	xpath = (xmlChar *) palloc(pathsize + 9);
  	strncpy((char *) xpath, "string(", 7);
+ 	memcpy((char *) (xpath + 7), VARDATA(xpathsupp), pathsize);
  	xpath[pathsize + 7] = ')';
  	xpath[pathsize + 8] = '\0';
  
! 	res = pgxml_xpath(document, xpath, &workspace);
! 
! 	xpres = pgxml_result_to_text(res, NULL, NULL, NULL);
! 
! 	cleanup_workspace(&workspace);
  
  	pfree(xpath);
  
*************** PG_FUNCTION_INFO_V1(xpath_number);
*** 326,346 ****
  Datum
  xpath_number(PG_FUNCTION_ARGS)
  {
  	xmlChar    *xpath;
- 	int32		pathsize;
- 	text	   *xpathsupp;
  	float4		fRes;
- 
  	xmlXPathObjectPtr res;
! 
! 	/* PG_GETARG_TEXT_P(0) is document buffer */
! 	xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
! 
! 	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
  
  	xpath = pgxml_texttoxmlchar(xpathsupp);
  
! 	res = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath);
  	pfree(xpath);
  
  	if (res == NULL)
--- 336,352 ----
  Datum
  xpath_number(PG_FUNCTION_ARGS)
  {
+ 	text	   *document = PG_GETARG_TEXT_P(0);
+ 	text	   *xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
  	xmlChar    *xpath;
  	float4		fRes;
  	xmlXPathObjectPtr res;
! 	xpath_workspace workspace;
  
  	xpath = pgxml_texttoxmlchar(xpathsupp);
  
! 	res = pgxml_xpath(document, xpath, &workspace);
! 
  	pfree(xpath);
  
  	if (res == NULL)
*************** xpath_number(PG_FUNCTION_ARGS)
*** 348,353 ****
--- 354,361 ----
  
  	fRes = xmlXPathCastToNumber(res);
  
+ 	cleanup_workspace(&workspace);
+ 
  	if (xmlXPathIsNaN(fRes))
  		PG_RETURN_NULL();
  
*************** PG_FUNCTION_INFO_V1(xpath_bool);
*** 360,380 ****
  Datum
  xpath_bool(PG_FUNCTION_ARGS)
  {
  	xmlChar    *xpath;
- 	int32		pathsize;
- 	text	   *xpathsupp;
  	int			bRes;
- 
  	xmlXPathObjectPtr res;
! 
! 	/* PG_GETARG_TEXT_P(0) is document buffer */
! 	xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
! 
! 	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
  
  	xpath = pgxml_texttoxmlchar(xpathsupp);
  
! 	res = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath);
  	pfree(xpath);
  
  	if (res == NULL)
--- 368,384 ----
  Datum
  xpath_bool(PG_FUNCTION_ARGS)
  {
+ 	text	   *document = PG_GETARG_TEXT_P(0);
+ 	text	   *xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
  	xmlChar    *xpath;
  	int			bRes;
  	xmlXPathObjectPtr res;
! 	xpath_workspace workspace;
  
  	xpath = pgxml_texttoxmlchar(xpathsupp);
  
! 	res = pgxml_xpath(document, xpath, &workspace);
! 
  	pfree(xpath);
  
  	if (res == NULL)
*************** xpath_bool(PG_FUNCTION_ARGS)
*** 382,387 ****
--- 386,393 ----
  
  	bRes = xmlXPathCastToBoolean(res);
  
+ 	cleanup_workspace(&workspace);
+ 
  	PG_RETURN_BOOL(bRes);
  }
  
*************** xpath_bool(PG_FUNCTION_ARGS)
*** 390,438 ****
  /* Core function to evaluate XPath query */
  
  static xmlXPathObjectPtr
! pgxml_xpath(text *document, xmlChar *xpath)
  {
! 	xmlDocPtr	doctree;
! 	xmlXPathContextPtr ctxt;
  	xmlXPathObjectPtr res;
  	xmlXPathCompExprPtr comppath;
- 	int32		docsize;
  
! 	docsize = VARSIZE(document) - VARHDRSZ;
  
  	pgxml_parser_init();
  
! 	doctree = xmlParseMemory((char *) VARDATA(document), docsize);
! 	if (doctree == NULL)
  		return NULL;			/* not well-formed */
  
! 	ctxt = xmlXPathNewContext(doctree);
! 	ctxt->node = xmlDocGetRootElement(doctree);
  
  	/* compile the path */
  	comppath = xmlXPathCompile(xpath);
  	if (comppath == NULL)
  	{
! 		xmlFreeDoc(doctree);
  		xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
  					"XPath Syntax Error");
  	}
  
  	/* Now evaluate the path expression. */
! 	res = xmlXPathCompiledEval(comppath, ctxt);
  	xmlXPathFreeCompExpr(comppath);
  
  	if (res == NULL)
! 	{
! 		xmlXPathFreeContext(ctxt);
! 		xmlFreeDoc(doctree);
  
- 		return NULL;
- 	}
- 	/* xmlFreeDoc(doctree); */
  	return res;
  }
  
  static text *
  pgxml_result_to_text(xmlXPathObjectPtr res,
  					 xmlChar *toptag,
--- 396,456 ----
  /* Core function to evaluate XPath query */
  
  static xmlXPathObjectPtr
! pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
  {
! 	int32		docsize = VARSIZE(document) - VARHDRSZ;
  	xmlXPathObjectPtr res;
  	xmlXPathCompExprPtr comppath;
  
! 	workspace->doctree = NULL;
! 	workspace->ctxt = NULL;
! 	workspace->res = NULL;
  
  	pgxml_parser_init();
  
! 	workspace->doctree = xmlParseMemory((char *) VARDATA(document), docsize);
! 	if (workspace->doctree == NULL)
  		return NULL;			/* not well-formed */
  
! 	workspace->ctxt = xmlXPathNewContext(workspace->doctree);
! 	workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
  
  	/* compile the path */
  	comppath = xmlXPathCompile(xpath);
  	if (comppath == NULL)
  	{
! 		cleanup_workspace(workspace);
  		xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
  					"XPath Syntax Error");
  	}
  
  	/* Now evaluate the path expression. */
! 	res = xmlXPathCompiledEval(comppath, workspace->ctxt);
! 	workspace->res = res;
! 
  	xmlXPathFreeCompExpr(comppath);
  
  	if (res == NULL)
! 		cleanup_workspace(workspace);
  
  	return res;
  }
  
+ /* Clean up after processing the result of pgxml_xpath() */
+ static void
+ cleanup_workspace(xpath_workspace *workspace)
+ {
+ 	if (workspace->res)
+ 		xmlXPathFreeObject(workspace->res);
+ 	workspace->res = NULL;
+ 	if (workspace->ctxt)
+ 		xmlXPathFreeContext(workspace->ctxt);
+ 	workspace->ctxt = NULL;
+ 	if (workspace->doctree)
+ 		xmlFreeDoc(workspace->doctree);
+ 	workspace->doctree = NULL;
+ }
+ 
  static text *
  pgxml_result_to_text(xmlXPathObjectPtr res,
  					 xmlChar *toptag,
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to