X-Git-Url: https://git.rrq.au/?a=blobdiff_plain;f=vector%2FQuery.c;h=94a39d744a2b288638d107501edbc7ab088c5b1c;hb=48cdb87442b7b3f1cdde9c1710ed90ec773dce97;hp=c13ecde73e418e4c399f190fc7ad4f370e46809f;hpb=813cf9d12ff1b1c58e508485c977d33caaf89a86;p=rrq%2Frrqmisc.git diff --git a/vector/Query.c b/vector/Query.c index c13ecde..94a39d7 100644 --- a/vector/Query.c +++ b/vector/Query.c @@ -1,360 +1,88 @@ -#include -#include -#include #include -#include - -/* ==================== AssignmentQuery ==================== */ /** - * AssignmentQuery represents an assignment of values to names. - * \extends Query - * \related Query + * \brief Trampoline for the 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. */ -typedef struct { - struct QueryCallbacks *def; - int arity; - Tuple *names; - Tuple *values; - Tuple *saved; -} AssignmentQuery; - -// Release any memory. -static void AssignmentQuery_reclaim(Query *this) { - AssignmentQuery *q = (AssignmentQuery*) this; - free( q->saved ); - free( this ); -} - -static int AssignmentQuery_check(int arity,Tuple *a,Tuple *b) { - int i; - for ( i = 0; i < arity; i++ ) { - char *value = a->elements[i]; - char *current = b->elements[i]; - if ( value && current && current != value && - strcmp( current, value ) != 0 ) { - return 0; - } - } - return 1; -} - -static void AssignmentQuery_assign( - BindingTable *bt,int n,Tuple *names,Tuple *values,int all) -{ - int i; - for ( i = 0; i < n; i++ ) { - if ( all || values->elements[i] ) { - BindingTable_set( bt, names->elements[i], values->elements[i] ); - } - } -} - -// Make names have given values and return 1. If any name has a -// different value then return 0. Values are strings. -static int AssignmentQuery_next( - Query *this,BindingTable *bt,enum NextState state) { - AssignmentQuery *q = (AssignmentQuery*) this; - switch ( state ) { - case initial: - if ( q->saved == 0 ) { - q->saved = Tuple_clone( q->arity, q->names ); - } else { - 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 ) ) { - AssignmentQuery_assign( bt, q->arity, q->names, q->values, 0 ); - return 1; - } - // Fall through - case subsequent: - case restore: - if ( q->saved ) { - AssignmentQuery_assign( bt, q->arity, q->names, q->saved, 1 ); - free( q->saved ); - q->saved = 0; - } - return 0; - } - return 0; +void Query_reclaim(Query *this) { + this->def->reclaim( this ); } -static struct QueryCallbacks AssignmentQuery_def = { - .reclaim = AssignmentQuery_reclaim, - .next = AssignmentQuery_next -}; - /** - * Return a Query object representing an assignment of one or more - * variables. + * \brief Trampoline for the 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. */ -Query *Query_assign(int arity,Tuple *names,Tuple *values) { - AssignmentQuery *q = (AssignmentQuery*) - malloc( sizeof( AssignmentQuery ) ); - (*q) = (AssignmentQuery) { - .def = &AssignmentQuery_def, - .arity = arity, - .names = names, - .values = values, - .saved = 0 - }; - return (Query*) q; +int Query_next(Query *this,BindingTable *bt,enum NextState state) { + return this->def->next( this, bt, state ); } -/* ==================== conjunction ==================== */ - /** - * ConjunctionQuery represents a conjunction of sub queries. - * \extends Query - * \related Query + * \brief Trampoline for the callback function that adds its binding + * names to the hashvector. */ -typedef struct { - struct QueryCallbacks *def; - int active; - int size; - Query **conjuncts; -} ConjunctionQuery; - -static void ConjunctionQuery_reclaim(Query *this) { - ConjunctionQuery *q = (ConjunctionQuery*) this; - int i; - for ( i = 0; i < q->size; i++ ) { - q->conjuncts[i]->def->reclaim( q->conjuncts[i] ); - } - free( q->conjuncts ); - free( this ); +void Query_variables(Query *this,HashVector *hv) { + this->def->variables( this, hv ); } -static int ConjunctionQuery_next( - Query *this,BindingTable *bt,enum NextState state) +void Query_eval( + Query *q,BindingTable *bt, + int (*consequent)(BindingTable *bt,void *data), + void *data ) { - ConjunctionQuery *q = (ConjunctionQuery*) this; - int i = q->size - 1; - enum NextState s = subsequent; - switch ( state ) { - case initial: - q->active = 1; - i = 0; - s = initial; - // Fall through? - case subsequent: - while ( i < q->size ) { - if ( q->conjuncts[i]->def->next( q->conjuncts[i], bt, s ) ) { - continue; - } - q->conjuncts[i]->def->next( q->conjuncts[i], bt, restore ); - if ( i-- == 0 ) { - // The first conjunct now exhausted - q->active = 0; - return 0; - } - s = subsequent; - } - return 1; - case restore: - if ( q->active ) { - for ( ; i >= 0; i-- ) { - q->conjuncts[i]->def->next( q->conjuncts[i], bt, restore ); - } - } - q->active = 0; - return 0; - } - return 0; -} - -static struct QueryCallbacks ConjunctionQuery_def = { - .reclaim = ConjunctionQuery_reclaim, - .next = ConjunctionQuery_next -}; - -Query *Query_and(int n,...) { - va_list args; - ConjunctionQuery *q = (ConjunctionQuery *) - malloc( sizeof( ConjunctionQuery ) ); - (*q) = (ConjunctionQuery) { - .def = &ConjunctionQuery_def, - .active = 0, - .size = n, - .conjuncts = (Query**) malloc( n * sizeof( Query* ) ) - }; - int i; - va_start( args, n ); - for ( i = 0; i < n; i++ ) { - q->conjuncts[i] = va_arg( args, Query* ); - } - va_end( args ); - return (Query*) q; -} - -/* ==================== disjunction ==================== */ - -/** - * DisjunctionQuery represents a disjunction of sub queries. - * \extends Query - * \related Query - */ -typedef struct { - struct QueryCallbacks *def; - int index; - int size; - Query **disjuncts; -} DisjunctionQuery; - -static void DisjunctionQuery_reclaim(Query *this) { - DisjunctionQuery *q = (DisjunctionQuery*) this; - int i; - for ( i = 0; i < q->size; i++ ) { - q->disjuncts[i]->def->reclaim( q->disjuncts[i] ); - } - free( q->disjuncts ); - free( this ); -} - -static int DisjunctionQuery_next( - Query *this,BindingTable *bt,enum NextState state) { - DisjunctionQuery *q = (DisjunctionQuery*) this; - int i = q->index; - enum NextState s = subsequent; - switch ( state ) { - case initial: - i = 0; - s = initial; - case subsequent: - for ( ; i < q->size; i++ ) { - if ( q->disjuncts[i]->def->next( q->disjuncts[i], bt, s ) ) { - q->index = i; - return 1; - } - q->disjuncts[i]->def->next( q->disjuncts[i], bt, restore ); - s = initial; - } - q->index = -1; - return 0; - case restore: - if ( i >= 0 ) { - q->disjuncts[i]->def->next( q->disjuncts[i], bt, restore ); - q->index = -1; - } - return 0; - } - return 0; -} - -static struct QueryCallbacks DisjunctionQuery_def = { - .reclaim = DisjunctionQuery_reclaim, - .next = DisjunctionQuery_next, -}; - -Query *Query_or(int n,...) { - va_list args; - DisjunctionQuery *q = (DisjunctionQuery *) - malloc( sizeof( DisjunctionQuery ) ); - (*q) = (DisjunctionQuery) { - .def = &DisjunctionQuery_def, - .index = -1, - .size = n, - .disjuncts = (Query**) malloc( n * sizeof( Query* ) ), - }; - int i; - va_start( args, n ); - for ( i = 0; i < n; i++ ) { - q->disjuncts[i] = va_arg( args, Query* ); + if ( Query_next( q, bt, initial ) && consequent( bt, data ) ) { + while ( Query_next( q, bt, subsequent ) && consequent( bt, data ) ); } - va_end( args ); - return (Query*) q; + (void) Query_next( q, bt, restore ); } -/* ==================== Relation access ==================== */ +/* ==================== Snapshotting a query ==================== */ /** - * RelationQuery represents a ground query on a relation. - * \extends Query - * \related Query + * The data used for bindings capture in snapshotting. */ -typedef struct { - struct QueryCallbacks *def; - Relation *rel; - VectorIndex index; +struct Query_snapshot_data { Tuple *names; - Tuple *values; - Tuple *saved; -} RelationQuery; - -// Release any memory. -static void RelationQuery_reclaim(Query *this) { - RelationQuery *q = (RelationQuery*) this; - free( q->saved ); - free( this ); -} - -// Make names have given values and return 1. If any name has a -// different value then return 0. Values are strings. -static int RelationQuery_next( - Query *this,BindingTable *bt,enum NextState state) { - RelationQuery *q = (RelationQuery*) this; - int arity = ((TupleSchema*) q->rel->content.type)->arity; - VectorIndex index = q->index + 1; - switch ( state ) { - case initial: - if ( q->saved == 0 ) { - q->saved = Tuple_clone( arity, q->names ); - } else { - 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 ); - if ( values ) { - q->index = index; - AssignmentQuery_assign( bt, arity, q->names, values, 1 ); - return 1; - } - } - case restore: - if ( q->saved ) { - AssignmentQuery_assign( bt, arity, q->names, q->saved, 1 ); - free( q->saved ); - q->saved = 0; - } - return 0; - } - return 0; -} - -static struct QueryCallbacks RelationQuery_def = { - .reclaim = RelationQuery_reclaim, - .next = RelationQuery_next + Vector *v; }; -/** - * Return a Query object representing an Relation of one or more - * variables. - */ -Query *Query_Relation(Relation *r,Tuple *names,Tuple *values) { - RelationQuery *q = (RelationQuery*) malloc( sizeof( RelationQuery ) ); - (*q) = (RelationQuery) { - .def = &RelationQuery_def, - .rel = r, - .names = names, - .values = values, - .saved = 0 - }; - return (Query*) q; +static int Query_snapshot_capture(BindingTable *bt,void *data) { + struct Query_snapshot_data *d = (struct Query_snapshot_data*) data; + Tuple *values = Tuple_clone( d->names ); + BindingTable_deref( bt, values ); + Vector_append( d->v, values ); + return 1; } -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 ); +int Query_snapshot(Query *q,Tuple *names,Vector *v) { + BindingTable *bt = BindingTable_create( 0 ); + struct Query_snapshot_data data = { .names = names, .v = v }; + Vector_resize( v, 0, Vector_free_any, 0 ); + Query_eval( q, bt, Query_snapshot_capture, &data ); + return v->size; }