Go to the first, previous, next, last section, table of contents.


SQL persistent database interface

Author(s): I. Caballero, D. Cabeza, J.M. Gómez, and M. Hermenegildo, clip@dia.fi.upm.es, http://www.clip.dia.fi.upm.es/, The CLIP Group, Facultad de Informática, Universidad Politécnica de Madrid.

Version: 1.5#118 (2000/4/19, 18:13:43 CEST)

Version of last change: 1.5#105 (2000/4/3, 14:21:58 CEST)

The purpose of this library is to implement an instance of the generic concept of persistent predicates, where external relational databases are used for storage (see the documentation of the persdb library and [CHGT98,Par97] for details). To this end, this library exports SQL persistent versions of the assertz_fact/1, retract_fact/1 and retractall_fact/1 builtin predicates. Persistent predicates also allow concurrent updates from several programs, since each update is atomic.

The notion of persistence provides a very natural and transparent way to access database relations from a Prolog program. Stub definitions are provided for such predicates which access the database when the predicate is called (using the db_client library). A Prolog to SQL translator is used to generate the required SQL code dynamically (see library pl2sql).

This library also provides facilities for reflecting more complex views of the database relations as Prolog predicates. Such views can be constructed as conjunctions, disjunctions, projections, etc. of database relations. Also, SQL-like aggregation operations are supported.

Implementation of the Database Interface

The architecture of the low-level implementation of the database interface was defined with two goals in mind:

In order to allow the flexibility mentioned above, a client-sever architecture was chosen. The following figure depicts the overall architecture of the system:

Image:autofigarchitecture.jpg

At the server side, a "database mediator server" connects on one side to the databases using the ODBC interface (this interface is available for the databases of the RadioWeb project, as well as for the majority of the databases running in the Win95/NT operating systems) and on the other it is connected to the network by TCP/IP using a fixed socket number / service (currently fixed to socket number 2020).

The mediator server must run on the Windows (NT/95) operating system, on the machine where the databases are also running. The (Prolog) clients which connect to it can be run locally at the server machine. In addition, remote clients running on different machines can also connect to the mediator server by connecting to its socket number (service). Such clients can run on either Unix or Windows systems.

After the connection is established a client can send commands to the mediator server which will pass them to the corresponding database server, and then the data will traverse in the opposite direction. These messages include logging on and off from the database, sending SQL queries, and receiving the responses.

The low level implementation of the current library is accomplished by providing several abstraction levels over the socket interface library of the Prolog engine. These layers of abstraction implement the persistent predicate view, build the appropriate commands for the database using a translator of Prolog goals to SQL commands, issue such commands using the mediator send/receive procedures, parse the responses, and present such responses to the Prolog engine via backtracking.

Example(s)

:- include(library('persdb_sql/persdb_sql')).
:- use_module(library(format)).

%% ------------------------------------------------- %%
%% First sample database : 'SA 6.0 Sample' %%
%% ------------------------------------------------- %%

%% Declare product/4 a persistent predicate, storage in 'radiowebdb':
:- sql_persistent(product( int,    int, string, string ),
              product( quantity,   id,      name,   size   ),
              sampledb).
sql_persistent_location(sampledb, %% The 'sampledb' descriptor:
         db('ASA 6.0 Sample','dba', 'sql','r2d5.dia.fi.upm.es':2020)).

main0 :-
%% Prints the contents of the relation 'product/4' by backtracking over it:
         format("Printing table:\n",[]),
         product(Quantity, Id, Name, Size), 
         format("Tuple: ~w \t ~w \t ~w \t ~w \n",
                [Quantity, Id, Name, Size]),
         fail.
main0 :-
         format("Done.\n",[]).

%% Generalizing table printing:
%% Prints the contents of Pred by backtracking over it
print_predicate(Pred):- 
        format("Printing relation:\n",[]),
        Pred, %% predicate call
        Pred=..[_|Args],
        format("\t Tuple: ~w \n",[Args]),
        fail.
print_predicate(_Pred):-
        format("Done.~n",[]).

main1 :- %% similar to main0:
%% Prints the contents of the relation 'product/4' by backtracking over it:
        print_predicate(product(_Quantity,_Id,_Name,_Size)).

main2 :- %% Issues a complex query inside a db_findall:
         dbfindall(sampledb,
                   foo(Quantity, Id, Name, Size, Bar),
                   ( product(Quantity, Id, Name, Size),
                     I^N^S^(Bar is avg(Q,product(Q, I, N, S)))
                   ),
                   Results),
         format("Results = ~w~n",[Results]).
