[m-rev.] for review: changes to odbc.m

David Overton dmo at cs.mu.OZ.AU
Mon May 13 16:42:42 AEST 2002


On Thu, May 09, 2002 at 03:40:21PM +1000, Simon Taylor wrote:
> On 09-May-2002, David Overton <dmo at cs.mu.OZ.AU> wrote:
> > These changes are for Simon to review, please.
> > 
> > The motivation behind them is that there are some people in the
> > Biochemistry department here at Monash who want to be able to perform IO
> > in the middle of transactions.  E.g. they have queries which return many
> > solutions which should be output to a file as they are returned.  The
> > number of solutions is typically too big to store them all in a list and
> > then do the output after the transaction finishes.
> > 
> > Is this a reasonable approach for such situations, or is there a better
> > way?
> 
> That approach is fine.
>  
> > Index: odbc.m
> > ===================================================================
> > RCS file: /home/mercury1/repository/mercury/extras/odbc/odbc.m,v
> > retrieving revision 1.15
> > diff -u -r1.15 odbc.m
> > --- odbc.m	19 Apr 2002 02:51:57 -0000	1.15
> > +++ odbc.m	9 May 2002 02:18:47 -0000
> > @@ -76,6 +76,14 @@
> >  :- type odbc__transaction(T)	== 	pred(T, odbc__state, odbc__state).
> >  :- mode odbc__transaction	::	pred(out, di, uo) is det.
> >  
> > +		% A closure that allows IO operations.
> > +		% See the WARNING at the predicate odbc__unsafe_io_transaction,
> > +		% below.
> > +:- type odbc__unsafe_io_transaction(T)	==
> > +		pred(T, io__state, io__state, odbc__state, odbc__state).
> > +:- mode odbc__unsafe_io_transaction ==
> > +		(pred(out, di, uo, di, uo) is det).
> > +
> >  :- type odbc__state.
> >  
> >  	% odbc__transaction(Source, UserName, Password, Transaction, Result).
> > @@ -96,6 +104,15 @@
> >  		odbc__transaction(T), odbc__result(T), io__state, io__state).
> >  :- mode odbc__transaction(in, in, in, odbc__transaction, out, di, uo) is det.
> >  
> > +	% Same as odbc__transaction except allow the transaction to operate on
> > +	% the io__state.
> > +	% WARNING: This is unsafe.
> > +:- pred odbc__unsafe_io_transaction(odbc__data_source, odbc__user_name,
> > +		odbc__password, odbc__unsafe_io_transaction(T),
> > +		odbc__result(T), io__state, io__state).
> > +:- mode odbc__unsafe_io_transaction(in, in, in, odbc__unsafe_io_transaction,
> > +		out, di, uo) is det.
> 
> The warning here is a bit weak.
> 
> Maybe something like:
> 	% odbc__unsafe_io_transaction is useful when a transaction
> 	% returns more results than can be stored in memory.
> 	%
> 	% WARNING: transactions run by odbc__unsafe_io_transaction
> 	% may violate the atomicity and isolation properties expected
> 	% of ACID transactions.  Database updates will be rolled back
> 	% if the transaction is aborted, but I/O actions will not be.

Done.

> 
> Now that transactions can have access to an io__state, you need
> to check that you're not already inside a transaction before
> starting a new one (and return an error if you are).

I've added a check for this.  I'm not all that familiar with ODBC so if
there is a better way to do this please let me know.



--- odbc.m.old	Mon May 13 16:38:34 2002
+++ odbc.m	Mon May 13 16:39:54 2002
@@ -104,9 +104,13 @@
 		odbc__transaction(T), odbc__result(T), io__state, io__state).
 :- mode odbc__transaction(in, in, in, odbc__transaction, out, di, uo) is det.
 
-	% Same as odbc__transaction except allow the transaction to operate on
-	% the io__state.
-	% WARNING: This is unsafe.
+	% odbc__unsafe_io_transaction is useful when a transaction
+	% returns more results than can be stored in memory.
+	%
+	% WARNING: transactions run by odbc__unsafe_io_transaction
+	% may violate the atomicity and isolation properties expected
+	% of ACID transactions.  Database updates will be rolled back
+	% if the transaction is aborted, but I/O actions will not be.
 :- pred odbc__unsafe_io_transaction(odbc__data_source, odbc__user_name,
 		odbc__password, odbc__unsafe_io_transaction(T),
 		odbc__result(T), io__state, io__state).
