@@ -32,6 +32,15 @@ Datum xpath_table(PG_FUNCTION_ARGS);
32
32
void elog_error (const char * explain , bool force );
33
33
void pgxml_parser_init (void );
34
34
35
+ /* workspace for pgxml_xpath() */
36
+
37
+ typedef struct
38
+ {
39
+ xmlDocPtr doctree ;
40
+ xmlXPathContextPtr ctxt ;
41
+ xmlXPathObjectPtr res ;
42
+ } xpath_workspace ;
43
+
35
44
/* local declarations */
36
45
37
46
static void pgxml_errorHandler (void * ctxt , const char * msg ,...);
@@ -45,7 +54,10 @@ static text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
45
54
46
55
static xmlChar * pgxml_texttoxmlchar (text * textstring );
47
56
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 );
49
61
50
62
/* Global variables */
51
63
static char * pgxml_errorMsg = NULL ; /* overall error message */
@@ -289,25 +301,22 @@ PG_FUNCTION_INFO_V1(xpath_nodeset);
289
301
Datum
290
302
xpath_nodeset (PG_FUNCTION_ARGS )
291
303
{
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 ;
301
312
302
- toptag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (2 ));
303
- septag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (3 ));
313
+ xpath = pgxml_texttoxmlchar (xpathsupp );
304
314
305
- pathsize = VARSIZE ( xpathsupp ) - VARHDRSZ ;
315
+ res = pgxml_xpath ( document , xpath , & workspace ) ;
306
316
307
- xpath = pgxml_texttoxmlchar ( xpathsupp );
317
+ xpres = pgxml_result_to_text ( res , toptag , septag , NULL );
308
318
309
- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
310
- toptag , septag , NULL );
319
+ cleanup_workspace (& workspace );
311
320
312
321
pfree (xpath );
313
322
@@ -325,23 +334,21 @@ PG_FUNCTION_INFO_V1(xpath_list);
325
334
Datum
326
335
xpath_list (PG_FUNCTION_ARGS )
327
336
{
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 ;
336
344
337
- plainsep = pgxml_texttoxmlchar (PG_GETARG_TEXT_P ( 2 ) );
345
+ xpath = pgxml_texttoxmlchar (xpathsupp );
338
346
339
- pathsize = VARSIZE ( xpathsupp ) - VARHDRSZ ;
347
+ res = pgxml_xpath ( document , xpath , & workspace ) ;
340
348
341
- xpath = pgxml_texttoxmlchar ( xpathsupp );
349
+ xpres = pgxml_result_to_text ( res , NULL , NULL , plainsep );
342
350
343
- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
344
- NULL , NULL , plainsep );
351
+ cleanup_workspace (& workspace );
345
352
346
353
pfree (xpath );
347
354
@@ -356,13 +363,13 @@ PG_FUNCTION_INFO_V1(xpath_string);
356
363
Datum
357
364
xpath_string (PG_FUNCTION_ARGS )
358
365
{
366
+ text * document = PG_GETARG_TEXT_P (0 );
367
+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
359
368
xmlChar * xpath ;
360
369
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 ;
366
373
367
374
pathsize = VARSIZE (xpathsupp ) - VARHDRSZ ;
368
375
@@ -373,13 +380,16 @@ xpath_string(PG_FUNCTION_ARGS)
373
380
/* We could try casting to string using the libxml function? */
374
381
375
382
xpath = (xmlChar * ) palloc (pathsize + 9 );
376
- memcpy ((char * ) (xpath + 7 ), VARDATA (xpathsupp ), pathsize );
377
383
strncpy ((char * ) xpath , "string(" , 7 );
384
+ memcpy ((char * ) (xpath + 7 ), VARDATA (xpathsupp ), pathsize );
378
385
xpath [pathsize + 7 ] = ')' ;
379
386
xpath [pathsize + 8 ] = '\0' ;
380
387
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 );
383
393
384
394
pfree (xpath );
385
395
@@ -394,28 +404,26 @@ PG_FUNCTION_INFO_V1(xpath_number);
394
404
Datum
395
405
xpath_number (PG_FUNCTION_ARGS )
396
406
{
407
+ text * document = PG_GETARG_TEXT_P (0 );
408
+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
397
409
xmlChar * xpath ;
398
- int32 pathsize ;
399
- text * xpathsupp ;
400
410
float4 fRes ;
401
-
402
411
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 ;
408
413
409
414
xpath = pgxml_texttoxmlchar (xpathsupp );
410
415
411
- res = pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath );
416
+ res = pgxml_xpath (document , xpath , & workspace );
417
+
412
418
pfree (xpath );
413
419
414
420
if (res == NULL )
415
421
PG_RETURN_NULL ();
416
422
417
423
fRes = xmlXPathCastToNumber (res );
418
424
425
+ cleanup_workspace (& workspace );
426
+
419
427
if (xmlXPathIsNaN (fRes ))
420
428
PG_RETURN_NULL ();
421
429
@@ -428,28 +436,26 @@ PG_FUNCTION_INFO_V1(xpath_bool);
428
436
Datum
429
437
xpath_bool (PG_FUNCTION_ARGS )
430
438
{
439
+ text * document = PG_GETARG_TEXT_P (0 );
440
+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
431
441
xmlChar * xpath ;
432
- int32 pathsize ;
433
- text * xpathsupp ;
434
442
int bRes ;
435
-
436
443
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 ;
442
445
443
446
xpath = pgxml_texttoxmlchar (xpathsupp );
444
447
445
- res = pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath );
448
+ res = pgxml_xpath (document , xpath , & workspace );
449
+
446
450
pfree (xpath );
447
451
448
452
if (res == NULL )
449
453
PG_RETURN_BOOL (false);
450
454
451
455
bRes = xmlXPathCastToBoolean (res );
452
456
457
+ cleanup_workspace (& workspace );
458
+
453
459
PG_RETURN_BOOL (bRes );
454
460
}
455
461
@@ -458,48 +464,60 @@ xpath_bool(PG_FUNCTION_ARGS)
458
464
/* Core function to evaluate XPath query */
459
465
460
466
static xmlXPathObjectPtr
461
- pgxml_xpath (text * document , xmlChar * xpath )
467
+ pgxml_xpath (text * document , xmlChar * xpath , xpath_workspace * workspace )
462
468
{
463
- xmlDocPtr doctree ;
464
- xmlXPathContextPtr ctxt ;
469
+ int32 docsize = VARSIZE (document ) - VARHDRSZ ;
465
470
xmlXPathObjectPtr res ;
466
471
xmlXPathCompExprPtr comppath ;
467
- int32 docsize ;
468
472
469
- docsize = VARSIZE (document ) - VARHDRSZ ;
473
+ workspace -> doctree = NULL ;
474
+ workspace -> ctxt = NULL ;
475
+ workspace -> res = NULL ;
470
476
471
477
pgxml_parser_init ();
472
478
473
- doctree = xmlParseMemory ((char * ) VARDATA (document ), docsize );
474
- if (doctree == NULL )
479
+ workspace -> doctree = xmlParseMemory ((char * ) VARDATA (document ), docsize );
480
+ if (workspace -> doctree == NULL )
475
481
return NULL ; /* not well-formed */
476
482
477
- ctxt = xmlXPathNewContext (doctree );
478
- ctxt -> node = xmlDocGetRootElement (doctree );
483
+ workspace -> ctxt = xmlXPathNewContext (workspace -> doctree );
484
+ workspace -> ctxt -> node = xmlDocGetRootElement (workspace -> doctree );
479
485
480
486
/* compile the path */
481
487
comppath = xmlXPathCompile (xpath );
482
488
if (comppath == NULL )
483
489
{
484
- xmlFreeDoc ( doctree );
490
+ cleanup_workspace ( workspace );
485
491
elog_error ("XPath Syntax Error" , true);
486
492
}
487
493
488
494
/* Now evaluate the path expression. */
489
- res = xmlXPathCompiledEval (comppath , ctxt );
495
+ res = xmlXPathCompiledEval (comppath , workspace -> ctxt );
496
+ workspace -> res = res ;
497
+
490
498
xmlXPathFreeCompExpr (comppath );
491
499
492
500
if (res == NULL )
493
- {
494
- xmlXPathFreeContext (ctxt );
495
- xmlFreeDoc (doctree );
501
+ cleanup_workspace (workspace );
496
502
497
- return NULL ;
498
- }
499
- /* xmlFreeDoc(doctree); */
500
503
return res ;
501
504
}
502
505
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
+
503
521
static text *
504
522
pgxml_result_to_text (xmlXPathObjectPtr res ,
505
523
xmlChar * toptag ,
0 commit comments