main21 :- %% Using db_call
         dbcall(sampledb,
             (product(Quantity, Id, Name, Size),
              product(Quantity, Id1, _Name1, _Size1),Id1>Id)),
%%       product(Quantity, Id, Name, Size),
%%          product(Quantity, Id1, Name1, Size1),
%%          Id1>Id,
         format("Tuple: ~w \t ~w \t ~w \t ~w \n",
                [Quantity, Id, Name, Size]).

main22 :-  % get the set of tables from a database
        sql_get_tables(sampledb,TablesList),
        display(TablesList).

main23 :- % get table attributes and its types 
        sql_table_types(sampledb, 'Customer', AttList),
        display(AttList).
        
%% ------------------------------------------------- %%
%% Second sample database : 'Literature'             %%
%% ------------------------------------------------- %%

:- sql_persistent(authors(string,string,int),
               authors(firstName,lastName,id), %% 'id' is the primary key
               literature_db).
sql_persistent_location(literature_db,
        db('Literature','dba','sql','r2d5.dia.fi.upm.es':2020)).

main3:- %% Prints the contents of authors
         print_predicate(authors(_FirstName,_LastName,_Id)) .

main4:- %% assert a persistent fact
         dbassertz_fact(authors('Pedro','Calderon de la Barca',17)).

main6:- %% retract a persistent fact
         dbretract_fact(authors('Pedro','Calderon de la Barca',17)).

main9:- %% checking if a persistent fact is a current fact
        dbcurrent_fact(authors(_X,_Y,_Z)).

Usage and interface (persdbrtsql)

Documentation on exports (persdbrtsql)

PREDICATE: init_sql_persdb/0:

Usage:

PREDICATE: sql_persistent/3:

No further documentation available for this predicate.

PREDICATE: dbassertz_fact/1:

Usage: dbassertz_fact(+Fact)

PREDICATE: dbretract_fact/1:

Usage: dbretract_fact(+Fact)

PREDICATE: dbcurrent_fact/1:

Usage: dbcurrent_fact(+Fact)

PREDICATE: dbretractall_fact/1:

Usage: dbretractall_fact(+Fact)

PREDICATE: make_sql_persistent/3:

Meta-predicate with arguments: make_sql_persistent(addmodule,?,?).

Usage: make_sql_persistent(PrologPredTypes,TableAttributes,Keyword)

PREDICATE: dbfindall/4:

Usage: dbfindall(+DBId,+Pattern,+ComplexGoal,-(Results))

PREDICATE: dbcall/2:

Usage: dbcall(+DBId,+ComplexGoal)

PREDICATE: sql_query/3:

Usage: sql_query(+DBId,+SQLString,AnswerTableTerm)

PREDICATE: sql_get_tables/2:

Usage 1: sql_get_tables(+Location,-(Tables))

Usage 2: sql_get_tables(+DbConnection,-(Tables))

PREDICATE: sql_table_types/3:

Usage 1: sql_table_types(+Location,+Table,-(AttrTypes))

Usage 2: sql_table_types(+DbConnection,+Table,-(AttrTypes))

REGTYPE: socketname/1:

Usage: socketname(IPP)

REGTYPE: dbname/1:

Usage: dbname(DBId)

REGTYPE: user/1:

Usage: user(User)

REGTYPE: passwd/1:

Usage: passwd(Passwd)

REGTYPE: projterm/1:

Usage: projterm(DBProjTerm)

REGTYPE: querybody/1:

Usage: querybody(DBGoal)

(UNDOC_REEXPORT): sqltype/1:

Imported from sqltypes (see the corresponding documentation for details).

Documentation on multifiles (persdbrtsql)

PREDICATE: sql_persistent_location/2:

Relates names of locations (the Keywords) with descriptions of such locations (Locations).

The predicate is multifile.

The predicate is of type data.

Usage 1: sql_persistent_location(Keyword,Location)

Usage 2: sql_persistent_location(Keyword,DBLocation)

Documentation on internals (persdbrtsql)

PREDICATE: db_query/4:

Usage: db_query(+DBId,+ProjTerm,+Goal,ResultTerm)

PREDICATE: db_query_one_tuple/4:

Usage: db_query_one_tuple(+DBId,+ProjTerm,+Goal,ResultTerm)

PREDICATE: sql_query_one_tuple/3:

Usage: sql_query_one_tuple(+DBId,+SQLString,ResultTuple)

REGTYPE: dbconnection/1:

Usage: dbconnection(H)

REGTYPE: tuple/1:

Usage: tuple(T)

Known bugs and planned improvements (persdbrtsql)


Go to the first, previous, next, last section, table of contents.