1
2 /* Module: tuplelist.c
3 *
4 * Description: This module contains functions for creating a manual result set
5 * (the TupleList) and retrieving data from it for a specific row/column.
6 *
7 * Classes: TupleListClass (Functions prefix: "TL_")
8 *
9 * API functions: none
10 *
11 * Comments: See "notice.txt" for copyright and license information.
12 *
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18
19 #include <stdlib.h>
20 #include "tuplelist.h"
21 #include "tuple.h"
22
23 TupleListClass *
TL_Constructor(UInt4 fieldcnt)24 TL_Constructor(UInt4 fieldcnt)
25 {
26 TupleListClass *rv;
27
28 mylog("in TL_Constructor\n");
29
30 rv = (TupleListClass *) malloc(sizeof(TupleListClass));
31 if (rv) {
32
33 rv->num_fields = fieldcnt;
34 rv->num_tuples = 0;
35 rv->list_start = NULL;
36 rv->list_end = NULL;
37 rv->lastref = NULL;
38 rv->last_indexed = -1;
39 }
40
41 mylog("exit TL_Constructor\n");
42
43 return rv;
44 }
45
46 void
TL_Destructor(TupleListClass * self)47 TL_Destructor(TupleListClass *self)
48 {
49 int lf;
50 TupleNode *node, *tp;
51
52 mylog("TupleList: in DESTRUCTOR\n");
53
54 node = self->list_start;
55 while(node != NULL) {
56 for (lf=0; lf < self->num_fields; lf++)
57 if (node->tuple[lf].value != NULL) {
58 free(node->tuple[lf].value);
59 }
60 tp = node->next;
61 free(node);
62 node = tp;
63 }
64
65 free(self);
66
67 mylog("TupleList: exit DESTRUCTOR\n");
68 }
69
70
71 void *
TL_get_fieldval(TupleListClass * self,Int4 tupleno,Int2 fieldno)72 TL_get_fieldval(TupleListClass *self, Int4 tupleno, Int2 fieldno)
73 {
74 Int4 lf;
75 Int4 delta, from_end;
76 char end_is_closer, start_is_closer;
77 TupleNode *rv;
78
79 if (self->last_indexed == -1)
80 /* we have an empty tuple list */
81 return NULL;
82
83 /* some more sanity checks */
84 if ((tupleno >= self->num_tuples) || (tupleno < 0))
85 /* illegal tuple number range */
86 return NULL;
87
88 if ((fieldno >= self->num_fields) || (fieldno < 0))
89 /* illegel field number range */
90 return NULL;
91
92 /* check if we are accessing the same tuple that was used in
93 the last fetch (e.g: for fetching all the fields one after
94 another. Do this to speed things up
95 */
96 if (tupleno == self->last_indexed)
97 return self->lastref->tuple[fieldno].value;
98
99 /* now for the tricky part... */
100
101 /*
102 Since random access is quite inefficient for linked lists we use
103 the lastref pointer that points to the last element referenced
104 by a get_fieldval() call in conjunction with the its index number
105 that is stored in last_indexed. (So we use some locality of
106 reference principle to speed things up)
107 */
108
109 delta = tupleno - self->last_indexed;
110 /* if delta is positive, we have to go forward */
111
112 /* now check if we are closer to the start or the end of the list
113 than to our last_indexed pointer
114 */
115 from_end = (self->num_tuples - 1) - tupleno;
116
117 start_is_closer = labs(delta) > tupleno;
118 /* true if we are closer to the start of the list than to the
119 last_indexed pointer
120 */
121
122 end_is_closer = labs(delta) > from_end;
123 /* true if we are closer at the end of the list */
124
125 if (end_is_closer) {
126 /* scanning from the end is the shortest way. so we do that... */
127 rv = self->list_end;
128 for (lf=0; lf < from_end; lf++)
129 rv = rv->prev;
130 } else if (start_is_closer) {
131 /* the shortest way is to start the search from the head of the list */
132 rv = self->list_start;
133 for (lf=0; lf < tupleno; lf++)
134 rv = rv->next;
135 } else {
136 /* the closest way is starting from our lastref - pointer */
137 rv = self->lastref;
138 /* at first determine whether we have to search forward or backwards */
139 if (delta < 0) {
140 /* we have to search backwards */
141 for(lf=0; lf < (-1)*delta; lf++)
142 rv = rv->prev;
143 } else {
144 /* ok, we have to search forward... */
145 for (lf=0; lf < delta; lf++)
146 rv = rv->next;
147 }
148 }
149
150 /* now we have got our return pointer, so update the lastref
151 and the last_indexed values
152 */
153 self->lastref = rv;
154 self->last_indexed = tupleno;
155
156 return rv->tuple[fieldno].value;
157 }
158
159
160
161 char
TL_add_tuple(TupleListClass * self,TupleNode * new_field)162 TL_add_tuple(TupleListClass *self, TupleNode *new_field)
163 {
164 /* we append the tuple at the end of the doubly linked list
165 of the tuples we have already read in
166 */
167
168 new_field->prev = NULL;
169 new_field->next = NULL;
170
171 if (self->list_start == NULL) {
172 /* the list is empty, we have to add the first tuple */
173 self->list_start = new_field;
174 self->list_end = new_field;
175 self->lastref = new_field;
176 self->last_indexed = 0;
177 } else {
178 /* there is already an element in the list, so add the new
179 one at the end of the list
180 */
181 self->list_end->next = new_field;
182 new_field->prev = self->list_end;
183 self->list_end = new_field;
184 }
185 self->num_tuples++;
186
187 /* this method of building a list cannot fail, so we return 1 */
188 return 1;
189 }
190
191
192