@@ -40,6 +40,15 @@ Datum xpath_table(PG_FUNCTION_ARGS);
4040
4141void pgxml_parser_init (void );
4242
43+ /* workspace for pgxml_xpath() */
44+
45+ typedef struct
46+ {
47+ xmlDocPtr doctree ;
48+ xmlXPathContextPtr ctxt ;
49+ xmlXPathObjectPtr res ;
50+ } xpath_workspace ;
51+
4352/* local declarations */
4453
4554static xmlChar * pgxmlNodeSetToText (xmlNodeSetPtr nodeset ,
@@ -51,7 +60,10 @@ static text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
5160
5261static xmlChar * pgxml_texttoxmlchar (text * textstring );
5362
54- static xmlXPathObjectPtr pgxml_xpath (text * document , xmlChar * xpath );
63+ static xmlXPathObjectPtr pgxml_xpath (text * document , xmlChar * xpath ,
64+ xpath_workspace * workspace );
65+
66+ static void cleanup_workspace (xpath_workspace * workspace );
5567
5668
5769/*
@@ -221,25 +233,22 @@ PG_FUNCTION_INFO_V1(xpath_nodeset);
221233Datum
222234xpath_nodeset (PG_FUNCTION_ARGS )
223235{
224- xmlChar * xpath ,
225- * toptag ,
226- * septag ;
227- int32 pathsize ;
228- text * xpathsupp ,
229- * xpres ;
230-
231- /* PG_GETARG_TEXT_P(0) is document buffer */
232- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
236+ text * document = PG_GETARG_TEXT_P (0 );
237+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
238+ xmlChar * toptag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (2 ));
239+ xmlChar * septag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (3 ));
240+ xmlChar * xpath ;
241+ text * xpres ;
242+ xmlXPathObjectPtr res ;
243+ xpath_workspace workspace ;
233244
234- toptag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (2 ));
235- septag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (3 ));
245+ xpath = pgxml_texttoxmlchar (xpathsupp );
236246
237- pathsize = VARSIZE ( xpathsupp ) - VARHDRSZ ;
247+ res = pgxml_xpath ( document , xpath , & workspace ) ;
238248
239- xpath = pgxml_texttoxmlchar ( xpathsupp );
249+ xpres = pgxml_result_to_text ( res , toptag , septag , NULL );
240250
241- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
242- toptag , septag , NULL );
251+ cleanup_workspace (& workspace );
243252
244253 pfree (xpath );
245254
@@ -257,23 +266,21 @@ PG_FUNCTION_INFO_V1(xpath_list);
257266Datum
258267xpath_list (PG_FUNCTION_ARGS )
259268{
260- xmlChar * xpath ,
261- * plainsep ;
262- int32 pathsize ;
263- text * xpathsupp ,
264- * xpres ;
265-
266- /* PG_GETARG_TEXT_P(0) is document buffer */
267- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
269+ text * document = PG_GETARG_TEXT_P (0 );
270+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
271+ xmlChar * plainsep = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (2 ));
272+ xmlChar * xpath ;
273+ text * xpres ;
274+ xmlXPathObjectPtr res ;
275+ xpath_workspace workspace ;
268276
269- plainsep = pgxml_texttoxmlchar (PG_GETARG_TEXT_P ( 2 ) );
277+ xpath = pgxml_texttoxmlchar (xpathsupp );
270278
271- pathsize = VARSIZE ( xpathsupp ) - VARHDRSZ ;
279+ res = pgxml_xpath ( document , xpath , & workspace ) ;
272280
273- xpath = pgxml_texttoxmlchar ( xpathsupp );
281+ xpres = pgxml_result_to_text ( res , NULL , NULL , plainsep );
274282
275- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
276- NULL , NULL , plainsep );
283+ cleanup_workspace (& workspace );
277284
278285 pfree (xpath );
279286
@@ -288,13 +295,13 @@ PG_FUNCTION_INFO_V1(xpath_string);
288295Datum
289296xpath_string (PG_FUNCTION_ARGS )
290297{
298+ text * document = PG_GETARG_TEXT_P (0 );
299+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
291300 xmlChar * xpath ;
292301 int32 pathsize ;
293- text * xpathsupp ,
294- * xpres ;
295-
296- /* PG_GETARG_TEXT_P(0) is document buffer */
297- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
302+ text * xpres ;
303+ xmlXPathObjectPtr res ;
304+ xpath_workspace workspace ;
298305
299306 pathsize = VARSIZE (xpathsupp ) - VARHDRSZ ;
300307
@@ -305,13 +312,16 @@ xpath_string(PG_FUNCTION_ARGS)
305312 /* We could try casting to string using the libxml function? */
306313
307314 xpath = (xmlChar * ) palloc (pathsize + 9 );
308- memcpy ((char * ) (xpath + 7 ), VARDATA (xpathsupp ), pathsize );
309315 strncpy ((char * ) xpath , "string(" , 7 );
316+ memcpy ((char * ) (xpath + 7 ), VARDATA (xpathsupp ), pathsize );
310317 xpath [pathsize + 7 ] = ')' ;
311318 xpath [pathsize + 8 ] = '\0' ;
312319
313- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
314- NULL , NULL , NULL );
320+ res = pgxml_xpath (document , xpath , & workspace );
321+
322+ xpres = pgxml_result_to_text (res , NULL , NULL , NULL );
323+
324+ cleanup_workspace (& workspace );
315325
316326 pfree (xpath );
317327
@@ -326,28 +336,26 @@ PG_FUNCTION_INFO_V1(xpath_number);
326336Datum
327337xpath_number (PG_FUNCTION_ARGS )
328338{
339+ text * document = PG_GETARG_TEXT_P (0 );
340+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
329341 xmlChar * xpath ;
330- int32 pathsize ;
331- text * xpathsupp ;
332342 float4 fRes ;
333-
334343 xmlXPathObjectPtr res ;
335-
336- /* PG_GETARG_TEXT_P(0) is document buffer */
337- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
338-
339- pathsize = VARSIZE (xpathsupp ) - VARHDRSZ ;
344+ xpath_workspace workspace ;
340345
341346 xpath = pgxml_texttoxmlchar (xpathsupp );
342347
343- res = pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath );
348+ res = pgxml_xpath (document , xpath , & workspace );
349+
344350 pfree (xpath );
345351
346352 if (res == NULL )
347353 PG_RETURN_NULL ();
348354
349355 fRes = xmlXPathCastToNumber (res );
350356
357+ cleanup_workspace (& workspace );
358+
351359 if (xmlXPathIsNaN (fRes ))
352360 PG_RETURN_NULL ();
353361
@@ -360,28 +368,26 @@ PG_FUNCTION_INFO_V1(xpath_bool);
360368Datum
361369xpath_bool (PG_FUNCTION_ARGS )
362370{
371+ text * document = PG_GETARG_TEXT_P (0 );
372+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
363373 xmlChar * xpath ;
364- int32 pathsize ;
365- text * xpathsupp ;
366374 int bRes ;
367-
368375 xmlXPathObjectPtr res ;
369-
370- /* PG_GETARG_TEXT_P(0) is document buffer */
371- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
372-
373- pathsize = VARSIZE (xpathsupp ) - VARHDRSZ ;
376+ xpath_workspace workspace ;
374377
375378 xpath = pgxml_texttoxmlchar (xpathsupp );
376379
377- res = pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath );
380+ res = pgxml_xpath (document , xpath , & workspace );
381+
378382 pfree (xpath );
379383
380384 if (res == NULL )
381385 PG_RETURN_BOOL (false);
382386
383387 bRes = xmlXPathCastToBoolean (res );
384388
389+ cleanup_workspace (& workspace );
390+
385391 PG_RETURN_BOOL (bRes );
386392}
387393
@@ -390,49 +396,61 @@ xpath_bool(PG_FUNCTION_ARGS)
390396/* Core function to evaluate XPath query */
391397
392398static xmlXPathObjectPtr
393- pgxml_xpath (text * document , xmlChar * xpath )
399+ pgxml_xpath (text * document , xmlChar * xpath , xpath_workspace * workspace )
394400{
395- xmlDocPtr doctree ;
396- xmlXPathContextPtr ctxt ;
401+ int32 docsize = VARSIZE (document ) - VARHDRSZ ;
397402 xmlXPathObjectPtr res ;
398403 xmlXPathCompExprPtr comppath ;
399- int32 docsize ;
400404
401- docsize = VARSIZE (document ) - VARHDRSZ ;
405+ workspace -> doctree = NULL ;
406+ workspace -> ctxt = NULL ;
407+ workspace -> res = NULL ;
402408
403409 pgxml_parser_init ();
404410
405- doctree = xmlParseMemory ((char * ) VARDATA (document ), docsize );
406- if (doctree == NULL )
411+ workspace -> doctree = xmlParseMemory ((char * ) VARDATA (document ), docsize );
412+ if (workspace -> doctree == NULL )
407413 return NULL ; /* not well-formed */
408414
409- ctxt = xmlXPathNewContext (doctree );
410- ctxt -> node = xmlDocGetRootElement (doctree );
415+ workspace -> ctxt = xmlXPathNewContext (workspace -> doctree );
416+ workspace -> ctxt -> node = xmlDocGetRootElement (workspace -> doctree );
411417
412418 /* compile the path */
413419 comppath = xmlXPathCompile (xpath );
414420 if (comppath == NULL )
415421 {
416- xmlFreeDoc ( doctree );
422+ cleanup_workspace ( workspace );
417423 xml_ereport (ERROR , ERRCODE_EXTERNAL_ROUTINE_EXCEPTION ,
418424 "XPath Syntax Error" );
419425 }
420426
421427 /* Now evaluate the path expression. */
422- res = xmlXPathCompiledEval (comppath , ctxt );
428+ res = xmlXPathCompiledEval (comppath , workspace -> ctxt );
429+ workspace -> res = res ;
430+
423431 xmlXPathFreeCompExpr (comppath );
424432
425433 if (res == NULL )
426- {
427- xmlXPathFreeContext (ctxt );
428- xmlFreeDoc (doctree );
434+ cleanup_workspace (workspace );
429435
430- return NULL ;
431- }
432- /* xmlFreeDoc(doctree); */
433436 return res ;
434437}
435438
439+ /* Clean up after processing the result of pgxml_xpath() */
440+ static void
441+ cleanup_workspace (xpath_workspace * workspace )
442+ {
443+ if (workspace -> res )
444+ xmlXPathFreeObject (workspace -> res );
445+ workspace -> res = NULL ;
446+ if (workspace -> ctxt )
447+ xmlXPathFreeContext (workspace -> ctxt );
448+ workspace -> ctxt = NULL ;
449+ if (workspace -> doctree )
450+ xmlFreeDoc (workspace -> doctree );
451+ workspace -> doctree = NULL ;
452+ }
453+
436454static text *
437455pgxml_result_to_text (xmlXPathObjectPtr res ,
438456 xmlChar * toptag ,
0 commit comments