Aditi updates

Simon Taylor stayl at
Fri Dec 4 14:13:57 AEDT 1998


I'm looking at adding Aditi updates to the compiler, and there's
a few things I want to run past the group.

'Database transactions in a purely declarative logic programming language'
(tech report 96/45) gives the interface for update predicates.

For example, for a base relation with declaration:
:- pred edge(aditi:state::ui, int::out, int::out) is nondet.
:- pragma base_relation(edge/3).

the compiler automatically defines:

:- pred edge_insert(int::in, int::in,
		aditi__state::di, aditi__state::uo) is det.

:- pred edge_delete(int::in, int::in,
		aditi__state::di, aditi__state::uo) is det.

:- pred edge_bulk_insert(pred(int::in, int::in, aditi__state::ui) is nondet, 
		aditi__state::di, aditi__state::uo) is det.
:- pred edge_bulk_delete(pred(int::in, int::in, aditi__state::ui) is nondet, 
		aditi__state::di, aditi__state::uo) is det.

Assuming a primary key on attribute 1 (the first integer attribute),
we also get:

% Delete the tuple with the given key.
:- pred edge_delete_1(int::in, aditi__state::di, aditi__state::uo) is det.

% Update the non-key value of each tuple.
% A B-tree index could be used to select out the tuples to be modified
% if only certain ranges of tuples match.
:- pred edge_modify_1(pred(int::in, int::in, int::out) is det/semidet,
		aditi__state::di, aditi__state::uo) is det.

There are a few issues:

1) Handling of the input query for the bulk insert and delete operations.

This must be executed bottom-up on the Aditi side of the connection.
The closure must be compiled to Aditi-RL bytecode.

The way I propose to handle this is to add a new higher-order predicate type
`aditi_query/N'. The differences from normal `pred/N' types are:
- the representation of an `aditi_query' closure is similar to a pred_const,
except that instead of a code address the name of the database procedure
to call is passed as a string.
- this also requires a way to add Aditi markers to lambda expressions. For now,
it might be enough to require that the predicate which has its address taken
must have a `:- pragma aditi(...)' declaration, and not allow general goals
in this type of lambda expression.

2) Specification of primary keys for deletion/modification.

Some of the Aditi documentation suggests doing this by adding
semidet/det modes for base relations.
For example 
:- pred edge(aditi__state::ui, int::in, int::out) is semidet.

The deletion/modification operations would specify which key to use by
listing the input attributes after the predicate name, separated by
underscores as for edge_delete_1 above. This could cause problems with
name clashes.

3) Specification of modification closures.

A modification closure takes the primary key and non-primary key attributes
and returns new non-primary key attributes. The closure is executed top-down. 

The closure is split into two parts for execution by Aditi.
The first is used if the base relation to modify is indexed. It selects
out those tuples for which the modification predicate could succeed.
For example, if the modification predicate for edge was the lambda expression
below and the edge/3 is indexed on attribute 1, only tuples with first
attributes between 1 and 4 would have the modification applied.

		(pred(A::in, B::in, C::out) is semidet :-
			A > 1,
			A < 4,
			C = B + 1

If there is not an index on the primary key attributes being used for
modification, the modification predicate would need to be applied to the entire

The second part of the closure works out the updated values.

There is a similar problem here as for the bulk_update query closure --
the closure must be passed across the Mercury-Aditi interface.
For this, I propose adding another higher-order predicate type
`aditi_update/N'. The representation would contain the owner and module name
and expression numbers of both the index and update parts of the update
closure stored in the RL code in the database. Only predicates with a
`:- pragma aditi_update(...)' declaration may have their address taken
in this way.

(An aside -- Aditi-RL code is stored in the database as a set of modules.
Each module contains a set of `expressions' used to evaluate join conditions
and other similar things top-down. The owner of the module, the module name
and the index in the list of expressions for that module uniquely identify
the expression).


Have I overlooked anything? Can anyone think of a cleaner way
to do some of this?


More information about the developers mailing list