@@ -40,6 +40,15 @@ Datum xpath_table(PG_FUNCTION_ARGS);
40
40
41
41
void pgxml_parser_init (void );
42
42
43
+ /* workspace for pgxml_xpath() */
44
+
45
+ typedef struct
46
+ {
47
+ xmlDocPtr doctree ;
48
+ xmlXPathContextPtr ctxt ;
49
+ xmlXPathObjectPtr res ;
50
+ } xpath_workspace ;
51
+
43
52
/* local declarations */
44
53
45
54
static xmlChar * pgxmlNodeSetToText (xmlNodeSetPtr nodeset ,
@@ -51,7 +60,10 @@ static text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
51
60
52
61
static xmlChar * pgxml_texttoxmlchar (text * textstring );
53
62
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 );
55
67
56
68
57
69
/*
@@ -214,25 +226,22 @@ PG_FUNCTION_INFO_V1(xpath_nodeset);
214
226
Datum
215
227
xpath_nodeset (PG_FUNCTION_ARGS )
216
228
{
217
- xmlChar * xpath ,
218
- * toptag ,
219
- * septag ;
220
- int32 pathsize ;
221
- text * xpathsupp ,
222
- * xpres ;
223
-
224
- /* PG_GETARG_TEXT_P(0) is document buffer */
225
- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
229
+ text * document = PG_GETARG_TEXT_P (0 );
230
+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
231
+ xmlChar * toptag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (2 ));
232
+ xmlChar * septag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (3 ));
233
+ xmlChar * xpath ;
234
+ text * xpres ;
235
+ xmlXPathObjectPtr res ;
236
+ xpath_workspace workspace ;
226
237
227
- toptag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (2 ));
228
- septag = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (3 ));
238
+ xpath = pgxml_texttoxmlchar (xpathsupp );
229
239
230
- pathsize = VARSIZE ( xpathsupp ) - VARHDRSZ ;
240
+ res = pgxml_xpath ( document , xpath , & workspace ) ;
231
241
232
- xpath = pgxml_texttoxmlchar ( xpathsupp );
242
+ xpres = pgxml_result_to_text ( res , toptag , septag , NULL );
233
243
234
- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
235
- toptag , septag , NULL );
244
+ cleanup_workspace (& workspace );
236
245
237
246
pfree (xpath );
238
247
@@ -250,23 +259,21 @@ PG_FUNCTION_INFO_V1(xpath_list);
250
259
Datum
251
260
xpath_list (PG_FUNCTION_ARGS )
252
261
{
253
- xmlChar * xpath ,
254
- * plainsep ;
255
- int32 pathsize ;
256
- text * xpathsupp ,
257
- * xpres ;
258
-
259
- /* PG_GETARG_TEXT_P(0) is document buffer */
260
- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
262
+ text * document = PG_GETARG_TEXT_P (0 );
263
+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
264
+ xmlChar * plainsep = pgxml_texttoxmlchar (PG_GETARG_TEXT_P (2 ));
265
+ xmlChar * xpath ;
266
+ text * xpres ;
267
+ xmlXPathObjectPtr res ;
268
+ xpath_workspace workspace ;
261
269
262
- plainsep = pgxml_texttoxmlchar (PG_GETARG_TEXT_P ( 2 ) );
270
+ xpath = pgxml_texttoxmlchar (xpathsupp );
263
271
264
- pathsize = VARSIZE ( xpathsupp ) - VARHDRSZ ;
272
+ res = pgxml_xpath ( document , xpath , & workspace ) ;
265
273
266
- xpath = pgxml_texttoxmlchar ( xpathsupp );
274
+ xpres = pgxml_result_to_text ( res , NULL , NULL , plainsep );
267
275
268
- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
269
- NULL , NULL , plainsep );
276
+ cleanup_workspace (& workspace );
270
277
271
278
pfree (xpath );
272
279
@@ -281,13 +288,13 @@ PG_FUNCTION_INFO_V1(xpath_string);
281
288
Datum
282
289
xpath_string (PG_FUNCTION_ARGS )
283
290
{
291
+ text * document = PG_GETARG_TEXT_P (0 );
292
+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
284
293
xmlChar * xpath ;
285
294
int32 pathsize ;
286
- text * xpathsupp ,
287
- * xpres ;
288
-
289
- /* PG_GETARG_TEXT_P(0) is document buffer */
290
- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
295
+ text * xpres ;
296
+ xmlXPathObjectPtr res ;
297
+ xpath_workspace workspace ;
291
298
292
299
pathsize = VARSIZE (xpathsupp ) - VARHDRSZ ;
293
300
@@ -298,13 +305,16 @@ xpath_string(PG_FUNCTION_ARGS)
298
305
/* We could try casting to string using the libxml function? */
299
306
300
307
xpath = (xmlChar * ) palloc (pathsize + 9 );
301
- memcpy ((char * ) (xpath + 7 ), VARDATA (xpathsupp ), pathsize );
302
308
strncpy ((char * ) xpath , "string(" , 7 );
309
+ memcpy ((char * ) (xpath + 7 ), VARDATA (xpathsupp ), pathsize );
303
310
xpath [pathsize + 7 ] = ')' ;
304
311
xpath [pathsize + 8 ] = '\0' ;
305
312
306
- xpres = pgxml_result_to_text (pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath ),
307
- NULL , NULL , NULL );
313
+ res = pgxml_xpath (document , xpath , & workspace );
314
+
315
+ xpres = pgxml_result_to_text (res , NULL , NULL , NULL );
316
+
317
+ cleanup_workspace (& workspace );
308
318
309
319
pfree (xpath );
310
320
@@ -319,28 +329,26 @@ PG_FUNCTION_INFO_V1(xpath_number);
319
329
Datum
320
330
xpath_number (PG_FUNCTION_ARGS )
321
331
{
332
+ text * document = PG_GETARG_TEXT_P (0 );
333
+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
322
334
xmlChar * xpath ;
323
- int32 pathsize ;
324
- text * xpathsupp ;
325
335
float4 fRes ;
326
-
327
336
xmlXPathObjectPtr res ;
328
-
329
- /* PG_GETARG_TEXT_P(0) is document buffer */
330
- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
331
-
332
- pathsize = VARSIZE (xpathsupp ) - VARHDRSZ ;
337
+ xpath_workspace workspace ;
333
338
334
339
xpath = pgxml_texttoxmlchar (xpathsupp );
335
340
336
- res = pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath );
341
+ res = pgxml_xpath (document , xpath , & workspace );
342
+
337
343
pfree (xpath );
338
344
339
345
if (res == NULL )
340
346
PG_RETURN_NULL ();
341
347
342
348
fRes = xmlXPathCastToNumber (res );
343
349
350
+ cleanup_workspace (& workspace );
351
+
344
352
if (xmlXPathIsNaN (fRes ))
345
353
PG_RETURN_NULL ();
346
354
@@ -353,28 +361,26 @@ PG_FUNCTION_INFO_V1(xpath_bool);
353
361
Datum
354
362
xpath_bool (PG_FUNCTION_ARGS )
355
363
{
364
+ text * document = PG_GETARG_TEXT_P (0 );
365
+ text * xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
356
366
xmlChar * xpath ;
357
- int32 pathsize ;
358
- text * xpathsupp ;
359
367
int bRes ;
360
-
361
368
xmlXPathObjectPtr res ;
362
-
363
- /* PG_GETARG_TEXT_P(0) is document buffer */
364
- xpathsupp = PG_GETARG_TEXT_P (1 ); /* XPath expression */
365
-
366
- pathsize = VARSIZE (xpathsupp ) - VARHDRSZ ;
369
+ xpath_workspace workspace ;
367
370
368
371
xpath = pgxml_texttoxmlchar (xpathsupp );
369
372
370
- res = pgxml_xpath (PG_GETARG_TEXT_P (0 ), xpath );
373
+ res = pgxml_xpath (document , xpath , & workspace );
374
+
371
375
pfree (xpath );
372
376
373
377
if (res == NULL )
374
378
PG_RETURN_BOOL (false);
375
379
376
380
bRes = xmlXPathCastToBoolean (res );
377
381
382
+ cleanup_workspace (& workspace );
383
+
378
384
PG_RETURN_BOOL (bRes );
379
385
}
380
386
@@ -383,49 +389,61 @@ xpath_bool(PG_FUNCTION_ARGS)
383
389
/* Core function to evaluate XPath query */
384
390
385
391
static xmlXPathObjectPtr
386
- pgxml_xpath (text * document , xmlChar * xpath )
392
+ pgxml_xpath (text * document , xmlChar * xpath , xpath_workspace * workspace )
387
393
{
388
- xmlDocPtr doctree ;
389
- xmlXPathContextPtr ctxt ;
394
+ int32 docsize = VARSIZE (document ) - VARHDRSZ ;
390
395
xmlXPathObjectPtr res ;
391
396
xmlXPathCompExprPtr comppath ;
392
- int32 docsize ;
393
397
394
- docsize = VARSIZE (document ) - VARHDRSZ ;
398
+ workspace -> doctree = NULL ;
399
+ workspace -> ctxt = NULL ;
400
+ workspace -> res = NULL ;
395
401
396
402
pgxml_parser_init ();
397
403
398
- doctree = xmlParseMemory ((char * ) VARDATA (document ), docsize );
399
- if (doctree == NULL )
404
+ workspace -> doctree = xmlParseMemory ((char * ) VARDATA (document ), docsize );
405
+ if (workspace -> doctree == NULL )
400
406
return NULL ; /* not well-formed */
401
407
402
- ctxt = xmlXPathNewContext (doctree );
403
- ctxt -> node = xmlDocGetRootElement (doctree );
408
+ workspace -> ctxt = xmlXPathNewContext (workspace -> doctree );
409
+ workspace -> ctxt -> node = xmlDocGetRootElement (workspace -> doctree );
404
410
405
411
/* compile the path */
406
412
comppath = xmlXPathCompile (xpath );
407
413
if (comppath == NULL )
408
414
{
409
- xmlFreeDoc ( doctree );
415
+ cleanup_workspace ( workspace );
410
416
xml_ereport (ERROR , ERRCODE_EXTERNAL_ROUTINE_EXCEPTION ,
411
417
"XPath Syntax Error" );
412
418
}
413
419
414
420
/* Now evaluate the path expression. */
415
- res = xmlXPathCompiledEval (comppath , ctxt );
421
+ res = xmlXPathCompiledEval (comppath , workspace -> ctxt );
422
+ workspace -> res = res ;
423
+
416
424
xmlXPathFreeCompExpr (comppath );
417
425
418
426
if (res == NULL )
419
- {
420
- xmlXPathFreeContext (ctxt );
421
- xmlFreeDoc (doctree );
427
+ cleanup_workspace (workspace );
422
428
423
- return NULL ;
424
- }
425
- /* xmlFreeDoc(doctree); */
426
429
return res ;
427
430
}
428
431
432
+ /* Clean up after processing the result of pgxml_xpath() */
433
+ static void
434
+ cleanup_workspace (xpath_workspace * workspace )
435
+ {
436
+ if (workspace -> res )
437
+ xmlXPathFreeObject (workspace -> res );
438
+ workspace -> res = NULL ;
439
+ if (workspace -> ctxt )
440
+ xmlXPathFreeContext (workspace -> ctxt );
441
+ workspace -> ctxt = NULL ;
442
+ if (workspace -> doctree )
443
+ xmlFreeDoc (workspace -> doctree );
444
+ workspace -> doctree = NULL ;
445
+ }
446
+
429
447
static text *
430
448
pgxml_result_to_text (xmlXPathObjectPtr res ,
431
449
xmlChar * toptag ,
0 commit comments