@@ -32,6 +32,15 @@ Datum xpath_table(PG_FUNCTION_ARGS);
3232void elog_error (const char * explain , bool force );
3333void pgxml_parser_init (void );
3434
35+ /* workspace for pgxml_xpath() */
36+
37+ typedef struct
38+ {
39+ xmlDocPtr doctree ;
40+ xmlXPathContextPtr ctxt ;
41+ xmlXPathObjectPtr res ;
42+ } xpath_workspace ;
43+
3544/* local declarations */
3645
3746static void pgxml_errorHandler (void * ctxt , const char * msg ,...);
@@ -45,7 +54,10 @@ static text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
4554
4655static xmlChar * pgxml_texttoxmlchar (text * textstring );
4756
48- static xmlXPathObjectPtr pgxml_xpath (text * document , xmlChar * xpath );
57+ static xmlXPathObjectPtr pgxml_xpath (text * document , xmlChar * xpath ,
58+ xpath_workspace * workspace );
59+
60+ static void cleanup_workspace (xpath_workspace * workspace );
4961
5062/* Global variables */
5163static char * pgxml_errorMsg = NULL ; /* overall error message */
@@ -289,25 +301,22 @@ PG_FUNCTION_INFO_V1(xpath_nodeset);
289301Datum
290302xpath_nodeset (PG_FUNCTION_ARGS )
291303{
292- xmlChar * xpath ,
293- * toptag ,
294- * septag ;
295- int32 pathsize ;
296- text * xpathsupp ,
297- * xpres ;
298-
299- /* PG_GETARG_TEXT_P(0) is document buffer */
300- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
304+ text * document = PG_GETARG_TEXT_P (0 );
305+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
306+ xmlChar * toptag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (2 ));
307+ xmlChar * septag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (3 ));
308+ xmlChar * xpath ;
309+ text * xpres ;
310+ xmlXPathObjectPtr res ;
311+ xpath_workspace workspace ;
301312
302- toptag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (2 ));
303- septag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (3 ));
313+ xpath = pgxml_texttoxmlchar (xpathsupp );
304314
305- pathsize = VARSIZE ( xpathsupp ) - VARHDRSZ ;
315+ res = pgxml_xpath ( document , xpath , & workspace ) ;
306316
307- xpath = pgxml_texttoxmlchar ( xpathsupp );
317+ xpres = pgxml_result_to_text ( res , toptag , septag , NULL );
308318
309- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
310- toptag , septag , NULL );
319+ cleanup_workspace (& workspace );
311320
312321 pfree (xpath );
313322
@@ -325,23 +334,21 @@ PG_FUNCTION_INFO_V1(xpath_list);
325334Datum
326335xpath_list (PG_FUNCTION_ARGS )
327336{
328- xmlChar * xpath ,
329- * plainsep ;
330- int32 pathsize ;
331- text * xpathsupp ,
332- * xpres ;
333-
334- /* PG_GETARG_TEXT_P(0) is document buffer */
335- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
337+ text * document = PG_GETARG_TEXT_P (0 );
338+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
339+ xmlChar * plainsep = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (2 ));
340+ xmlChar * xpath ;
341+ text * xpres ;
342+ xmlXPathObjectPtr res ;
343+ xpath_workspace workspace ;
336344
337- plainsep = pgxml_texttoxmlchar (PG_GETARG_TEXT_P ( 2 ) );
345+ xpath = pgxml_texttoxmlchar (xpathsupp );
338346
339- pathsize = VARSIZE ( xpathsupp ) - VARHDRSZ ;
347+ res = pgxml_xpath ( document , xpath , & workspace ) ;
340348
341- xpath = pgxml_texttoxmlchar ( xpathsupp );
349+ xpres = pgxml_result_to_text ( res , NULL , NULL , plainsep );
342350
343- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
344- NULL , NULL , plainsep );
351+ cleanup_workspace (& workspace );
345352
346353 pfree (xpath );
347354
@@ -356,13 +363,13 @@ PG_FUNCTION_INFO_V1(xpath_string);
356363Datum
357364xpath_string (PG_FUNCTION_ARGS )
358365{
366+ text * document = PG_GETARG_TEXT_P (0 );
367+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
359368 xmlChar * xpath ;
360369 int32 pathsize ;
361- text * xpathsupp ,
362- * xpres ;
363-
364- /* PG_GETARG_TEXT_P(0) is document buffer */
365- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
370+ text * xpres ;
371+ xmlXPathObjectPtr res ;
372+ xpath_workspace workspace ;
366373
367374 pathsize = VARSIZE (xpathsupp ) - VARHDRSZ ;
368375
@@ -373,13 +380,16 @@ xpath_string(PG_FUNCTION_ARGS)
373380 /* We could try casting to string using the libxml function? */
374381
375382 xpath = (xmlChar * ) palloc (pathsize + 9 );
376- memcpy ((char * ) (xpath + 7 ), VARDATA (xpathsupp ), pathsize );
377383 strncpy ((char * ) xpath , "string(" , 7 );
384+ memcpy ((char * ) (xpath + 7 ), VARDATA (xpathsupp ), pathsize );
378385 xpath [pathsize + 7 ] = ')' ;
379386 xpath [pathsize + 8 ] = '\0' ;
380387
381- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
382- NULL , NULL , NULL );
388+ res = pgxml_xpath (document , xpath , & workspace );
389+
390+ xpres = pgxml_result_to_text (res , NULL , NULL , NULL );
391+
392+ cleanup_workspace (& workspace );
383393
384394 pfree (xpath );
385395
@@ -394,28 +404,26 @@ PG_FUNCTION_INFO_V1(xpath_number);
394404Datum
395405xpath_number (PG_FUNCTION_ARGS )
396406{
407+ text * document = PG_GETARG_TEXT_P (0 );
408+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
397409 xmlChar * xpath ;
398- int32 pathsize ;
399- text * xpathsupp ;
400410 float4 fRes ;
401-
402411 xmlXPathObjectPtr res ;
403-
404- /* PG_GETARG_TEXT_P(0) is document buffer */
405- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
406-
407- pathsize = VARSIZE (xpathsupp ) - VARHDRSZ ;
412+ xpath_workspace workspace ;
408413
409414 xpath = pgxml_texttoxmlchar (xpathsupp );
410415
411- res = pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath );
416+ res = pgxml_xpath (document , xpath , & workspace );
417+
412418 pfree (xpath );
413419
414420 if (res == NULL )
415421 PG_RETURN_NULL ();
416422
417423 fRes = xmlXPathCastToNumber (res );
418424
425+ cleanup_workspace (& workspace );
426+
419427 if (xmlXPathIsNaN (fRes ))
420428 PG_RETURN_NULL ();
421429
@@ -428,28 +436,26 @@ PG_FUNCTION_INFO_V1(xpath_bool);
428436Datum
429437xpath_bool (PG_FUNCTION_ARGS )
430438{
439+ text * document = PG_GETARG_TEXT_P (0 );
440+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
431441 xmlChar * xpath ;
432- int32 pathsize ;
433- text * xpathsupp ;
434442 int bRes ;
435-
436443 xmlXPathObjectPtr res ;
437-
438- /* PG_GETARG_TEXT_P(0) is document buffer */
439- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
440-
441- pathsize = VARSIZE (xpathsupp ) - VARHDRSZ ;
444+ xpath_workspace workspace ;
442445
443446 xpath = pgxml_texttoxmlchar (xpathsupp );
444447
445- res = pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath );
448+ res = pgxml_xpath (document , xpath , & workspace );
449+
446450 pfree (xpath );
447451
448452 if (res == NULL )
449453 PG_RETURN_BOOL (false);
450454
451455 bRes = xmlXPathCastToBoolean (res );
452456
457+ cleanup_workspace (& workspace );
458+
453459 PG_RETURN_BOOL (bRes );
454460}
455461
@@ -458,48 +464,60 @@ xpath_bool(PG_FUNCTION_ARGS)
458464/* Core function to evaluate XPath query */
459465
460466static xmlXPathObjectPtr
461- pgxml_xpath (text * document , xmlChar * xpath )
467+ pgxml_xpath (text * document , xmlChar * xpath , xpath_workspace * workspace )
462468{
463- xmlDocPtr doctree ;
464- xmlXPathContextPtr ctxt ;
469+ int32 docsize = VARSIZE (document ) - VARHDRSZ ;
465470 xmlXPathObjectPtr res ;
466471 xmlXPathCompExprPtr comppath ;
467- int32 docsize ;
468472
469- docsize = VARSIZE (document ) - VARHDRSZ ;
473+ workspace -> doctree = NULL ;
474+ workspace -> ctxt = NULL ;
475+ workspace -> res = NULL ;
470476
471477 pgxml_parser_init ();
472478
473- doctree = xmlParseMemory ((char * ) VARDATA (document ), docsize );
474- if (doctree == NULL )
479+ workspace -> doctree = xmlParseMemory ((char * ) VARDATA (document ), docsize );
480+ if (workspace -> doctree == NULL )
475481 return NULL ; /* not well-formed */
476482
477- ctxt = xmlXPathNewContext (doctree );
478- ctxt -> node = xmlDocGetRootElement (doctree );
483+ workspace -> ctxt = xmlXPathNewContext (workspace -> doctree );
484+ workspace -> ctxt -> node = xmlDocGetRootElement (workspace -> doctree );
479485
480486 /* compile the path */
481487 comppath = xmlXPathCompile (xpath );
482488 if (comppath == NULL )
483489 {
484- xmlFreeDoc ( doctree );
490+ cleanup_workspace ( workspace );
485491 elog_error ("XPath Syntax Error" , true);
486492 }
487493
488494 /* Now evaluate the path expression. */
489- res = xmlXPathCompiledEval (comppath , ctxt );
495+ res = xmlXPathCompiledEval (comppath , workspace -> ctxt );
496+ workspace -> res = res ;
497+
490498 xmlXPathFreeCompExpr (comppath );
491499
492500 if (res == NULL )
493- {
494- xmlXPathFreeContext (ctxt );
495- xmlFreeDoc (doctree );
501+ cleanup_workspace (workspace );
496502
497- return NULL ;
498- }
499- /* xmlFreeDoc(doctree); */
500503 return res ;
501504}
502505
506+ /* Clean up after processing the result of pgxml_xpath() */
507+ static void
508+ cleanup_workspace (xpath_workspace * workspace )
509+ {
510+ if (workspace -> res )
511+ xmlXPathFreeObject (workspace -> res );
512+ workspace -> res = NULL ;
513+ if (workspace -> ctxt )
514+ xmlXPathFreeContext (workspace -> ctxt );
515+ workspace -> ctxt = NULL ;
516+ if (workspace -> doctree )
517+ xmlFreeDoc (workspace -> doctree );
518+ workspace -> doctree = NULL ;
519+ }
520+
503521static text *
504522pgxml_result_to_text (xmlXPathObjectPtr res ,
505523 xmlChar * toptag ,
0 commit comments