+#include <stdarg.h>
#include <stdlib.h>
#include <relation.h>
+relation *relation_create(tupleschema *schema) {
+ relation *r = (relation *) malloc( sizeof( relation ) );
+ (*r) = (relation) {
+ .content = (hashvector) {
+ .table = (vector) {
+ .variant = nibble_index_levels,
+ .size = 16,
+ .entries = 0
+ },
+ .fill = 0, .holes = 0, .type = (itemkeyfun*) schema
+ },
+ .constraints = (vector) {
+ .variant = single_index_level,
+ .size = 0,
+ .entries = 0
+ },
+ };
+ return r;
+}
+
#define COPYA(T,P,N) (T*) memcpy( malloc( N * sizeof(T) ), P, N * sizeof( T ) )
#define COPY(T,P) COPYA(T,P,1)
-// Add an indexing hashvector to the relation using the nominated
-// column indexes being the value part. the key must be a clone of the
-// relation columns but with some columns reset.
-int relation_addindex(relation *r,tupleschema *key) {
- tupleschema *primary = r->columns;
- if ( primary->arity != key->arity ) {
- return -1;
- }
+// 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,...) {
+ va_list ap;
+ tupleschema *ts = (tupleschema *) r->content.type;
+ tuple *columns = (tuple*) calloc( ts->arity, sizeof( void* ) );
int i = 0;
- for ( ; i < primary->arity; i++ ) {
- if ( key->columns[i] && primary->columns[i] != key->columns[i] ) {
- return -1;
+ va_start( ap, r );
+ for ( ; i < ts->arity; i++ ) {
+ if ( va_arg( ap, int ) ) {
+ (*columns)[i] = ts->columns[i];
}
}
- i = (int) r->indexes.size;
- vector_append( &r->indexes, hashvector_create( 1, (itemkeyfun*) key ) );
+ va_end( ap );
+ ts = tupleschema_create( ts->arity, columns );
+ i = (int) r->constraints.size;
+ vector_append(
+ &r->constraints,
+ hashvector_create( nibble_index_levels, (itemkeyfun*) ts ) );
return i;
}
-relation *relation_create(int arity,tupleschema *schema) {
- relation *r = (relation *) malloc( sizeof( relation ) );
- (*r) = (relation) {
- .indexes = {
- .variant = 2,
- .size = 0,
- .entries = 0
- },
- .columns = schema
- };
- return r;
-}
-
+//============== Adding an item =============
// Iteration context for adding or querying a relation
typedef struct {
- itemkeyfun *columns;
+ relation *rel;
vector knockouts;
- void *key;
-} knockoutdata;
+ void *item;
+} knockout;
-// Determine matches to ((knockoutdata*)data)->key in
-// (hashvector*)item, optionally using ((knockoutdata*)data)->columns
+// Determine matches to ((knockout*)data)->key in
+// (hashvector*)item, optionally using ((knockout*)data)->columns
// for ignoring full matches to the key tuple.
static int knockout_check(vector_index index,void *item,void *data) {
- knockoutdata *kod = (knockoutdata*) data;
- void *old = 0;
- if ( hashvector_find( (hashvector*) item, kod->key, &old ) ) {
- if ( kod->columns == 0 ||
- kod->columns->haskey( kod->columns, old, kod->key ) == 0 ) {
- if ( vector_find( &kod->knockouts, old ) >= kod->knockouts.size ) {
- vector_append( &kod->knockouts, old );
- }
- }
+ knockout *kod = (knockout*) data;
+ void *old = hashvector_next( (hashvector*) item, 0, kod->item );
+ if ( old ) {
+ vector_append( &kod->knockouts, old );
}
return 0;
}
return 0;
}
-// 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 *x) {
- knockoutdata data = {
- .columns = &(r->columns->functions),
- .knockouts = { .variant = 2, .size = 0, .entries = 0 },
- .key = x
+// 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) {
+ (*this) = (knockout) {
+ .rel = r,
+ .knockouts = {
+ .variant = bitpair_index_levels,
+ .size = 0, .entries = 0
+ },
+ .item = item
};
- // Find all knockouts
- vector_iterate( &r->indexes, 0, knockout_check, &data );
- // Delete them
- vector_iterate( &r->indexes, 0, knockout_delete, &data.knockouts );
- // Add the new tuple
- vector_iterate( &r->indexes, 0, knockout_add, x );
- if ( data.knockouts.size == 0 ) {
+ knockout_check( 0, &r->content, this );
+ if ( add && this->knockouts.size > 0 ) {
return 0;
}
- return vector_clone( 3, &data.knockouts );
+ // Find all constraint knockouts
+ vector_iterate( &r->constraints, 0, knockout_check, this );
+ if ( this->knockouts.size > 0 ) {
+ // Delete them from all tables
+ vector_iterate(
+ &this->knockouts, 0, knockout_delete_item, &r->content );
+ vector_iterate(
+ &r->constraints, 0, knockout_delete, &this->knockouts );
+ }
+ return 1;
+}
+
+// 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) {
+ knockout data;
+ if ( knockout_clear( &data, r, item, 1 ) ) {
+ // Add the new tuple
+ hashvector_add( &r->content, item );
+ vector_iterate( &r->constraints, 0, knockout_add, item );
+ if ( data.knockouts.size > 0 ) {
+ return vector_clone( single_index_level, &data.knockouts );
+ }
+ }
+ return 0;
+}
+
+vector *relation_delete(relation *r,tuple *item) {
+ knockout data;
+ (void) knockout_clear( &data, r, item, 0 );
+ if ( data.knockouts.size > 0 ) {
+ return vector_clone( single_index_level, &data.knockouts );
+ }
+ return 0;
+}
+
+void *relation_next(relation *r,vector_index *index,tuple *query) {
+ return hashvector_next( &r->content, index, query );
}