[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