@@ -305,7 +309,7 @@
 %-----------------------------------------------------------------------------%
 :- implementation.
 
-:- import_module assoc_list, exception, int, require, std_util, string.
+:- import_module assoc_list, exception, int, require, std_util, string, bool.
 
 %-----------------------------------------------------------------------------%
 
@@ -459,6 +463,11 @@
 			Word *Msgs, Word IO0, Word *IO);
 static MR_bool odbc_check(SQLHENV, SQLHDBC, SQLHSTMT, SQLRETURN);
 
+	/*
+	** odbc_in_transaction = MR_TRUE iff we are currently in a transaction.
+	*/
+static MR_bool odbc_in_transaction = MR_FALSE;
+
 ").
 
 %-----------------------------------------------------------------------------%
@@ -650,12 +659,14 @@
 		Exception, IO0, IO, State0, State) :-
 	try_io((pred(TryResult::out, IO1::di, IO2::uo) is det :-
 		unsafe_promise_unique(State0, State1),
-		Closure(Result, IO1, IO2, State1, ResultState),
+		check_not_in_transaction(State1, State2),
+		Closure(Result, IO1, IO2, State2, State3),
+		unset_in_transaction(State3, ResultState),
 		TryResult = Result - ResultState
 	), ExceptResult, IO0, IO),
 	(
-		ExceptResult = succeeded(Results - State2),
-		unsafe_promise_unique(State2, State),
+		ExceptResult = succeeded(Results - State4),
+		unsafe_promise_unique(State4, State),
 		make_dummy_value(Exception),
 		GotException = 0
 	;
@@ -671,6 +682,58 @@
 :- pragma c_code(make_dummy_value(T::out),
 		[will_not_call_mercury, thread_safe],
 		"T = 0;").
+
+:- pred check_not_in_transaction(odbc__state::di, odbc__state::uo) is det.
+
+check_not_in_transaction -->
+	get_in_transaction(InTransaction),
+	( { InTransaction = yes } ->
+		odbc__rollback("[Mercury][odbc.m]Detected nested transaction.")
+	;
+		set_in_transaction
+	).
+
+:- pred get_in_transaction(bool::out, odbc__state::di, odbc__state::uo) is det.
+
+get_in_transaction(InTransaction) -->
+	get_in_transaction_2(InTransaction0),
+	{ InTransaction0 = 0 ->
+		InTransaction = no
+	;
+		InTransaction = yes
+	}.
+
+:- pred get_in_transaction_2(int::out, odbc__state::di, odbc__state::uo) is det.
+
+:- pragma foreign_proc("C",
+		get_in_transaction_2(InTransaction::out, State0::di, State::uo),
+		[will_not_call_mercury, promise_pure],
+"
+	if (odbc_in_transaction == MR_FALSE) {
+		InTransaction = 0;
+	} else {
+		InTransaction = 1;
+	}
+	State = State0;
+").
+
+:- pred set_in_transaction(odbc__state::di, odbc__state::uo) is det.
+
+:- pragma foreign_proc("C", set_in_transaction(State0::di, State::uo),
+		[will_not_call_mercury, promise_pure],
+"
+	odbc_in_transaction = MR_TRUE;
+	State = State0;
+").
+
+:- pred unset_in_transaction(odbc__state::di, odbc__state::uo) is det.
+
+:- pragma foreign_proc("C", unset_in_transaction(State0::di, State::uo),
+		[will_not_call_mercury, promise_pure],
+"
+	odbc_in_transaction = MR_FALSE;
+	State = State0;
+").
 
 %-----------------------------------------------------------------------------%
 

-- 
David Overton      Computer Science and Software Engineering
PhD Student        The University of Melbourne   +61 3 8344 9159
Research Fellow    Monash University (Clayton)   +61 3 9905 5779
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list