#include <stdlib.h>
#include <string.h>
#include <Query.h>
-#include <BindingTable.h>
+#include <QueryCallbacks.h>
-enum NextState {
- /**
- * This state tells the "next" function that it should capture the
- * incoming BindingTable state and provide the initial Binding of
- * a new sucession of bindings.
- */
- initial,
- /**
- * This state tells the "next" function that it should update the
- * bidning table with a subsequent Binding in the current
- * succession of bindings.
- */
- subsequent,
- /**
- * This state tells the "next" function that it should just
- * restore the Binding table to its incoming state.
- */
- restore
-};
+/* ==================== AssignmentQuery ==================== */
/**
- * A struct Query_callbacks record defines the callbacks for a
- * specific Query type.
+ * AssignmentQuery represents an assignment of values to names.
+ * \extends Query
+ * \related Query
*/
-struct QueryCallbacks {
- /**
- * \brief Callback function to reclaim the Query memory for a
- * given Query.
- *
- * \param this is the specific \ref Query concerned.
- *
- * Ground queries recalim their own state memory. Composite
- * queries first propagate the reclaim call to its components, and
- * thereafter reclaim their local state memory.
- */
- void (*reclaim)(Query *this);
- void (*start)(Query *this,BindingTable *bt,enum NextState s);
- /**
- * \brief Callback function to update the Binding table with a
- * succession of alternative bindings.
- *
- * \param this is the specific \ref Query concerned.
- *
- * \param bt is the Binding table to set bindings in.
- *
- * \param s is the call "sub-command" for the function.
- *
- * \returns 1 if a new Binding is provided and 0 otherwise.
- *
- * This function is called repeatedly for successively obtaining
- * the alternative bindings that satisfy the Query. The "initial"
- * state sub-command tells the function to capture the incoming
- * BindingTable state so that the function can later restore it
- * upon the "restore" sub-command. Upon the "initial" command, the
- * function also sets up the Binding table with its first Binding
- * alternative. This is followed by a series of "subsequent"
- * sub-command calls for the function to change the BindingTable
- * for its succession of Binding alternatives. The function should
- * return 1 after any successful Binding setup, and return 0 when
- * it cannot setup any (more) Binding.
- */
- int (*next)(Query *this,BindingTable *bt,enum NextState state);
-};
-
-/* ==================== AssignmentQuery ==================== */
typedef struct {
struct QueryCallbacks *def;
int arity;
- tuple *names;
- tuple *values;
- tuple *saved;
+ Tuple *names;
+ Tuple *values;
+ Tuple *saved;
} AssignmentQuery;
// Release any memory.
free( this );
}
-static int AssignmentQuery_check(int arity,tuple *a,tuple *b) {
+static int AssignmentQuery_check(int arity,Tuple *a,Tuple *b) {
int i;
for ( i = 0; i < arity; i++ ) {
- char *value = (*a)[i];
- char *current = (*b)[i];
+ char *value = a->elements[i];
+ char *current = b->elements[i];
if ( value && current && current != value &&
strcmp( current, value ) != 0 ) {
return 0;
}
static void AssignmentQuery_assign(
- BindingTable *bt,int n,tuple *names,tuple *values,int all)
+ BindingTable *bt,int n,Tuple *names,Tuple *values,int all)
{
int i;
for ( i = 0; i < n; i++ ) {
- if ( all || (*values)[i] ) {
- BindingTable_set( bt, (*names)[i], (*values)[i] );
+ if ( all || values->elements[i] ) {
+ BindingTable_set( bt, names->elements[i], values->elements[i] );
}
}
}
switch ( state ) {
case initial:
if ( q->saved == 0 ) {
- q->saved = (tuple*) malloc( q->arity * sizeof( void* ) );
+ q->saved = Tuple_clone( q->arity, q->names );
+ } else {
+ memcpy( q->saved, q->names, q->arity * sizeof( void* ) );
}
- memcpy( q->saved, q->names, q->arity * sizeof( void* ) );
BindingTable_deref( bt, q->arity, q->saved );
// Check with new values
if ( AssignmentQuery_check( q->arity, q->values, q->saved ) ) {
* Return a Query object representing an assignment of one or more
* variables.
*/
-Query *Query_assign(int arity,tuple *names,tuple *values) {
+Query *Query_assign(int arity,Tuple *names,Tuple *values) {
AssignmentQuery *q = (AssignmentQuery*)
malloc( sizeof( AssignmentQuery ) );
(*q) = (AssignmentQuery) {
}
/* ==================== conjunction ==================== */
+
+/**
+ * ConjunctionQuery represents a conjunction of sub queries.
+ * \extends Query
+ * \related Query
+ */
typedef struct {
struct QueryCallbacks *def;
int active;
}
/* ==================== disjunction ==================== */
+
+/**
+ * DisjunctionQuery represents a disjunction of sub queries.
+ * \extends Query
+ * \related Query
+ */
typedef struct {
struct QueryCallbacks *def;
int index;
}
/* ==================== Relation access ==================== */
+
+/**
+ * RelationQuery represents a ground query on a relation.
+ * \extends Query
+ * \related Query
+ */
typedef struct {
struct QueryCallbacks *def;
Relation *rel;
VectorIndex index;
- tuple *names;
- tuple *values;
- tuple *saved;
+ Tuple *names;
+ Tuple *values;
+ Tuple *saved;
} RelationQuery;
// Release any memory.
switch ( state ) {
case initial:
if ( q->saved == 0 ) {
- q->saved = (tuple*) malloc( arity * sizeof( void* ) );
+ q->saved = Tuple_clone( arity, q->names );
+ } else {
+ memcpy( q->saved, q->names, arity * sizeof( void* ) );
}
- memcpy( q->saved, q->names, arity * sizeof( void* ) );
BindingTable_deref( bt, arity, q->saved );
index = 0;
// Fall through
case subsequent:
for ( ; index < q->rel->content.table.size; index++ ) {
- tuple *values = Relation_next( q->rel, &index, q->values );
+ Tuple *values = Relation_next( q->rel, &index, q->values );
if ( values ) {
q->index = index;
AssignmentQuery_assign( bt, arity, q->names, values, 1 );
* Return a Query object representing an Relation of one or more
* variables.
*/
-Query *Query_Relation(Relation *r,tuple *names,tuple *values) {
+Query *Query_Relation(Relation *r,Tuple *names,Tuple *values) {
RelationQuery *q = (RelationQuery*) malloc( sizeof( RelationQuery ) );
(*q) = (RelationQuery) {
.def = &RelationQuery_def,
};
return (Query*) q;
}
+
+void Query_rule(
+ Query *q,BindingTable *bt,
+ int (*consequent)(BindingTable *bt,void *data),
+ void *data )
+{
+ if ( q->def->next( q, bt, initial ) && consequent( bt, data ) ) {
+ while ( q->def->next( q, bt, subsequent ) && consequent( bt, data ) );
+ }
+ (void) q->def->next( q, bt, restore );
+}