1 /*
2  * Copyright (c) 2014 Jerry Lundström <lundstrom.jerry@gmail.com>
3  * Copyright (c) 2014 .SE (The Internet Infrastructure Foundation).
4  * Copyright (c) 2014 OpenDNSSEC AB (svb)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #include "db_result.h"
31 #include "db_error.h"
32 
33 
34 /* DB RESULT */
35 
36 
37 
db_result_new(void)38 db_result_t* db_result_new(void) {
39     db_result_t* result =
40         (db_result_t*)calloc(1, sizeof(db_result_t));
41 
42     return result;
43 }
44 
45 /* TODO: unit test */
db_result_new_copy(const db_result_t * from_result)46 db_result_t* db_result_new_copy(const db_result_t* from_result) {
47     db_result_t* result;
48 
49     if (!from_result) {
50         return NULL;
51     }
52 
53     if ((result = db_result_new())) {
54         if (db_result_copy(result, from_result)) {
55             db_result_free(result);
56             return NULL;
57         }
58     }
59 
60     return result;
61 }
62 
db_result_free(db_result_t * result)63 void db_result_free(db_result_t* result) {
64     if (result) {
65         if (result->value_set) {
66             db_value_set_free(result->value_set);
67         }
68         free(result);
69     }
70 }
71 
72 /* TODO: unit test */
db_result_copy(db_result_t * result,const db_result_t * from_result)73 int db_result_copy(db_result_t* result, const db_result_t* from_result) {
74     db_value_set_t* value_set = NULL;
75 
76     if (!result) {
77         return DB_ERROR_UNKNOWN;
78     }
79     if (!from_result) {
80         return DB_ERROR_UNKNOWN;
81     }
82 
83     if (from_result->value_set
84         && !(value_set = db_value_set_new_copy(from_result->value_set)))
85     {
86         return DB_ERROR_UNKNOWN;
87     }
88 
89     if (result->value_set) {
90         db_value_set_free(result->value_set);
91     }
92     result->value_set = value_set;
93 
94     return DB_OK;
95 }
96 
db_result_value_set(const db_result_t * result)97 const db_value_set_t* db_result_value_set(const db_result_t* result) {
98     if (!result) {
99         return NULL;
100     }
101 
102     return result->value_set;
103 }
104 
db_result_set_value_set(db_result_t * result,db_value_set_t * value_set)105 int db_result_set_value_set(db_result_t* result, db_value_set_t* value_set) {
106     if (!result) {
107         return DB_ERROR_UNKNOWN;
108     }
109     if (!value_set) {
110         return DB_ERROR_UNKNOWN;
111     }
112     if (result->value_set) {
113         return DB_ERROR_UNKNOWN;
114     }
115 
116     result->value_set = value_set;
117     return DB_OK;
118 }
119 
db_result_not_empty(const db_result_t * result)120 int db_result_not_empty(const db_result_t* result) {
121     if (!result) {
122         return DB_ERROR_UNKNOWN;
123     }
124     if (!result->value_set) {
125         return DB_ERROR_UNKNOWN;
126     }
127     return DB_OK;
128 }
129 
130 /* DB RESULT LIST */
131 
132 
133 
db_result_list_new(void)134 db_result_list_t* db_result_list_new(void) {
135     db_result_list_t* result_list =
136         (db_result_list_t*)calloc(1, sizeof(db_result_list_t));
137 
138     return result_list;
139 }
140 
141 /* TODO: unit test */
db_result_list_new_copy(const db_result_list_t * from_result_list)142 db_result_list_t* db_result_list_new_copy(const db_result_list_t* from_result_list) {
143     db_result_list_t* result_list;
144 
145     if (!from_result_list) {
146         return NULL;
147     }
148 
149     result_list = (db_result_list_t*)calloc(1, sizeof(db_result_list_t));
150     if (result_list) {
151         if (db_result_list_copy(result_list, from_result_list)) {
152             db_result_list_free(result_list);
153             return NULL;
154         }
155     }
156 
157     return result_list;
158 }
159 
db_result_list_free(db_result_list_t * result_list)160 void db_result_list_free(db_result_list_t* result_list) {
161     if (result_list) {
162         if (result_list->begin) {
163             db_result_t* this = result_list->begin;
164             db_result_t* next = NULL;
165 
166             while (this) {
167                 next = this->next;
168                 db_result_free(this);
169                 this = next;
170             }
171         }
172         if (result_list->next_function) {
173             (void)result_list->next_function(result_list->next_data, 1);
174             if (result_list->current) {
175                 db_result_free(result_list->current);
176             }
177         }
178         free(result_list);
179     }
180 }
181 
182 /* TODO: unit test */
db_result_list_copy(db_result_list_t * result_list,const db_result_list_t * from_result_list)183 int db_result_list_copy(db_result_list_t* result_list, const db_result_list_t* from_result_list) {
184     db_result_t* result;
185     db_result_t* result_copy;
186 
187     if (!result_list) {
188         return DB_ERROR_UNKNOWN;
189     }
190     /*
191      * TODO: Should we be able to copy into a result list that already contains
192      * data?
193      */
194     if (result_list->begin) {
195         return DB_ERROR_UNKNOWN;
196     }
197     if (result_list->end) {
198         return DB_ERROR_UNKNOWN;
199     }
200     if (result_list->current) {
201         return DB_ERROR_UNKNOWN;
202     }
203     if (result_list->size) {
204         return DB_ERROR_UNKNOWN;
205     }
206     if (result_list->next_function) {
207         return DB_ERROR_UNKNOWN;
208     }
209     if (!from_result_list) {
210         return DB_ERROR_UNKNOWN;
211     }
212     if (from_result_list->next_function) {
213         return DB_ERROR_UNKNOWN;
214     }
215 
216     result = from_result_list->begin;
217     while (result) {
218         if (!(result_copy = db_result_new_copy(result))
219             || db_result_list_add(result_list, result_copy))
220         {
221             return DB_ERROR_UNKNOWN;
222         }
223 
224         if (result == from_result_list->current) {
225             result_list->current = result_copy;
226         }
227 
228         result = result->next;
229     }
230 
231     return DB_OK;
232 }
233 
db_result_list_set_next(db_result_list_t * result_list,db_result_list_next_t next_function,void * next_data,size_t size)234 int db_result_list_set_next(db_result_list_t* result_list, db_result_list_next_t next_function, void* next_data, size_t size) {
235     if (!result_list) {
236         return DB_ERROR_UNKNOWN;
237     }
238     if (result_list->begin) {
239         return DB_ERROR_UNKNOWN;
240     }
241     if (result_list->next_function) {
242         return DB_ERROR_UNKNOWN;
243     }
244     if (!next_data) {
245         return DB_ERROR_UNKNOWN;
246     }
247     if (result_list->next_data) {
248         return DB_ERROR_UNKNOWN;
249     }
250 
251     result_list->next_function = next_function;
252     result_list->next_data = next_data;
253     result_list->size = size;
254     return 0;
255 }
256 
db_result_list_add(db_result_list_t * result_list,db_result_t * result)257 int db_result_list_add(db_result_list_t* result_list, db_result_t* result) {
258     if (!result_list) {
259         return DB_ERROR_UNKNOWN;
260     }
261     if (!result) {
262         return DB_ERROR_UNKNOWN;
263     }
264     if (db_result_not_empty(result)) {
265         return DB_ERROR_UNKNOWN;
266     }
267     if (result->next) {
268         return DB_ERROR_UNKNOWN;
269     }
270     if (result_list->next_function) {
271         return DB_ERROR_UNKNOWN;
272     }
273 
274     if (result_list->begin) {
275         if (!result_list->end) {
276             return DB_ERROR_UNKNOWN;
277         }
278         result_list->end->next = result;
279         result_list->end = result;
280     }
281     else {
282         result_list->begin = result;
283         result_list->end = result;
284     }
285     result_list->size++;
286 
287     return DB_OK;
288 }
289 
db_result_list_begin(db_result_list_t * result_list)290 const db_result_t* db_result_list_begin(db_result_list_t* result_list) {
291     if (!result_list) {
292         return NULL;
293     }
294     if (result_list->next_function) {
295         /*
296          * Can not start over a list that uses next function
297          */
298         if (result_list->current) {
299             return NULL;
300         }
301         result_list->current = result_list->next_function(result_list->next_data, 0);
302         return result_list->current;
303     }
304 
305     result_list->current = result_list->begin;
306     result_list->begun = 1;
307     return result_list->current;
308 }
309 
db_result_list_next(db_result_list_t * result_list)310 const db_result_t* db_result_list_next(db_result_list_t* result_list) {
311     if (!result_list) {
312         return NULL;
313     }
314 
315     if (result_list->next_function) {
316         if (result_list->current) {
317             db_result_free(result_list->current);
318         }
319         result_list->current = result_list->next_function(result_list->next_data, 0);
320         return result_list->current;
321     }
322 
323     if (!result_list->begun) {
324         result_list->begun = 1;
325         result_list->current = result_list->begin;
326     }
327     else if (result_list->current) {
328         result_list->current = result_list->current->next;
329     }
330     return result_list->current;
331 }
332 
db_result_list_size(const db_result_list_t * result_list)333 size_t db_result_list_size(const db_result_list_t* result_list) {
334     if (!result_list) {
335         return 0;
336     }
337 
338     return result_list->size;
339 }
340 
db_result_list_fetch_all(db_result_list_t * result_list)341 int db_result_list_fetch_all(db_result_list_t* result_list) {
342     db_result_t* result;
343     db_result_list_next_t next_function;
344 
345     if (!result_list) {
346         return DB_ERROR_UNKNOWN;
347     }
348 
349     if (result_list->next_function) {
350         if (result_list->current) {
351             return DB_ERROR_UNKNOWN;
352         }
353 
354         next_function = result_list->next_function;
355         result_list->next_function = NULL;
356         result_list->size = 0;
357 
358         while ((result = next_function(result_list->next_data, 0))) {
359             if (db_result_list_add(result_list, result)) {
360                 next_function(result_list->next_data, 1);
361                 result_list->next_data = NULL;
362                 db_result_free(result);
363                 return DB_ERROR_UNKNOWN;
364             }
365         }
366         next_function(result_list->next_data, 1);
367         result_list->next_data = NULL;
368     }
369 
370     return DB_OK;
371 }
372