+ // 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;