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

David Overton dmo at cs.mu.OZ.AU
Thu May 9 14:00:20 AEST 2002


Hi,

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?


David

Estimated hours taken: 0.5
Branches: main

extras/odbc/odbc.m:
	Add predicate `odbc__aggregate2' which is like `odbc__aggregate' but has
	two accumulators.
	Add `odbc__unsafe_io_transaction' whic is like `odbc__transaction' but
	allows IO inside the transaction.

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.
+
 	% Abort the current transaction, returning the given error message.
 :- pred odbc__rollback(string, odbc__state, odbc__state).
 :- mode odbc__rollback(in, di, uo) is erroneous.
@@ -136,6 +153,15 @@
 :- mode odbc__aggregate(in, pred(in, in, out) is det, in, out, di, uo) is det.
 :- mode odbc__aggregate(in, pred(in, di, uo) is det, di, uo, di, uo) is det.
 
+:- pred odbc__aggregate2(string, pred(odbc__row, T, T, U, U), T, T, U, U,
+		odbc__state, odbc__state).
+:- mode odbc__aggregate2(in, pred(in, in, out, in, out) is det,
+		in, out, in, out, di, uo) is det.
+:- mode odbc__aggregate2(in, pred(in, in, out, di, uo) is det,
+		in, out, di, uo, di, uo) is det.
+:- mode odbc__aggregate2(in, pred(in, di, uo, di, uo) is det,
+		di, uo, di, uo, di, uo) is det.
+
 %-----------------------------------------------------------------------------%
 
 	% Predicates and types to get information about database tables.
@@ -438,7 +464,12 @@
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
-odbc__transaction(Source, User, Password, Closure, Result) -->
+odbc__transaction(Source, User, Password, Closure0, Result) -->
+	{ Closure = (pred(Res::out, IO::di, IO::uo, di, uo) is det
+			--> Closure0(Res) ) },
+	odbc__unsafe_io_transaction(Source, User, Password, Closure, Result).
+
+odbc__unsafe_io_transaction(Source, User, Password, Closure, Result) -->
 	% We could have separate open and close connection predicates in the 
 	% interface, but that would just be more effort for the programmer 
 	% for a very minor efficiency gain. The connection time will be 
@@ -480,14 +511,14 @@
 	).
 
 :- pred odbc__transaction_2(odbc__connection,
-		pred(T, odbc__state, odbc__state), T, 
+		odbc__unsafe_io_transaction(T), T, 
 		int, univ, int, list(odbc__message), io__state, io__state).  
