5 relation *relation_create(tupleschema *schema) {
6 relation *r = (relation *) malloc( sizeof( relation ) );
8 .content = (hashvector) {
10 .variant = nibble_index_levels,
14 .fill = 0, .holes = 0, .type = (itemkeyfun*) schema
16 .constraints = (vector) {
17 .variant = single_index_level,
25 #define COPYA(T,P,N) (T*) memcpy( malloc( N * sizeof(T) ), P, N * sizeof( T ) )
26 #define COPY(T,P) COPYA(T,P,1)
28 // Add an indexing hashvector to the relation using the given column
29 // flags with 1 indicating key column and 0 indicating value column.
30 int relation_add_constraint(relation *r,...) {
32 tupleschema *ts = (tupleschema *) r->content.type;
33 tuple *columns = (tuple*) calloc( ts->arity, sizeof( void* ) );
36 for ( ; i < ts->arity; i++ ) {
37 if ( va_arg( ap, int ) ) {
38 (*columns)[i] = ts->columns[i];
42 ts = tupleschema_create( ts->arity, columns );
43 i = (int) r->constraints.size;
46 hashvector_create( nibble_index_levels, (itemkeyfun*) ts ) );
50 //============== Adding an item =============
51 // Iteration context for adding or querying a relation
58 // Determine matches to ((knockout*)data)->key in
59 // (hashvector*)item, optionally using ((knockout*)data)->columns
60 // for ignoring full matches to the key tuple.
61 static int knockout_check(vector_index index,void *item,void *data) {
62 knockout *kod = (knockout*) data;
63 void *old = hashvector_next( (hashvector*) item, 0, kod->item );
65 vector_append( &kod->knockouts, old );
70 // delete the (tuple*)item from the (hashvector*)data
71 static int knockout_delete_item(vector_index index,void *item,void *data) {
72 hashvector_delete( (hashvector*)data, item );
76 // delete the tuples of (vector*)data from the (hashvector*)item
77 static int knockout_delete(vector_index index,void *item,void *data) {
78 vector_iterate( (vector*)data, 0, knockout_delete_item, item );
82 // add the (tuple*)data to the (hashvector*)item
83 static int knockout_add(vector_index index,void *item,void *data) {
84 hashvector_add( (hashvector*)item, data );
88 // Find and remove all collisions for a query, unless "add" is
89 // non-zero in which case the function aborts if there is any match in
91 static int knockout_clear(knockout *this,relation *r,tuple *item,int add) {
92 (*this) = (knockout) {
95 .variant = bitpair_index_levels,
96 .size = 0, .entries = 0
100 knockout_check( 0, &r->content, this );
101 if ( add && this->knockouts.size > 0 ) {
104 // Find all constraint knockouts
105 vector_iterate( &r->constraints, 0, knockout_check, this );
106 if ( this->knockouts.size > 0 ) {
107 // Delete them from all tables
109 &this->knockouts, 0, knockout_delete_item, &r->content );
111 &r->constraints, 0, knockout_delete, &this->knockouts );
116 // add a tuple to a relation and return a vector of knocked out
117 // tuples, if any, or 0 otherwise.
118 vector *relation_add(relation *r,tuple *item) {
120 if ( knockout_clear( &data, r, item, 1 ) ) {
122 hashvector_add( &r->content, item );
123 vector_iterate( &r->constraints, 0, knockout_add, item );
124 if ( data.knockouts.size > 0 ) {
125 return vector_clone( single_index_level, &data.knockouts );
131 vector *relation_delete(relation *r,tuple *item) {
133 (void) knockout_clear( &data, r, item, 0 );
134 if ( data.knockouts.size > 0 ) {
135 return vector_clone( single_index_level, &data.knockouts );
140 void *relation_next(relation *r,vector_index *index,tuple *query) {
141 return hashvector_next( &r->content, index, query );