33
33
* ENHANCEMENTS, OR MODIFICATIONS.
34
34
*
35
35
* IDENTIFICATION
36
- * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.59 2004/11/20 19:07:40 tgl Exp $
36
+ * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.60 2004/11/21 21:17:03 tgl Exp $
37
37
*
38
38
**********************************************************************/
39
39
@@ -1593,20 +1593,79 @@ plperl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc)
1593
1593
}
1594
1594
1595
1595
1596
+ /*
1597
+ * Implementation of spi_exec_query() Perl function
1598
+ */
1596
1599
HV *
1597
1600
plperl_spi_exec (char * query , int limit )
1598
1601
{
1599
1602
HV * ret_hv ;
1600
- int spi_rv ;
1601
1603
1602
- spi_rv = SPI_execute (query , plperl_current_prodesc -> fn_readonly , limit );
1603
- ret_hv = plperl_spi_execute_fetch_result (SPI_tuptable , SPI_processed , spi_rv );
1604
+ /*
1605
+ * Execute the query inside a sub-transaction, so we can cope with
1606
+ * errors sanely
1607
+ */
1608
+ MemoryContext oldcontext = CurrentMemoryContext ;
1609
+ ResourceOwner oldowner = CurrentResourceOwner ;
1610
+
1611
+ BeginInternalSubTransaction (NULL );
1612
+ /* Want to run inside function's memory context */
1613
+ MemoryContextSwitchTo (oldcontext );
1614
+
1615
+ PG_TRY ();
1616
+ {
1617
+ int spi_rv ;
1618
+
1619
+ spi_rv = SPI_execute (query , plperl_current_prodesc -> fn_readonly ,
1620
+ limit );
1621
+ ret_hv = plperl_spi_execute_fetch_result (SPI_tuptable , SPI_processed ,
1622
+ spi_rv );
1623
+
1624
+ /* Commit the inner transaction, return to outer xact context */
1625
+ ReleaseCurrentSubTransaction ();
1626
+ MemoryContextSwitchTo (oldcontext );
1627
+ CurrentResourceOwner = oldowner ;
1628
+ /*
1629
+ * AtEOSubXact_SPI() should not have popped any SPI context,
1630
+ * but just in case it did, make sure we remain connected.
1631
+ */
1632
+ SPI_restore_connection ();
1633
+ }
1634
+ PG_CATCH ();
1635
+ {
1636
+ ErrorData * edata ;
1637
+
1638
+ /* Save error info */
1639
+ MemoryContextSwitchTo (oldcontext );
1640
+ edata = CopyErrorData ();
1641
+ FlushErrorState ();
1642
+
1643
+ /* Abort the inner transaction */
1644
+ RollbackAndReleaseCurrentSubTransaction ();
1645
+ MemoryContextSwitchTo (oldcontext );
1646
+ CurrentResourceOwner = oldowner ;
1647
+
1648
+ /*
1649
+ * If AtEOSubXact_SPI() popped any SPI context of the subxact,
1650
+ * it will have left us in a disconnected state. We need this
1651
+ * hack to return to connected state.
1652
+ */
1653
+ SPI_restore_connection ();
1654
+
1655
+ /* Punt the error to Perl */
1656
+ croak ("%s" , edata -> message );
1657
+
1658
+ /* Can't get here, but keep compiler quiet */
1659
+ return NULL ;
1660
+ }
1661
+ PG_END_TRY ();
1604
1662
1605
1663
return ret_hv ;
1606
1664
}
1607
1665
1608
1666
static HV *
1609
- plperl_spi_execute_fetch_result (SPITupleTable * tuptable , int processed , int status )
1667
+ plperl_spi_execute_fetch_result (SPITupleTable * tuptable , int processed ,
1668
+ int status )
1610
1669
{
1611
1670
HV * result ;
1612
1671
@@ -1619,21 +1678,18 @@ plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed, int stat
1619
1678
1620
1679
if (status == SPI_OK_SELECT )
1621
1680
{
1622
- if (processed )
1623
- {
1624
- AV * rows ;
1625
- HV * row ;
1626
- int i ;
1681
+ AV * rows ;
1682
+ HV * row ;
1683
+ int i ;
1627
1684
1628
- rows = newAV ();
1629
- for (i = 0 ; i < processed ; i ++ )
1630
- {
1631
- row = plperl_hash_from_tuple (tuptable -> vals [i ], tuptable -> tupdesc );
1632
- av_push (rows , newRV_noinc ((SV * )row ));
1633
- }
1634
- hv_store (result , "rows" , strlen ("rows" ),
1635
- newRV_noinc ((SV * ) rows ), 0 );
1685
+ rows = newAV ();
1686
+ for (i = 0 ; i < processed ; i ++ )
1687
+ {
1688
+ row = plperl_hash_from_tuple (tuptable -> vals [i ], tuptable -> tupdesc );
1689
+ av_push (rows , newRV_noinc ((SV * )row ));
1636
1690
}
1691
+ hv_store (result , "rows" , strlen ("rows" ),
1692
+ newRV_noinc ((SV * ) rows ), 0 );
1637
1693
}
1638
1694
1639
1695
SPI_freetuptable (tuptable );
0 commit comments