aa4bdbd4387d1df15a07a234f566dd52d9b0db77
[rrq/rrqmisc.git] / vector / RelationQuery.c
1 #include <stdarg.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <RelationQuery.h>
5
6 // Release any memory.
7 static void RelationQuery_reclaim(Query *this) {
8     RelationQuery *q = (RelationQuery*) this;
9     free( q->saved );
10     free( this );
11 }
12
13 // Make names have given values and return 1. If any name has a
14 // different value then return 0. Values are strings.
15 static int RelationQuery_next(
16     Query *this,BindingTable *bt,enum NextState state) {
17     RelationQuery *q = (RelationQuery*) this;
18     VectorIndex index = q->index + 1;
19     switch ( state ) {
20     case initial:
21         if ( q->saved == 0 ) {
22             q->saved = Tuple_clone( q->names );
23         } else {
24             memcpy( q->saved, q->names, q->names->size * sizeof( void* ) );
25         }
26         BindingTable_deref( bt, q->saved );
27         index = 0;
28         // Fall through
29     case subsequent:
30         for ( ; index < q->rel->content.table.size; index++ ) {
31             Tuple *values = Relation_next( q->rel, &index, q->values );
32             if ( values ) {
33                 q->index = index;
34                 BindingTable_set_all( bt, q->names, values, 1 );
35                 return 1;
36             }
37         }
38     case restore:
39         if ( q->saved ) {
40             BindingTable_set_all( bt, q->names, q->saved, 1 );
41             free( q->saved );
42             q->saved = 0;
43         }
44         return 0;
45     }
46     return 0;
47 }
48
49 static void RelationQuery_variables(Query *this,HashVector *hv) {
50     RelationQuery *q = (RelationQuery*) this;
51     unsigned long i;
52     for ( i = 0; i < q->names->size; i++ ) {
53         HashVector_add( hv, q->names->elements[i] );
54     }
55 }
56
57 static struct QueryCallbacks RelationQuery_def = {
58     .reclaim = RelationQuery_reclaim,
59     .next = RelationQuery_next,
60     .variables = RelationQuery_variables
61 };
62
63 /**
64  * Return a Query object representing an Relation of one or more
65  * variables.
66  */
67 Query *Query_relation(Relation *r,Tuple *names,Tuple *values) {
68     RelationQuery *q = (RelationQuery*) malloc( sizeof( RelationQuery ) );
69     (*q) = (RelationQuery) {
70         .def = &RelationQuery_def,
71         .rel = r,
72         .names = names,
73         .values = values,
74         .saved = 0
75     };
76     return (Query*) q;
77 }
78