-:- mode odbc__transaction_2(in, pred(out, di, uo) is det, 
+:- mode odbc__transaction_2(in, odbc__unsafe_io_transaction, 
 		out, out, out, out, out, di, uo) is det.
 
 :- pragma c_code(
 		odbc__transaction_2(Connection::in, 
-			Closure::pred(out, di, uo) is det,
+			Closure::odbc__unsafe_io_transaction,
 			Results::out, GotMercuryException::out, Exception::out,
 			Status::out, Msgs::out, IO0::di, IO::uo),
 		may_call_mercury,
@@ -606,22 +637,22 @@
 %-----------------------------------------------------------------------------%
 
 	% Call the transaction closure.
-:- pred odbc__do_transaction(odbc__transaction(T), int, T, univ,
-		odbc__state, odbc__state).
-:- mode odbc__do_transaction(odbc__transaction,
-		out, out, out, di, uo) is cc_multi.
+:- pred odbc__do_transaction(odbc__unsafe_io_transaction(T), int, T, univ,
+		io__state, io__state, odbc__state, odbc__state).
+:- mode odbc__do_transaction(odbc__unsafe_io_transaction,
+		out, out, out, di, uo, di, uo) is cc_multi.
 
-:- pragma export(odbc__do_transaction(odbc__transaction,
-		out, out, out, di, uo), 
+:- pragma export(odbc__do_transaction(odbc__unsafe_io_transaction,
+		out, out, out, di, uo, di, uo), 
 		"MODBC_odbc__do_transaction").
 
 odbc__do_transaction(Closure, GotException, Results,
-		Exception, State0, State) :-
-	try((pred(TryResult::out) is det :-
+		Exception, IO0, IO, State0, State) :-
+	try_io((pred(TryResult::out, IO1::di, IO2::uo) is det :-
 		unsafe_promise_unique(State0, State1),
-		Closure(Result, State1, ResultState),
+		Closure(Result, IO1, IO2, State1, ResultState),
 		TryResult = Result - ResultState
-	), ExceptResult),
+	), ExceptResult, IO0, IO),
 	(
 		ExceptResult = succeeded(Results - State2),
 		unsafe_promise_unique(State2, State),
@@ -816,72 +847,104 @@
 odbc__solutions(SQLString, Results) -->
 	% XXX optimize this when we have better support 
 	% for last call optimization.
-	odbc__do_aggregate(odbc__execute_statement(SQLString), 
-		cons, [], Results0),
+	odbc__aggregate(SQLString, cons, [], Results0),
 	{ list__reverse(Results0, Results) }.
 
 odbc__aggregate(SQLString, Accumulator, Acc0, Acc) -->
-	odbc__do_aggregate(odbc__execute_statement(SQLString), 
-		Accumulator, Acc0, Acc).
+	odbc__aggregate2(SQLString, add_accumulator_args(Accumulator),
+		Acc0, Acc, unit, _).
+
+odbc__aggregate2(SQLString, Accumulator, A0, A, B0, B) -->
+	odbc__do_aggregate(odbc__execute_statement(SQLString),
+		Accumulator, A0, A, B0, B).
 
 :- pred cons(T, list(T), list(T)).
 :- mode cons(in, in, out) is det.
 
 cons(H, T, [H|T]).
 
+:- func add_accumulator_args(pred(odbc__row, T, T)) =
+		pred(odbc__row, T, T, unit, unit).
+:- mode add_accumulator_args(in(pred(in, in, out) is det)) =
+		out(pred(in, in, out, di, uo) is det) is det.
+:- mode add_accumulator_args(in(pred(in, di, uo) is det)) =
+		out(pred(in, di, uo, di, uo) is det) is det.
+
+:- pragma promise_pure(add_accumulator_args/1).
+
+% Use mode-specific clauses since we need to explicitly give the mode for the
+% pred expression.
+
+add_accumulator_args(P0::in(pred(in, in, out) is det)) =
+		(P::out(pred(in, in, out, di, uo) is det)) :-
+	P = (pred(R::in, A0::in, A::out, di, uo) is det -->
+		{ P0(R, A0, A) } ).
+add_accumulator_args(P0::in(pred(in, di, uo) is det)) =
+		(P::out(pred(in, di, uo, di, uo) is det)) :-
+	P = (pred(R::in, A0::di, A::uo, di, uo) is det -->
+		{ P0(R, A0, A) } ).
+
 %-----------------------------------------------------------------------------%
 
 :- pred odbc__do_aggregate(pred(odbc__statement, odbc__statement, 
-			odbc__state, odbc__state), pred(odbc__row, T, T),
-			T, T, odbc__state, odbc__state).
+			odbc__state, odbc__state), pred(odbc__row, T, T, U, U),
+			T, T, U, U, odbc__state, odbc__state).
+:- mode odbc__do_aggregate(pred(di, uo, di, uo) is det, 
+			pred(in, in, out, in, out) is det,
+			in, out, in, out, di, uo) is det.
 :- mode odbc__do_aggregate(pred(di, uo, di, uo) is det, 
-			pred(in, in, out) is det,
-			in, out, di, uo) is det.
+			pred(in, in, out, di, uo) is det,
+			in, out, di, uo, di, uo) is det.
 :- mode odbc__do_aggregate(pred(di, uo, di, uo) is det, 
-			pred(in, di, uo) is det,
-			di, uo, di, uo) is det.
+			pred(in, di, uo, di, uo) is det,
+			di, uo, di, uo, di, uo) is det.
 
-odbc__do_aggregate(Execute, Accumulate, Result0, Result) -->
+odbc__do_aggregate(Execute, Accumulate, A0, A, B0, B) -->
 	odbc__alloc_statement(Statement0),
 	call(Execute, Statement0, Statement1),
 	odbc__bind_columns(Statement1, Statement2),
