rework Relation_next and HashVector_next to void query handling in HashVector
[rrq/rrqmisc.git] / vector / Relation.c
index f72f19888d8ab531ac6fe47e7944baed178b2fd3..0f671abce2d09c475f8092e22ff760825211250c 100644 (file)
@@ -2,7 +2,7 @@
 #include <stdlib.h>
 #include <Relation.h>
 
-Relation *relation_create(TupleSchema *schema) {
+Relation *Relation_create(TupleSchema *schema) {
     Relation *r = (Relation *) malloc( sizeof( Relation ) );
     (*r) = (Relation) {
        .content = (HashVector) {
@@ -27,15 +27,16 @@ Relation *relation_create(TupleSchema *schema) {
 
 // Add an indexing HashVector to the Relation using the given column
 // flags with 1 indicating key column and 0 indicating value column.
-int relation_add_constraint(Relation *r,...) {
+int Relation_add_constraint(Relation *r,...) {
     va_list ap;
     TupleSchema *ts = (TupleSchema *) r->content.type;
-    tuple *columns = (tuple*) calloc( ts->arity, sizeof( void* ) );
+    Tuple *columns = (Tuple*) malloc(
+       sizeof( Tuple ) + ts->arity * sizeof( void* ) );
     int i = 0;
     va_start( ap, r );
     for ( ; i < ts->arity; i++ ) {
        if ( va_arg( ap, int ) ) {
-           (*columns)[i] = ts->columns[i];
+           columns->elements[i] = ts->columns->elements[i];
        }
     }
     va_end( ap );
@@ -48,7 +49,7 @@ int relation_add_constraint(Relation *r,...) {
 }
 
 //============== Adding an item =============
-// Iteration context for adding or querying a Relation
+// Iteration context for adding or Querying a Relation
 typedef struct {
     Relation *rel;
     HashVector knockouts;
@@ -60,10 +61,16 @@ typedef struct {
 // for ignoring full matches to the key tuple.
 static int knockout_check(VectorIndex index,void *item,void *data) {
     Knockout *kod = (Knockout*) data;
+    void *key = kod->item;
+    HashVector *hv = (HashVector*) item;
+    TupleSchema *type = (TupleSchema *)hv->type;
     VectorIndex i = 0;
-    for ( ; i < ((HashVector*) item)->table.size; i++ ) {
-       void *old = HashVector_next( (HashVector*) item, &i, kod->item );
+    for ( ; i < hv->table.size; i++ ) {
+       void *old = HashVector_next( hv, &i );
        if ( old ) {
+           if ( key && type->base.haskey( type, old, key ) == 0 ) {
+               continue;
+           }
            HashVector_add( &kod->knockouts, old );
        }
     }
@@ -82,10 +89,10 @@ static int knockout_add(VectorIndex index,void *item,void *data) {
     return 0;
 }
 
-// Find and remove all collisions for a query, unless "add" is
+// Find and remove all collisions for a Query, unless "add" is
 // non-zero in which case the function aborts if there is any match in
 // the main content.
-static int knockout_clear(Knockout *this,Relation *r,tuple *item,int add) {
+static int knockout_clear(Knockout *this,Relation *r,Tuple *item,int add) {
     (*this) = (Knockout) {
        .rel = r,
        .knockouts = {
@@ -108,7 +115,7 @@ static int knockout_clear(Knockout *this,Relation *r,tuple *item,int add) {
        // Delete them from all tables
        VectorIndex i;
        for ( i = 0; i < this->knockouts.table.size; i++ ) {
-           void *t = HashVector_next( &this->knockouts, &i, 0 );
+           void *t = HashVector_next( &this->knockouts, &i );
            if ( t ) {
                HashVector_delete( &r->content, t );
                Vector_iterate( &r->constraints, 0, knockout_delete, t );
@@ -120,7 +127,7 @@ static int knockout_clear(Knockout *this,Relation *r,tuple *item,int add) {
 
 // add a tuple to a Relation and return a Vector of knocked out
 // tuples, if any, or 0 otherwise.
-Vector *relation_add(Relation *r,tuple *item) {
+Vector *Relation_add(Relation *r,Tuple *item) {
     Knockout data;
     if ( knockout_clear( &data, r, item, 1 ) ) {
        // Add the new tuple
@@ -131,13 +138,26 @@ Vector *relation_add(Relation *r,tuple *item) {
     return 0;
 }
 
-Vector *relation_delete(Relation *r,tuple *item) {
+Vector *Relation_delete(Relation *r,Tuple *item) {
     Knockout data;
     (void) knockout_clear( &data, r, item, 0 );
     return HashVector_contents( &data.knockouts, single_index_level, 0 );
 }
 
-void *relation_next(Relation *r,VectorIndex *index,tuple *query) {
-    return HashVector_next( &r->content, index, query );
+void *Relation_next(Relation *r,VectorIndex *index,Tuple *query) {
+    HashVector *hv = &r->content;
+    void *key = query;
+    TupleSchema *type = (TupleSchema *) hv->type;
+    for ( ; (*index) < hv->table.size; (*index)++ ) {
+       void *old = HashVector_next( hv, index );
+       if ( old ) {
+           if ( key && type->base.haskey( type, old, key ) == 0 ) {
+               continue;
+           }
+           return old;
+       }
+    }
+    (*index) = hv->table.size;
+    return 0;
 }