Access to Relational Databases

Overview

PrologJ allows a Prolog program to access any relational database, provided a JDBC driver is available for it. Three kinds of Prolog predicate can be created for this purpose. A table predicate associates a Prolog predicate with a single table in the database, so that operations performed on the predicate (asserta/1, assertz/1, call/1, clause/2, retract/1 and retractall/1) are executed as operations on the database table (insert, select, or delete). A query predicate associates a Prolog predicate with a SQL query (that may involve multiple tables), so that calling the Prolog predicate leads to executing the query and (generally) binding variables appearing in the query to values retrieved from the database. An update predicate associates a Prolog predicate with a SQL update statement, so that calling the Prolog predicate leads to updating the database, possibly with some of the values being specified by parameters of the Prolog predicate.

Relational database access predicates are created by options to an extended version of open/4, which specifies a database to connect to rather than a stream to open.

Connecting to a Relational Database

Two builtin-in predicates have been extended to allow code written in Prolog to initiate and terminate a connection to a relational database using JDBC, and to define Prolog predicates to access it.

Table Predicates

A table predicate represents an association between a Prolog predicate and a single table in the database. Both the predicate and the table must have the same arity; they may - but need not necessarily - have the same name. Arguments of the Prolog predicate are associated with columns in the table based on the order of the columns in the database.

Operations performed on a table predicate result in performing operations on the database table. The following example will be used in describing the various operations.
 
Suppose there is a table in the database with the following scheme:
 
person(last, first, mi, address, city, state, zip)

 
Suppose further that a table predicate is created by:
 
table(person/7, person).
 

Query Predicates

A query predicate represents an association between a Prolog predicate and a SQL query (select) statement, which may (but need not) involve joining multiple tables. If the statement has m parameters (? appears m times in the query) and produces a result having n columns, then the arity of the predicate is m + n. When the predicate is called, the first m arguments correspond to the parameters of the SQL statement, in the order in which they appear, and the final n arguments correspond to the values produced by the statement, in the order in which the columns appear either in the select clause or as columns in the database (if select * or select table.* is used).

The only legal operation on a query predicate is to call it (directly, or as an argument of a predicate like call/1). Each of the initial arguments of the call must be a values that is compatible with the type of the corresponding parameter. (An uninstantiated variable is allowed and will result in the corresponding parameter being set to NULL.) The next n arguments of the call must be will be unified with one of the columns of the result, converted to an appropriate Prolog type. A call to a query predicate succeeds as many times as there are rows in the result of the query which unify with the final arguments of the call.

Example: Suppose the database contains the following tables:

variable(name, type)

b       boolean
c       char
s       short
i       int
j       int
l       long
m       long
f       float
g       float
d       double

storage(type, bytes)

boolean 1
char    2
byte    1
short   2
int     4
long    8
float   4
double  4

Suppose further that a query predicate test/2 is created for the following statement:

select name
    from variable join storage on variable.type = storage.type
    where bytes = ?

Then the following goal will succeed 4 times, with the unifications shown:

test(4, Name).

Name = i;
Name = j;
Name = f;
Name = g.

Error cases:

ConditionsError Term
One of the initial arguments of the call (that correspond to parameters) is a variable, and the corresponding parameter does not allow its value to be NULL instantiation_error (See note 1)
One of the initial arguments of the call (that correspond to parameters) is instantiated to a value that is not compatible with the declared type of the corresponding parameter The error that is listed for the specific violation in the discussion of type conversion errors (See note 1)

Notes:

  1. The ability to detect such errors depends on the extent to with the database driver fully supports JDBC 3. With drivers that are not yet at this level of compliance, some parameter problems will not be detected until an attempt is made to set the parameter value, at which point the error thrown will be relational_database_access(predicate indicator).

Update Predicates

An update predicate represents an association between a Prolog predicate and a SQL update statement (often insert, update, or delete, but the statement may be any legal SQL statement that does not produce a result set). The arity of the predicate corresponds to the number of parameters in the statement (the number of times ? appears in the statement), plus one. When the predicate is called, its first arguments correspond to the parameters of the SQL statement, in the order in which they appear, and its last argument is unified with the count of the number of rows affected by the operation.

The only legal operation on an update predicate is to call it (directly, or as an argument of a predicate like call/1). Each of the initial arguments of the call must be a values that is compatible with the type of the corresponding parameter. (An uninstantiated variable is allowed and will result in the corresponding parameter being set to NULL.) In the absence of an error, the final argument is unified with the count of the number of rows affected by the operation, and the call to the update predicate succeeds just when the unification succeeds.

Example: Suppose the database contains the following table:

employee(name, department, salary)

Suppose further that an update predicate raise/2 is created for the following statement:

update employee
    set salary = salary * (1 + ?)
    where department = ?

Then the following goal will give a 10% raise to all employees in the Prolog Programming department: raise(0.10, 'Prolog Programming').

Note well: the success or failure of a call using an update predicate is based on the unification of the final parameter with the count of the number of rows affected, not on whether or not any rows were affected. If it is desired to call an update predicate in such a way as to have the call succeed only if one or more rows are affected, a form like the following can be used:

	update_predicate_name(args ...  AffectedRowCount),
	AffectedRowCount > 0

Error cases:

ConditionsError Term
One of the initial arguments of the call is a variable, and the corresponding parameter does not allow its value to be NULL instantiation_error (See note 1)
One of the initial arguments of the call is instantiated to a value that is not compatible with the declared type of the corresponding parameter The error that is listed for the specific violation in the discussion of type conversion errors (See note 1)

Notes:

  1. The ability to detect such errors depends on the extent to with the database driver fully supports JDBC 3. With drivers that are not yet at this level of compliance, some parameter problems will not be detected until an attempt is made to set the parameter value, at which point the error thrown will be relational_database_access(predicate indicator).

Creating Relational Database Predicates

A table, query, or update predicate is created by an appropriate option to an open/4 goal that specifies the database. (This may be either the open/4 that initially creates the connection, or a subsequent goal that references an already existing connection.)

Extensions to Built-in Predicates

The Relational Interface extends a number of built-in predicates for use in either creating or using relational database predicates.

Copyright © 2005 - Russell C. Bjork. See the file See file COPYING in the root directory for copyright information.

Valid XHTML 1.0!