-	odbc__get_rows(Accumulate, Result0, Result, Statement2, Statement),
+	odbc__get_rows(Accumulate, A0, A, B0, B, Statement2, Statement),
 	odbc__cleanup_statement_check_error(Statement).
 
 %-----------------------------------------------------------------------------%
 
 	% Get the set of result rows from the statement.
-:- pred odbc__get_rows(pred(odbc__row, T, T), T, T, 
+:- pred odbc__get_rows(pred(odbc__row, T, T, U, U), T, T, U, U,
 		odbc__statement, odbc__statement, odbc__state, odbc__state).
-:- mode odbc__get_rows(pred(in, in, out) is det, in, out, 
+:- mode odbc__get_rows(pred(in, in, out, in, out) is det, in, out, in, out,
+		di, uo, di, uo) is det.
+:- mode odbc__get_rows(pred(in, in, out, di, uo) is det, in, out, di, uo,
+		di, uo, di, uo) is det.
+:- mode odbc__get_rows(pred(in, di, uo, di, uo) is det, di, uo, di, uo,
 		di, uo, di, uo) is det.
-:- mode odbc__get_rows(pred(in, di, uo) is det, di, uo, di, uo, di, uo) is det.
 
-odbc__get_rows(Accumulate, Result0, Result, Statement0, Statement) -->
+odbc__get_rows(Accumulate, A0, A, B0, B, Statement0, Statement) -->
 	odbc__get_number_of_columns(NumColumns, Statement0, Statement1),
-	odbc__get_rows_2(NumColumns, Accumulate, Result0, Result, 
+	odbc__get_rows_2(NumColumns, Accumulate, A0, A, B0, B, 
 		Statement1, Statement).
 
-:- pred odbc__get_rows_2(int, pred(odbc__row, T, T), T, T,
+:- pred odbc__get_rows_2(int, pred(odbc__row, T, T, U, U), T, T, U, U,
 		odbc__statement, odbc__statement, odbc__state, odbc__state).
-:- mode odbc__get_rows_2(in, pred(in, in, out) is det, in, out,
+:- mode odbc__get_rows_2(in, pred(in, in, out, in, out) is det, in, out,
+		in, out, di, uo, di, uo) is det.
+:- mode odbc__get_rows_2(in, pred(in, in, out, di, uo) is det, in, out, di, uo,
 		di, uo, di, uo) is det.
-:- mode odbc__get_rows_2(in, pred(in, di, uo) is det, di, uo,
+:- mode odbc__get_rows_2(in, pred(in, di, uo, di, uo) is det, di, uo, di, uo,
 		di, uo, di, uo) is det.
 
-odbc__get_rows_2(NumColumns, Accumulate, Result0, Result,
+odbc__get_rows_2(NumColumns, Accumulate, A0, A, B0, B,
 		Statement0, Statement) -->
 	% Try to fetch a new row.
 	odbc__fetch(Statement0, Statement1, Status),
 	( { odbc__no_data(Status) } ->
-		{ Result = Result0 },	
+		{ A = A0, B = B0 },	
 		{ Statement = Statement1 }
 	;
 		odbc__get_attributes(1, NumColumns, Row, 
 			Statement1, Statement2),
-		{ Accumulate(Row, Result0, Result1) },
+		{ Accumulate(Row, A0, A1, B0, B1) },
 		odbc__get_rows_2(NumColumns, Accumulate, 
-			Result1, Result, Statement2, Statement)
+			A1, A, B1, B, Statement2, Statement)
 	).
 
 %-----------------------------------------------------------------------------%
@@ -2085,7 +2148,7 @@
 	{ odbc__convert_pattern_argument(TableName, TableStr, TableStatus) },
 	odbc__do_aggregate(odbc__sql_tables(QualifierStr, QualifierStatus,
 		OwnerStr, OwnerStatus, TableStr, TableStatus), 
-		cons, [], Results0),
+		add_accumulator_args(cons), [], Results0, unit, _),
 	{ list__reverse(Results0, Results) },
 	( { list__map(odbc__convert_table_desc, Results, Tables0) } ->
 		{ Tables = Tables0 }
-- 
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