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