@@ -189,6 +189,14 @@ macro_rules! check_desync(
189189 )
190190)
191191
192+ macro_rules! fail_unless_failing(
193+ ( $( $t: tt) * ) => (
194+ if !task:: failing( ) {
195+ fail!( $( $t) * )
196+ }
197+ )
198+ )
199+
192200static DEFAULT_PORT : Port = 5432 ;
193201
194202/// Trait for types that can handle Postgres notice messages
@@ -363,11 +371,18 @@ struct InnerPostgresConnection {
363371 cancel_data : PostgresCancelData ,
364372 unknown_types : HashMap < Oid , ~str > ,
365373 desynchronized : bool ,
374+ finished : bool ,
366375}
367376
368377impl Drop for InnerPostgresConnection {
369378 fn drop ( & mut self ) {
370- let _ = self . write_messages ( [ Terminate ] ) ;
379+ if !self . finished {
380+ match self . finish_inner ( ) {
381+ Ok ( ( ) ) => { }
382+ Err ( err) =>
383+ fail_unless_failing ! ( "Error dropping connection: {}" , err)
384+ }
385+ }
371386 }
372387}
373388
@@ -409,6 +424,7 @@ impl InnerPostgresConnection {
409424 cancel_data : PostgresCancelData { process_id : 0 , secret_key : 0 } ,
410425 unknown_types : HashMap :: new ( ) ,
411426 desynchronized : false ,
427+ finished : false ,
412428 } ;
413429
414430 args. push ( ( ~"client_encoding", ~"UTF8 ") ) ;
@@ -598,10 +614,15 @@ impl InnerPostgresConnection {
598614 name : stmt_name,
599615 param_types : param_types,
600616 result_desc : result_desc,
601- next_portal_id : Cell :: new ( 0 )
617+ next_portal_id : Cell :: new ( 0 ) ,
618+ finished : Cell :: new ( false ) ,
602619 } )
603620 }
604621
622+ fn is_desynchronized ( & self ) -> bool {
623+ self . desynchronized
624+ }
625+
605626 fn get_type_name ( & mut self , oid : Oid ) -> Result < ~str , PostgresError > {
606627 match self . unknown_types . find ( & oid) {
607628 Some ( name) => return Ok ( name. clone ( ) ) ,
@@ -623,6 +644,7 @@ impl InnerPostgresConnection {
623644
624645 fn quick_query ( & mut self , query : & str )
625646 -> Result < ~[ ~[ Option < ~str > ] ] , PostgresError > {
647+ check_desync ! ( self ) ;
626648 if_ok_pg ! ( self . write_messages( [ Query { query: query } ] ) ) ;
627649
628650 let mut result = ~[ ] ;
@@ -640,6 +662,11 @@ impl InnerPostgresConnection {
640662 }
641663 Ok ( result)
642664 }
665+
666+ fn finish_inner ( & mut self ) -> Result < ( ) , PostgresError > {
667+ check_desync ! ( self ) ;
668+ Ok ( if_ok_pg ! ( self . write_messages( [ Terminate ] ) ) )
669+ }
643670}
644671
645672/// A connection to a Postgres database.
@@ -736,7 +763,8 @@ impl PostgresConnection {
736763 Ok ( PostgresTransaction {
737764 conn : self ,
738765 commit : Cell :: new ( true ) ,
739- nested : false
766+ nested : false ,
767+ finished : false ,
740768 } )
741769 }
742770
@@ -790,10 +818,23 @@ impl PostgresConnection {
790818 /// If this has occurred, all further queries will immediately return an
791819 /// error.
792820 pub fn is_desynchronized ( & self ) -> bool {
793- self . conn . with ( |conn| conn. desynchronized )
821+ self . conn . with ( |conn| conn. is_desynchronized ( ) )
794822 }
795823
796- fn quick_query ( & self , query : & str ) -> Result < ~[ ~[ Option < ~str > ] ] , PostgresError > {
824+ /// Consumes the connection, closing it.
825+ ///
826+ /// Functionally equivalent to the `Drop` implementation for
827+ /// `PostgresConnection` except that it returns any error encountered to
828+ /// the caller.
829+ pub fn finish ( self ) -> Result < ( ) , PostgresError > {
830+ self . conn . with_mut ( |conn| {
831+ conn. finished = true ;
832+ conn. finish_inner ( )
833+ } )
834+ }
835+
836+ fn quick_query ( & self , query : & str )
837+ -> Result < ~[ ~[ Option < ~str > ] ] , PostgresError > {
797838 self . conn . with_mut ( |conn| conn. quick_query ( query) )
798839 }
799840
@@ -824,25 +865,39 @@ pub enum SslMode {
824865pub struct PostgresTransaction < ' conn > {
825866 priv conn : & ' conn PostgresConnection ,
826867 priv commit : Cell < bool > ,
827- priv nested : bool
868+ priv nested : bool ,
869+ priv finished : bool ,
828870}
829871
830872#[ unsafe_destructor]
831873impl < ' conn > Drop for PostgresTransaction < ' conn > {
832874 fn drop ( & mut self ) {
875+ if !self . finished {
876+ match self . finish_inner ( ) {
877+ Ok ( ( ) ) => { }
878+ Err ( err) =>
879+ fail_unless_failing ! ( "Error dropping transaction: {}" , err)
880+ }
881+ }
882+ }
883+ }
884+
885+ impl < ' conn > PostgresTransaction < ' conn > {
886+ fn finish_inner ( & mut self ) -> Result < ( ) , PostgresError > {
833887 if task:: failing ( ) || !self . commit . get ( ) {
834888 if self . nested {
835- self . conn . quick_query ( "ROLLBACK TO sp" ) ;
889+ if_ok ! ( self . conn. quick_query( "ROLLBACK TO sp" ) ) ;
836890 } else {
837- self . conn . quick_query ( "ROLLBACK" ) ;
891+ if_ok ! ( self . conn. quick_query( "ROLLBACK" ) ) ;
838892 }
839893 } else {
840894 if self . nested {
841- self . conn . quick_query ( "RELEASE sp" ) ;
895+ if_ok ! ( self . conn. quick_query( "RELEASE sp" ) ) ;
842896 } else {
843- self . conn . quick_query ( "COMMIT" ) ;
897+ if_ok ! ( self . conn. quick_query( "COMMIT" ) ) ;
844898 }
845899 }
900+ Ok ( ( ) )
846901 }
847902}
848903
@@ -884,7 +939,8 @@ impl<'conn> PostgresTransaction<'conn> {
884939 Ok ( PostgresTransaction {
885940 conn : self . conn ,
886941 commit : Cell :: new ( true ) ,
887- nested : true
942+ nested : true ,
943+ finished : false ,
888944 } )
889945 }
890946
@@ -920,6 +976,15 @@ impl<'conn> PostgresTransaction<'conn> {
920976 pub fn set_rollback ( & self ) {
921977 self . commit . set ( false ) ;
922978 }
979+
980+ /// Consumes the transaction, commiting or rolling it back as appropriate.
981+ ///
982+ /// Functionally equivalent to the `Drop` implementation of
983+ /// `PostgresTransaction` except that it returns any error to the caller.
984+ pub fn finish ( mut self ) -> Result < ( ) , PostgresError > {
985+ self . finished = true ;
986+ self . finish_inner ( )
987+ }
923988}
924989
925990/// A trait containing methods that can be called on a prepared statement.
@@ -974,6 +1039,12 @@ pub trait PostgresStatement {
9741039 Err ( err) => fail ! ( "Error executing query:\n {}" , err. to_str( ) )
9751040 }
9761041 }
1042+
1043+ /// Consumes the statement, clearing it from the Postgres session.
1044+ ///
1045+ /// Functionally identical to the `Drop` implementation of the
1046+ /// `PostgresStatement` except that it returns any error to the caller.
1047+ fn finish ( self ) -> Result < ( ) , PostgresError > ;
9771048}
9781049
9791050/// A statement prepared outside of a transaction.
@@ -982,29 +1053,42 @@ pub struct NormalPostgresStatement<'conn> {
9821053 priv name : ~str ,
9831054 priv param_types : ~[ PostgresType ] ,
9841055 priv result_desc : ~[ ResultDescription ] ,
985- priv next_portal_id : Cell < uint >
1056+ priv next_portal_id : Cell < uint > ,
1057+ priv finished : Cell < bool > ,
9861058}
9871059
9881060#[ unsafe_destructor]
9891061impl < ' conn > Drop for NormalPostgresStatement < ' conn > {
9901062 fn drop ( & mut self ) {
991- let _ = self . conn . write_messages ( [
1063+ if !self . finished . get ( ) {
1064+ match self . finish_inner ( ) {
1065+ Ok ( ( ) ) => { }
1066+ Err ( err) =>
1067+ fail_unless_failing ! ( "Error dropping statement: {}" , err)
1068+ }
1069+ }
1070+ }
1071+ }
1072+
1073+ impl < ' conn > NormalPostgresStatement < ' conn > {
1074+ fn finish_inner ( & mut self ) -> Result < ( ) , PostgresError > {
1075+ check_desync ! ( self . conn) ;
1076+ if_ok_pg ! ( self . conn. write_messages( [
9921077 Close {
9931078 variant: 'S' as u8 ,
9941079 name: self . name. as_slice( )
9951080 } ,
996- Sync ] ) ;
1081+ Sync ] ) ) ;
9971082 loop {
998- match self . conn . read_message ( ) {
999- Ok ( ReadyForQuery { .. } ) => break ,
1000- Err ( _ ) => break ,
1083+ // TODO forward db errors
1084+ match if_ok_pg ! ( self . conn . read_message ( ) ) {
1085+ ReadyForQuery { .. } => break ,
10011086 _ => { }
10021087 }
10031088 }
1089+ Ok ( ( ) )
10041090 }
1005- }
10061091
1007- impl < ' conn > NormalPostgresStatement < ' conn > {
10081092 fn execute ( & self , portal_name : & str , row_limit : uint , params : & [ & ToSql ] )
10091093 -> Result < ( ) , PostgresError > {
10101094 let mut formats = ~[ ] ;
@@ -1059,9 +1143,10 @@ impl<'conn> NormalPostgresStatement<'conn> {
10591143 name : portal_name,
10601144 data : RingBuf :: new ( ) ,
10611145 row_limit : row_limit,
1062- more_rows : true
1146+ more_rows : true ,
1147+ finished : false ,
10631148 } ;
1064- result. read_rows ( ) ;
1149+ if_ok ! ( result. read_rows( ) )
10651150
10661151 Ok ( result)
10671152 }
@@ -1114,6 +1199,11 @@ impl<'conn> PostgresStatement for NormalPostgresStatement<'conn> {
11141199 check_desync ! ( self . conn) ;
11151200 self . try_lazy_query ( 0 , params)
11161201 }
1202+
1203+ fn finish ( mut self ) -> Result < ( ) , PostgresError > {
1204+ self . finished . set ( true ) ;
1205+ self . finish_inner ( )
1206+ }
11171207}
11181208
11191209/// Information about a column of the result of a query.
@@ -1161,6 +1251,10 @@ impl<'conn> PostgresStatement for TransactionalPostgresStatement<'conn> {
11611251 -> Result < PostgresResult < ' a > , PostgresError > {
11621252 self . stmt . try_query ( params)
11631253 }
1254+
1255+ fn finish ( self ) -> Result < ( ) , PostgresError > {
1256+ self . stmt . finish ( )
1257+ }
11641258}
11651259
11661260impl < ' conn > TransactionalPostgresStatement < ' conn > {
@@ -1201,28 +1295,42 @@ pub struct PostgresResult<'stmt> {
12011295 priv name : ~str ,
12021296 priv data : RingBuf < ~[ Option < ~[ u8 ] > ] > ,
12031297 priv row_limit : uint ,
1204- priv more_rows : bool
1298+ priv more_rows : bool ,
1299+ priv finished : bool ,
12051300}
12061301
12071302#[ unsafe_destructor]
12081303impl < ' stmt > Drop for PostgresResult < ' stmt > {
12091304 fn drop ( & mut self ) {
1210- let _ = self . stmt . conn . write_messages ( [
1305+ if !self . finished {
1306+ match self . finish_inner ( ) {
1307+ Ok ( ( ) ) => { }
1308+ Err ( err) =>
1309+ fail_unless_failing ! ( "Error dropping result: {}" , err)
1310+ }
1311+ }
1312+ }
1313+ }
1314+
1315+ impl < ' stmt > PostgresResult < ' stmt > {
1316+ fn finish_inner ( & mut self ) -> Result < ( ) , PostgresError > {
1317+ check_desync ! ( self . stmt. conn) ;
1318+ if_ok_pg ! ( self . stmt. conn. write_messages( [
12111319 Close {
12121320 variant: 'P' as u8 ,
12131321 name: self . name. as_slice( )
12141322 } ,
1215- Sync ] ) ;
1323+ Sync ] ) ) ;
12161324 loop {
1217- match self . stmt . conn . read_message ( ) {
1218- Ok ( ReadyForQuery { .. } ) => break ,
1325+ // TODO forward PG errors
1326+ match if_ok_pg ! ( self . stmt. conn. read_message( ) ) {
1327+ ReadyForQuery { .. } => break ,
12191328 _ => { }
12201329 }
12211330 }
1331+ Ok ( ( ) )
12221332 }
1223- }
12241333
1225- impl < ' stmt > PostgresResult < ' stmt > {
12261334 fn read_rows ( & mut self ) -> Result < ( ) , PostgresError > {
12271335 loop {
12281336 match if_ok_pg ! ( self . stmt. conn. read_message( ) ) {
@@ -1253,18 +1361,40 @@ impl<'stmt> PostgresResult<'stmt> {
12531361 }
12541362}
12551363
1256- impl < ' stmt > Iterator < PostgresRow < ' stmt > > for PostgresResult < ' stmt > {
1257- fn next ( & mut self ) -> Option < PostgresRow < ' stmt > > {
1364+ impl < ' stmt > PostgresResult < ' stmt > {
1365+ /// Consumes the `PostgresResult`, cleaning up associated state.
1366+ ///
1367+ /// Functionally identical to the `Drop` implementation on
1368+ /// `PostgresResult` except that it returns any error to the caller.
1369+ pub fn finish ( mut self ) -> Result < ( ) , PostgresError > {
1370+ self . finished = true ;
1371+ self . finish_inner ( )
1372+ }
1373+
1374+ /// Like `PostgresResult::next` except that it returns any errors to the
1375+ /// caller instead of failing.
1376+ pub fn try_next ( & mut self )
1377+ -> Result < Option < PostgresRow < ' stmt > > , PostgresError > {
12581378 if self . data . is_empty ( ) && self . more_rows {
1259- self . execute ( ) ;
1379+ if_ok ! ( self . execute( ) ) ;
12601380 }
12611381
1262- self . data . pop_front ( ) . map ( |row| {
1382+ let row = self . data . pop_front ( ) . map ( |row| {
12631383 PostgresRow {
12641384 stmt : self . stmt ,
12651385 data : row
12661386 }
1267- } )
1387+ } ) ;
1388+ Ok ( row)
1389+ }
1390+ }
1391+
1392+ impl < ' stmt > Iterator < PostgresRow < ' stmt > > for PostgresResult < ' stmt > {
1393+ fn next ( & mut self ) -> Option < PostgresRow < ' stmt > > {
1394+ match self . try_next ( ) {
1395+ Ok ( ok) => ok,
1396+ Err ( err) => fail ! ( "Error fetching rows: {}" , err)
1397+ }
12681398 }
12691399
12701400 fn size_hint ( & self ) -> ( uint , Option < uint > ) {
@@ -1344,3 +1474,4 @@ impl<'a> RowIndex for &'a str {
13441474 fail ! ( "there is no column with name {}" , * self ) ;
13451475 }
13461476}
1477+
0 commit comments