1 /*
2  * libdbi - database independent abstraction layer for C.
3  * Copyright (C) 2001-2003, David Parker and Mark Tobenkin.
4  * http://libdbi.sourceforge.net
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * $Id: dbi_result.c,v 1.57 2013/01/08 23:54:30 mhoenicka Exp $
21  *
22  * (anything that has to do with row seeking or fetching fields goes in this file)
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #ifdef HAVE_UNISTD_H
34   #include <unistd.h>
35 #endif
36 #include <math.h>
37 #include <limits.h>
38 #include <time.h>
39 
40 #include <dbi/dbi.h>
41 #include <dbi/dbi-dev.h>
42 
43 #ifdef __MINGW32__
44 #warning "Using the thread-unsafe strtok function!"
45 #define strtok_r(s1,s2,s3) strtok(s1,s2)
46 #endif
47 
48 // cast the opaque parameter to our struct pointer
49 #define RESULT ((dbi_result_t*)Result)
50 
51 /* declarations for internal functions -- anything declared as static won't be accessible by name from client programs */
52 static _field_binding_t *_find_or_create_binding_node(dbi_result_t *result, const char *fieldname);
53 static void _remove_binding_node(dbi_result_t *result, _field_binding_t *deadbinding);
54 static unsigned int _find_field(dbi_result_t *result, const char *fieldname, dbi_error_flag* errflag);
55 static int _is_row_fetched(dbi_result_t *result, unsigned long long row);
56 static int _setup_binding(dbi_result_t *result, const char *fieldname, void *bindto, void *helperfunc);
57 static void _activate_bindings(dbi_result_t *result);
58 static unsigned int _parse_field_formatstr(const char *format, char ***tokens_dest, char ***fieldnames_dest);
59 static void _free_string_list(char **ptrs, int total);
60 static void _free_result_rows(dbi_result_t *result);
61 int _disjoin_from_conn(dbi_result_t *result);
62 
63 static void _bind_helper_char(_field_binding_t *binding);
64 static void _bind_helper_uchar(_field_binding_t *binding);
65 static void _bind_helper_short(_field_binding_t *binding);
66 static void _bind_helper_ushort(_field_binding_t *binding);
67 static void _bind_helper_int(_field_binding_t *binding);
68 static void _bind_helper_uint(_field_binding_t *binding);
69 static void _bind_helper_longlong(_field_binding_t *binding);
70 static void _bind_helper_ulonglong(_field_binding_t *binding);
71 static void _bind_helper_float(_field_binding_t *binding);
72 static void _bind_helper_double(_field_binding_t *binding);
73 static void _bind_helper_string(_field_binding_t *binding);
74 static void _bind_helper_binary(_field_binding_t *binding);
75 static void _bind_helper_string_copy(_field_binding_t *binding);
76 static void _bind_helper_binary_copy(_field_binding_t *binding);
77 static void _bind_helper_datetime(_field_binding_t *binding);
78 
79 /* XXX ROW SEEKING AND FETCHING XXX */
80 
81 /* returns 1 if ok, 0 on error */
dbi_result_seek_row(dbi_result Result,unsigned long long rowidx)82 int dbi_result_seek_row(dbi_result Result, unsigned long long rowidx) {
83   int retval;
84 
85   if (!RESULT) {
86     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
87     return 0;
88   }
89 
90   _reset_conn_error(RESULT->conn);
91 
92   if (RESULT->result_state == NOTHING_RETURNED
93       || rowidx <= 0 || rowidx > RESULT->numrows_matched) {
94     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
95     return 0;
96   }
97 
98   if (_is_row_fetched(RESULT, rowidx) == 1) {
99     /* jump right to it */
100     RESULT->currowidx = rowidx;
101     _activate_bindings(RESULT);
102     return 1;
103   }
104 
105   /* row is one-based for the user, but zero-based to the dbd conn */
106   retval = RESULT->conn->driver->functions->goto_row(RESULT, rowidx-1, RESULT->currowidx-1);
107   if (retval == -1) {
108     _error_handler(RESULT->conn, DBI_ERROR_DBD);
109     return 0;
110   }
111   retval = RESULT->conn->driver->functions->fetch_row(RESULT, rowidx-1);
112   if (retval == 0) {
113     _error_handler(RESULT->conn, DBI_ERROR_DBD);
114     return 0;
115   }
116 
117   RESULT->currowidx = rowidx;
118   _activate_bindings(RESULT);
119   return retval;
120 }
121 
dbi_result_first_row(dbi_result Result)122 int dbi_result_first_row(dbi_result Result) {
123   return dbi_result_seek_row(Result, 1);
124 }
125 
dbi_result_last_row(dbi_result Result)126 int dbi_result_last_row(dbi_result Result) {
127   return dbi_result_seek_row(Result, dbi_result_get_numrows(Result));
128 }
129 
dbi_result_has_prev_row(dbi_result Result)130 int dbi_result_has_prev_row(dbi_result Result) {
131   if (!RESULT) {
132     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
133     return 0;
134   }
135 
136   _reset_conn_error(RESULT->conn);
137 
138   return RESULT->result_state != NOTHING_RETURNED && RESULT->currowidx > 1;
139 }
140 
dbi_result_prev_row(dbi_result Result)141 int dbi_result_prev_row(dbi_result Result) {
142   if (!RESULT) {
143     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
144     return 0;
145   }
146 
147   _reset_conn_error(RESULT->conn);
148 
149   if (!dbi_result_has_prev_row(Result)) {
150     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
151     return 0;
152   }
153   return dbi_result_seek_row(Result, RESULT->currowidx-1);
154 }
155 
dbi_result_has_next_row(dbi_result Result)156 int dbi_result_has_next_row(dbi_result Result) {
157   if (!RESULT) {
158     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
159     return 0;
160   }
161 
162   _reset_conn_error(RESULT->conn);
163 
164   return RESULT->result_state != NOTHING_RETURNED
165   		 && RESULT->currowidx < dbi_result_get_numrows(Result);
166 }
167 
dbi_result_next_row(dbi_result Result)168 int dbi_result_next_row(dbi_result Result) {
169   if (!RESULT) {
170     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
171     return 0;
172   }
173 
174   _reset_conn_error(RESULT->conn);
175 
176   if (!dbi_result_has_next_row(Result)) {
177 /*     _error_handler(RESULT->conn, DBI_ERROR_BADIDX); */
178     return 0;
179   }
180   return dbi_result_seek_row(Result, RESULT->currowidx+1);
181 }
182 
dbi_result_get_currow(dbi_result Result)183 unsigned long long dbi_result_get_currow(dbi_result Result) {
184   if (!RESULT) {
185     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
186     return 0;
187   }
188 
189   _reset_conn_error(RESULT->conn);
190 
191   return RESULT->currowidx;
192 }
193 
dbi_result_get_numrows(dbi_result Result)194 unsigned long long dbi_result_get_numrows(dbi_result Result) {
195   if (!RESULT) {
196     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
197     return DBI_ROW_ERROR;
198   }
199 
200   _reset_conn_error(RESULT->conn);
201 
202   return RESULT->numrows_matched;
203 }
204 
dbi_result_get_numrows_affected(dbi_result Result)205 unsigned long long dbi_result_get_numrows_affected(dbi_result Result) {
206   if (!RESULT) {
207     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
208     return DBI_ROW_ERROR;
209   }
210 
211   _reset_conn_error(RESULT->conn);
212 
213   return RESULT->numrows_affected;
214 }
215 
216 /* returns the length of the string or binary, excluding a trailing \0 */
dbi_result_get_field_length(dbi_result Result,const char * fieldname)217 size_t dbi_result_get_field_length(dbi_result Result, const char *fieldname) {
218   unsigned int fieldidx = 0;
219   dbi_error_flag errflag = DBI_ERROR_NONE;
220 
221   if (!RESULT) {
222     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
223     return DBI_LENGTH_ERROR;
224   }
225 
226   _reset_conn_error(RESULT->conn);
227 
228   fieldidx = _find_field(RESULT, fieldname, &errflag);
229   if (errflag != DBI_ERROR_NONE) {
230     _error_handler(RESULT->conn, errflag);
231     return DBI_LENGTH_ERROR;
232   }
233 
234   return dbi_result_get_field_length_idx(Result, fieldidx+1);
235 }
236 
dbi_result_get_field_length_idx(dbi_result Result,unsigned int fieldidx)237 size_t dbi_result_get_field_length_idx(dbi_result Result, unsigned int fieldidx) {
238   unsigned long long currowidx;
239 
240   /* user-visible indexes start at 1 */
241   fieldidx--;
242 
243   if (!RESULT || !RESULT->rows) {
244     _error_handler(RESULT ? RESULT->conn : NULL, DBI_ERROR_BADPTR);
245     return DBI_LENGTH_ERROR;
246   }
247 
248   _reset_conn_error(RESULT->conn);
249 
250   currowidx = RESULT->currowidx;
251   if (!RESULT->rows[currowidx] || !RESULT->rows[currowidx]->field_sizes) {
252     _error_handler(RESULT->conn, DBI_ERROR_BADOBJECT);
253     return DBI_LENGTH_ERROR;
254   }
255   if (fieldidx >= RESULT->numfields) {
256     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
257     return DBI_LENGTH_ERROR;
258   }
259 
260   return RESULT->rows[currowidx]->field_sizes[fieldidx];
261 }
262 
263 /* the "field_size" functions are merely kept to support legacy
264    code. Their purpose was, er, unclear, their implementations were,
265    er, broke, and the name "field_length" is more appropriate to what
266    these functions do anyway. Support for the "field_size" functions
267    is likely to be dropped in the next release */
dbi_result_get_field_size(dbi_result Result,const char * fieldname)268 size_t dbi_result_get_field_size(dbi_result Result, const char *fieldname) {
269   return dbi_result_get_field_length(Result, fieldname);
270 }
271 
dbi_result_get_field_size_idx(dbi_result Result,unsigned int fieldidx)272 size_t dbi_result_get_field_size_idx(dbi_result Result, unsigned int fieldidx) {
273   return dbi_result_get_field_length_idx(Result, fieldidx);
274 }
275 
dbi_result_get_field_idx(dbi_result Result,const char * fieldname)276 unsigned int dbi_result_get_field_idx(dbi_result Result, const char *fieldname) {
277   unsigned int fieldidx = 0;
278   dbi_error_flag errflag = DBI_ERROR_NONE;
279 
280   if (!RESULT) {
281     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
282     return 0;
283   }
284 
285   _reset_conn_error(RESULT->conn);
286 
287   /* user-visible indexes start at 1 */
288   fieldidx = _find_field(RESULT, fieldname, &errflag)+1;
289   if (errflag != DBI_ERROR_NONE) {
290     _error_handler(RESULT->conn, errflag);
291     return 0;
292   }
293 
294   return fieldidx;
295 }
296 
dbi_result_get_field_name(dbi_result Result,unsigned int fieldidx)297 const char *dbi_result_get_field_name(dbi_result Result, unsigned int fieldidx) {
298 
299   if (!RESULT) {
300     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
301     return NULL;
302   }
303 
304   _reset_conn_error(RESULT->conn);
305 
306   if (fieldidx > RESULT->numfields) {
307     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
308     return NULL;
309   }
310   else if (RESULT->field_names == NULL) {
311     _error_handler(RESULT->conn, DBI_ERROR_BADOBJECT);
312     return NULL;
313   }
314 
315   return (const char *) RESULT->field_names[fieldidx-1];
316 }
317 
dbi_result_get_numfields(dbi_result Result)318 unsigned int dbi_result_get_numfields(dbi_result Result) {
319   if (!RESULT) return DBI_FIELD_ERROR;
320 
321   _reset_conn_error(RESULT->conn);
322 
323   return RESULT->numfields;
324 }
325 
dbi_result_get_field_type(dbi_result Result,const char * fieldname)326 unsigned short dbi_result_get_field_type(dbi_result Result, const char *fieldname) {
327   unsigned int fieldidx = 0;
328   dbi_error_flag errflag = DBI_ERROR_NONE;
329 
330   if (!RESULT) {
331     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
332     return DBI_TYPE_ERROR;
333   }
334 
335   _reset_conn_error(RESULT->conn);
336 
337   fieldidx = _find_field(RESULT, fieldname, &errflag);
338   if (errflag != DBI_ERROR_NONE) {
339     _error_handler(RESULT->conn, errflag);
340     return DBI_TYPE_ERROR;
341   }
342 
343   return dbi_result_get_field_type_idx(Result, fieldidx+1);
344 }
345 
dbi_result_get_field_type_idx(dbi_result Result,unsigned int fieldidx)346 unsigned short dbi_result_get_field_type_idx(dbi_result Result, unsigned int fieldidx) {
347   fieldidx--;
348 
349   if (!RESULT) {
350     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
351     return DBI_TYPE_ERROR;
352   }
353 
354   _reset_conn_error(RESULT->conn);
355 
356   if (!RESULT->field_types) {
357     _error_handler(RESULT->conn, DBI_ERROR_BADOBJECT);
358     return DBI_TYPE_ERROR;
359   }
360   else if (fieldidx >= RESULT->numfields) {
361     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
362     return DBI_TYPE_ERROR;
363   }
364 
365   return RESULT->field_types[fieldidx];
366 }
367 
dbi_result_get_field_attrib(dbi_result Result,const char * fieldname,unsigned int attribmin,unsigned int attribmax)368 unsigned int dbi_result_get_field_attrib(dbi_result Result, const char *fieldname, unsigned int attribmin, unsigned int attribmax) {
369   unsigned int fieldidx = 0;
370   dbi_error_flag errflag = DBI_ERROR_NONE;
371 
372   if (!RESULT) {
373     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
374     return DBI_ATTRIBUTE_ERROR;
375   }
376 
377   _reset_conn_error(RESULT->conn);
378 
379   fieldidx = _find_field(RESULT, fieldname, &errflag);
380   if (errflag != DBI_ERROR_NONE) {
381     _error_handler(RESULT->conn, errflag);
382     return DBI_ATTRIBUTE_ERROR;
383   }
384 
385   return dbi_result_get_field_attrib_idx(Result, fieldidx+1, attribmin, attribmax);
386 }
387 
dbi_result_get_field_attrib_idx(dbi_result Result,unsigned int fieldidx,unsigned int attribmin,unsigned int attribmax)388 unsigned int dbi_result_get_field_attrib_idx(dbi_result Result,
389 		unsigned int fieldidx, unsigned int attribmin, unsigned int attribmax) {
390   fieldidx--;
391 
392   if (!RESULT) {
393     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
394     return DBI_ATTRIBUTE_ERROR;
395   }
396 
397   _reset_conn_error(RESULT->conn);
398 
399   if (!RESULT->field_attribs) {
400     _error_handler(RESULT->conn, DBI_ERROR_BADOBJECT);
401     return DBI_ATTRIBUTE_ERROR;
402   }
403   else if (fieldidx >= RESULT->numfields) {
404     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
405     return DBI_ATTRIBUTE_ERROR;
406   }
407 
408   return _isolate_attrib(RESULT->field_attribs[fieldidx], attribmin, attribmax);
409 }
410 
dbi_result_get_field_attribs(dbi_result Result,const char * fieldname)411 unsigned int dbi_result_get_field_attribs(dbi_result Result, const char *fieldname) {
412   unsigned int fieldidx = 0;
413   dbi_error_flag errflag = DBI_ERROR_NONE;
414 
415   if (!RESULT) {
416     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
417     return DBI_ATTRIBUTE_ERROR;
418   }
419 
420   _reset_conn_error(RESULT->conn);
421 
422   fieldidx = _find_field(RESULT, fieldname, &errflag);
423   if (errflag != DBI_ERROR_NONE) {
424     _error_handler(RESULT->conn, errflag);
425     return DBI_ATTRIBUTE_ERROR;
426   }
427 
428   return dbi_result_get_field_attribs_idx(Result, fieldidx+1);
429 }
430 
dbi_result_get_field_attribs_idx(dbi_result Result,unsigned int fieldidx)431 unsigned int dbi_result_get_field_attribs_idx(dbi_result Result, unsigned int fieldidx) {
432   fieldidx--;
433 
434   if (!RESULT) {
435     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
436     return DBI_ATTRIBUTE_ERROR;
437   }
438 
439   _reset_conn_error(RESULT->conn);
440 
441   if (!RESULT->field_attribs) {
442     _error_handler(RESULT->conn, DBI_ERROR_BADOBJECT);
443     return DBI_ATTRIBUTE_ERROR;
444   }
445   else if (fieldidx >= RESULT->numfields) {
446     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
447     return DBI_ATTRIBUTE_ERROR;
448   }
449 
450   return RESULT->field_attribs[fieldidx];
451 }
452 
_set_field_flag(dbi_row_t * row,unsigned int fieldidx,unsigned char flag,unsigned char value)453 void _set_field_flag(dbi_row_t *row, unsigned int fieldidx, unsigned char flag, unsigned char value) {
454   unsigned char *flags = &row->field_flags[fieldidx];
455   if (value)
456     *flags |= flag; // if value = 1, set the flag
457   else
458     *flags &= ~flag; // set that bit to 0
459 }
460 
_get_field_flag(dbi_row_t * row,unsigned int fieldidx,unsigned char flag)461 int _get_field_flag(dbi_row_t *row, unsigned int fieldidx, unsigned char flag) {
462   return (row->field_flags[fieldidx] & flag) != 0;
463 }
464 
dbi_result_field_is_null(dbi_result Result,const char * fieldname)465 int dbi_result_field_is_null(dbi_result Result, const char *fieldname) {
466   unsigned int fieldidx = 0;
467   dbi_error_flag errflag = DBI_ERROR_NONE;
468 
469   if (!RESULT) {
470     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
471     return DBI_FIELD_FLAG_ERROR;
472   }
473 
474   _reset_conn_error(RESULT->conn);
475 
476   fieldidx = _find_field(RESULT, fieldname, &errflag);
477   if (errflag != DBI_ERROR_NONE) {
478     _error_handler(RESULT->conn, errflag);
479     return DBI_FIELD_FLAG_ERROR;
480   }
481 
482   return dbi_result_field_is_null_idx(Result, fieldidx+1);
483 }
484 
dbi_result_field_is_null_idx(dbi_result Result,unsigned int fieldidx)485 int dbi_result_field_is_null_idx(dbi_result Result, unsigned int fieldidx) {
486   unsigned long long currowidx;
487 
488   fieldidx--;
489 
490   if (!RESULT || !RESULT->rows) {
491     _error_handler(RESULT ? RESULT->conn : NULL, DBI_ERROR_BADPTR);
492     return DBI_FIELD_FLAG_ERROR;
493   }
494 
495   _reset_conn_error(RESULT->conn);
496 
497   currowidx = RESULT->currowidx;
498   if (!RESULT->rows[currowidx] || !RESULT->rows[currowidx]->field_flags) {
499     _error_handler(RESULT->conn, DBI_ERROR_BADOBJECT);
500     return DBI_FIELD_FLAG_ERROR;
501   }
502   if (fieldidx >= RESULT->numfields) {
503     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
504     return DBI_FIELD_FLAG_ERROR;
505   }
506 
507   return _get_field_flag(RESULT->rows[currowidx], fieldidx, DBI_VALUE_NULL);
508 }
509 
_disjoin_from_conn(dbi_result_t * result)510 int _disjoin_from_conn(dbi_result_t *result) {
511   /* todo: is int enough? */
512   int idx;
513   int found = -1;
514   int retval;
515 
516   retval = result->conn->driver->functions->free_query(result);
517 
518   for (idx = 0; idx < result->conn->results_used; idx++) {
519     if (found < 0) {
520       /* keep looking */
521       if (result->conn->results[idx] == result) {
522         found = idx;
523         result->conn->results[idx] = NULL;
524       }
525     }
526     else {
527       /* already found, shift remaining elements back one */
528       result->conn->results[idx-1] = result->conn->results[idx];
529     }
530   }
531   if (found >= 0) {
532     result->conn->results[result->conn->results_used-1] = NULL;
533     result->conn->results_used--;
534   }
535 
536   result->conn = NULL;
537 
538   return retval;
539 }
540 
dbi_result_disjoin(dbi_result Result)541 int dbi_result_disjoin(dbi_result Result) {
542   return RESULT ? _disjoin_from_conn(RESULT) : -1;
543 }
544 
dbi_result_free(dbi_result Result)545 int dbi_result_free(dbi_result Result) {
546   int retval = 0;
547 
548   if (!RESULT) return -1;
549 
550   if (RESULT->conn) {
551     retval = _disjoin_from_conn(RESULT);
552   }
553 
554   _reset_conn_error(RESULT->conn);
555 
556   while (RESULT->field_bindings) {
557     _remove_binding_node(RESULT, RESULT->field_bindings);
558   }
559 
560   if (RESULT->rows) {
561     _free_result_rows(RESULT);
562   }
563 
564   if (RESULT->numfields) {
565     _free_string_list(RESULT->field_names, RESULT->numfields);
566     free(RESULT->field_types);
567     free(RESULT->field_attribs);
568   }
569 
570   if (retval == -1) {
571     _error_handler(RESULT->conn, DBI_ERROR_DBD);
572   }
573 
574   free(RESULT);
575   return retval;
576 }
577 
dbi_result_get_conn(dbi_result Result)578 dbi_conn dbi_result_get_conn(dbi_result Result) {
579 
580   if (!RESULT) {
581     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
582     return NULL;
583   }
584 
585   return RESULT->conn;
586 }
587 
588 /* RESULT: mass retrieval functions */
589 
_parse_field_formatstr(const char * format,char *** tokens_dest,char *** fieldnames_dest)590 static unsigned int _parse_field_formatstr(const char *format, char ***tokens_dest, char ***fieldnames_dest) {
591   unsigned int found = 0;
592   unsigned int cur = 0;
593   char **tokens = NULL;
594   char **fieldnames = NULL;
595   char *chunk;
596   char *fieldtype;
597   char *fieldname;
598   char *temp1;
599   char *temp2;
600   char *line = strdup(format);
601 
602   temp1 = line;
603   while (temp1 && (temp1 = strchr(temp1, '.')) != NULL) {
604     temp1++;
605     found++;
606   }
607 
608   tokens = calloc(found, sizeof(char *));
609   fieldnames = calloc(found, sizeof(char *));
610   if (!tokens || !fieldnames) return DBI_FIELD_ERROR;
611 
612   chunk = strtok_r(line, " ", &temp1);
613   do {
614     temp2 = strchr(chunk, '.');
615     if (!temp2) continue;
616     fieldname = chunk;
617     *temp2 = '\0';
618     fieldtype = (temp2+2); /* ignore the % */
619     tokens[cur] = strdup(fieldtype);
620     fieldnames[cur] = strdup(fieldname);
621     cur++;
622   } while ((chunk = strtok_r(NULL, " ", &temp1)));
623 
624   *tokens_dest = tokens;
625   *fieldnames_dest = fieldnames;
626 
627   free(line);
628   return found;
629 }
630 
_free_string_list(char ** ptrs,int total)631 static void _free_string_list(char **ptrs, int total) {
632   int i;
633 
634   if (ptrs == NULL) return;
635   for (i = 0; i < total; ++i)
636     if (ptrs[i]) free(ptrs[i]);
637   free(ptrs);
638   return;
639 }
640 
_free_result_rows(dbi_result_t * result)641 static void _free_result_rows(dbi_result_t *result) {
642   unsigned long long rowidx = 0;
643   unsigned int fieldidx = 0;
644 
645   for (rowidx = 0; rowidx <= result->numrows_matched; rowidx++) {
646     if (!result->rows[rowidx]) continue;
647 
648     for (fieldidx = 0; fieldidx < result->numfields; fieldidx++) {
649       if ((result->field_types[fieldidx] == DBI_TYPE_STRING
650         || result->field_types[fieldidx] == DBI_TYPE_BINARY)
651         && result->rows[rowidx]->field_values[fieldidx].d_string)
652       {
653         free(result->rows[rowidx]->field_values[fieldidx].d_string);
654       }
655     }
656 
657     free(result->rows[rowidx]->field_values);
658     free(result->rows[rowidx]->field_sizes);
659     free(result->rows[rowidx]->field_flags);
660     free(result->rows[rowidx]);
661   }
662 
663   free(result->rows);
664 }
665 
dbi_result_get_fields(dbi_result Result,const char * format,...)666 unsigned int dbi_result_get_fields(dbi_result Result, const char *format, ...) {
667   char **tokens, **fieldnames;
668   unsigned int curidx = 0, numtokens = 0, uflag;
669   va_list ap;
670 
671   if (!RESULT) return DBI_FIELD_ERROR;
672 
673   numtokens = _parse_field_formatstr(format, &tokens, &fieldnames);
674 
675   if (numtokens == DBI_FIELD_ERROR) {
676     return numtokens;
677   }
678 
679   va_start(ap, format);
680   while (curidx < numtokens) {
681     uflag = strlen(tokens[curidx]) > 1 && tokens[curidx][0] == 'u';
682     switch (tokens[curidx][strlen(tokens[curidx])-1]) {
683     case 'c': /* char */
684       if (uflag) /* unsigned */
685         *va_arg(ap, unsigned char *) = dbi_result_get_uchar(Result, fieldnames[curidx]);
686       else
687         *va_arg(ap, char *) = dbi_result_get_char(Result, fieldnames[curidx]);
688       break;
689     case 'h': /* sHort ("S"tring was taken) */
690       if (uflag) /* unsigned */
691         *va_arg(ap, unsigned short *) = dbi_result_get_ushort(Result, fieldnames[curidx]);
692       else
693         *va_arg(ap, short *) = dbi_result_get_short(Result, fieldnames[curidx]);
694       break;
695     case 'l': /* 4-byte integer (both l and i work) */
696     case 'i':
697       if (uflag) /* unsigned */
698         *va_arg(ap, unsigned int *) = dbi_result_get_uint(Result, fieldnames[curidx]);
699       else
700         *va_arg(ap, int *) = dbi_result_get_int(Result, fieldnames[curidx]);
701       break;
702     case 'L': /* long long */
703       if (uflag) /* unsigned */
704         *va_arg(ap, unsigned long long *) = dbi_result_get_ulonglong(Result, fieldnames[curidx]);
705       else
706         *va_arg(ap, long long *) = dbi_result_get_longlong(Result, fieldnames[curidx]);
707       break;
708     case 'f': /* float */
709       *va_arg(ap, float *) = dbi_result_get_float(Result, fieldnames[curidx]);
710       break;
711     case 'd': /* double */
712       *va_arg(ap, double *) = dbi_result_get_double(Result, fieldnames[curidx]);
713       break;
714     case 's': /* string */
715       *va_arg(ap, const char **) = dbi_result_get_string(Result, fieldnames[curidx]);
716       break;
717     case 'b': /* binary */
718       *va_arg(ap, const unsigned char **) = dbi_result_get_binary(Result, fieldnames[curidx]);
719       break;
720     case 'S': /* string copy */
721       *va_arg(ap, char **) = dbi_result_get_string_copy(Result, fieldnames[curidx]);
722       break;
723     case 'B': /* binary copy */
724       *va_arg(ap, unsigned char **) = dbi_result_get_binary_copy(Result, fieldnames[curidx]);
725       break;
726     case 'm': /* datetiMe (what... you have any better ideas?? */
727       *va_arg(ap, time_t *) = dbi_result_get_datetime(Result, fieldnames[curidx]);
728       break;
729     }
730     curidx++;
731   }
732   va_end(ap);
733 
734   _free_string_list(tokens, numtokens);
735   _free_string_list(fieldnames, numtokens);
736   return numtokens;
737 }
738 
dbi_result_bind_fields(dbi_result Result,const char * format,...)739 unsigned int dbi_result_bind_fields(dbi_result Result, const char *format, ...) {
740   char **tokens, **fieldnames;
741   unsigned int curidx = 0, numtokens = 0, uflag;
742   va_list ap;
743 
744   if (!RESULT) return DBI_FIELD_ERROR;
745 
746   numtokens = _parse_field_formatstr(format, &tokens, &fieldnames);
747 
748   if (numtokens == DBI_FIELD_ERROR) {
749     return numtokens;
750   }
751 
752   va_start(ap, format);
753   while (curidx < numtokens) {
754     uflag = strlen(tokens[curidx]) > 1 && tokens[curidx][0] == 'u';
755     switch (tokens[curidx][strlen(tokens[curidx])-1]) {
756     case 'c': /* char */
757       if (uflag) /* unsigned */
758         dbi_result_bind_uchar(Result, fieldnames[curidx], va_arg(ap, unsigned char *));
759       else
760         dbi_result_bind_char(Result, fieldnames[curidx], va_arg(ap, char *));
761       break;
762     case 'h': /* sHort ("S"tring was taken) */
763       if (uflag) /* unsigned */
764         dbi_result_bind_ushort(Result, fieldnames[curidx], va_arg(ap, unsigned short *));
765       else
766         dbi_result_bind_short(Result, fieldnames[curidx], va_arg(ap, short *));
767       break;
768     case 'l': /* 4-byte integer (both l and i work) */
769     case 'i':
770       if (uflag) /* unsigned */
771         dbi_result_bind_uint(Result, fieldnames[curidx], va_arg(ap, unsigned int *));
772       else
773         dbi_result_bind_int(Result, fieldnames[curidx], va_arg(ap, int *));
774       break;
775     case 'L': /* long long */
776       if (uflag) /* unsigned */
777         dbi_result_bind_ulonglong(Result, fieldnames[curidx], va_arg(ap, unsigned long long *));
778       else
779         dbi_result_bind_longlong(Result, fieldnames[curidx], va_arg(ap, long long *));
780       break;
781     case 'f': /* float */
782       dbi_result_bind_float(Result, fieldnames[curidx], va_arg(ap, float *));
783       break;
784     case 'd': /* double */
785       dbi_result_bind_double(Result, fieldnames[curidx], va_arg(ap, double *));
786       break;
787     case 's': /* string */
788       dbi_result_bind_string(Result, fieldnames[curidx], va_arg(ap, const char **));
789       break;
790     case 'b': /* binary */
791       dbi_result_bind_binary(Result, fieldnames[curidx], va_arg(ap, const unsigned char **));
792       break;
793     case 'S': /* string copy */
794       dbi_result_bind_string_copy(Result, fieldnames[curidx], va_arg(ap, char **));
795       break;
796     case 'B': /* binary copy */
797       dbi_result_bind_binary_copy(Result, fieldnames[curidx], va_arg(ap, unsigned char **));
798       break;
799     case 'm': /* datetiMe (what... you have any better ideas?? */
800       dbi_result_bind_datetime(Result, fieldnames[curidx], va_arg(ap, time_t *));
801       break;
802     }
803     curidx++;
804   }
805   va_end(ap);
806 
807   _free_string_list(tokens, numtokens);
808   _free_string_list(fieldnames, numtokens);
809   return numtokens;
810 }
811 
812 /* RESULT: get_* functions */
813 
dbi_result_get_char(dbi_result Result,const char * fieldname)814 signed char dbi_result_get_char(dbi_result Result, const char *fieldname) {
815   signed char my_ERROR = 0;
816   unsigned int fieldidx;
817   dbi_error_flag errflag = DBI_ERROR_NONE;
818 
819   _reset_conn_error(RESULT->conn);
820 
821   fieldidx = _find_field(RESULT, fieldname, &errflag);
822   if (errflag != DBI_ERROR_NONE) {
823     dbi_conn_t *conn = RESULT->conn;
824     _error_handler(conn, errflag);
825     return my_ERROR;
826   }
827   return dbi_result_get_char_idx(Result, fieldidx+1);
828 }
829 
dbi_result_get_char_idx(dbi_result Result,unsigned int fieldidx)830 signed char dbi_result_get_char_idx(dbi_result Result, unsigned int fieldidx) {
831   signed char my_ERROR = 0;
832 
833   fieldidx--;
834 
835   _reset_conn_error(RESULT->conn);
836 
837   if (fieldidx >= RESULT->numfields) {
838     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
839     return my_ERROR;
840   }
841   if (RESULT->field_types[fieldidx] != DBI_TYPE_INTEGER) {
842     _verbose_handler(RESULT->conn, "%s: field `%s` is not integer type\n",
843                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
844     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
845     return my_ERROR;
846   }
847 
848   switch (RESULT->field_attribs[fieldidx] & DBI_INTEGER_SIZEMASK) {
849   case DBI_INTEGER_SIZE1:
850     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_char;
851   case DBI_INTEGER_SIZE2:
852   case DBI_INTEGER_SIZE3:
853   case DBI_INTEGER_SIZE4:
854   case DBI_INTEGER_SIZE8:
855     _verbose_handler(RESULT->conn, "%s: field `%s` is more than 1 byte wide\n",
856                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
857   default:
858     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
859     return my_ERROR;
860   }
861 }
862 
dbi_result_get_short(dbi_result Result,const char * fieldname)863 short dbi_result_get_short(dbi_result Result, const char *fieldname) {
864   short my_ERROR = 0;
865   unsigned int fieldidx;
866   dbi_error_flag errflag = DBI_ERROR_NONE;
867 
868   _reset_conn_error(RESULT->conn);
869 
870   fieldidx = _find_field(RESULT, fieldname, &errflag);
871   if (errflag != DBI_ERROR_NONE) {
872     dbi_conn_t *conn = RESULT->conn;
873     _error_handler(conn, DBI_ERROR_BADNAME);
874     return my_ERROR;
875   }
876   return dbi_result_get_short_idx(Result, fieldidx+1);
877 }
878 
dbi_result_get_short_idx(dbi_result Result,unsigned int fieldidx)879 short dbi_result_get_short_idx(dbi_result Result, unsigned int fieldidx) {
880   short my_ERROR = 0;
881   fieldidx--;
882 
883   _reset_conn_error(RESULT->conn);
884 
885   if (fieldidx >= RESULT->numfields) {
886     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
887     return my_ERROR;
888   }
889   if (RESULT->field_types[fieldidx] != DBI_TYPE_INTEGER) {
890     _verbose_handler(RESULT->conn, "%s: field `%s` is not integer type\n",
891                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
892     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
893     return my_ERROR;
894   }
895 
896   switch (RESULT->field_attribs[fieldidx] & DBI_INTEGER_SIZEMASK) {
897   case DBI_INTEGER_SIZE1:
898     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_char;
899   case DBI_INTEGER_SIZE2:
900     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_short;
901   case DBI_INTEGER_SIZE3:
902   case DBI_INTEGER_SIZE4:
903   case DBI_INTEGER_SIZE8:
904     _verbose_handler(RESULT->conn, "%s: field `%s` is more than 2 bytes wide\n",
905                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
906   default:
907     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
908     return my_ERROR;
909   }
910 }
911 
dbi_result_get_long(dbi_result Result,const char * fieldname)912 int dbi_result_get_long(dbi_result Result, const char *fieldname) {
913   return dbi_result_get_int(Result, fieldname);
914 }
915 
dbi_result_get_int(dbi_result Result,const char * fieldname)916 int dbi_result_get_int(dbi_result Result, const char *fieldname) {
917   long my_ERROR = 0;
918   unsigned int fieldidx;
919   dbi_error_flag errflag = DBI_ERROR_NONE;
920 
921   _reset_conn_error(RESULT->conn);
922 
923   fieldidx = _find_field(RESULT, fieldname, &errflag);
924   if (errflag != DBI_ERROR_NONE) {
925     dbi_conn_t *conn = RESULT->conn;
926     _error_handler(conn, DBI_ERROR_BADNAME);
927     return my_ERROR;
928   }
929   return dbi_result_get_int_idx(Result, fieldidx+1);
930 }
931 
dbi_result_get_long_idx(dbi_result Result,unsigned int fieldidx)932 int dbi_result_get_long_idx(dbi_result Result, unsigned int fieldidx) {
933   return dbi_result_get_int_idx(Result, fieldidx);
934 }
935 
dbi_result_get_int_idx(dbi_result Result,unsigned int fieldidx)936 int dbi_result_get_int_idx(dbi_result Result, unsigned int fieldidx) {
937   long my_ERROR = 0;
938   fieldidx--;
939 
940   _reset_conn_error(RESULT->conn);
941 
942   if (fieldidx >= RESULT->numfields) {
943     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
944     return my_ERROR;
945   }
946   if (RESULT->field_types[fieldidx] != DBI_TYPE_INTEGER) {
947     _verbose_handler(RESULT->conn, "%s: field `%s` is not integer type\n",
948                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
949     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
950     return my_ERROR;
951   }
952 
953   switch (RESULT->field_attribs[fieldidx] & DBI_INTEGER_SIZEMASK) {
954   case DBI_INTEGER_SIZE1:
955     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_char;
956   case DBI_INTEGER_SIZE2:
957     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_short;
958   case DBI_INTEGER_SIZE3:
959   case DBI_INTEGER_SIZE4:
960     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_long;
961   case DBI_INTEGER_SIZE8:
962     _verbose_handler(RESULT->conn, "%s: field `%s` is more than 4 bytes wide\n",
963                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
964   default:
965     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
966     return my_ERROR;
967   }
968 }
969 
dbi_result_get_longlong(dbi_result Result,const char * fieldname)970 long long dbi_result_get_longlong(dbi_result Result, const char *fieldname) {
971   long long my_ERROR = 0;
972   unsigned int fieldidx;
973   dbi_error_flag errflag = DBI_ERROR_NONE;
974 
975   _reset_conn_error(RESULT->conn);
976 
977   fieldidx = _find_field(RESULT, fieldname, &errflag);
978   if (errflag != DBI_ERROR_NONE) {
979     dbi_conn_t *conn = RESULT->conn;
980     _error_handler(conn, DBI_ERROR_BADNAME);
981     return my_ERROR;
982   }
983   return dbi_result_get_longlong_idx(Result, fieldidx+1);
984 }
985 
dbi_result_get_longlong_idx(dbi_result Result,unsigned int fieldidx)986 long long dbi_result_get_longlong_idx(dbi_result Result, unsigned int fieldidx) {
987   long long my_ERROR = 0;
988   fieldidx--;
989 
990   _reset_conn_error(RESULT->conn);
991 
992   if (fieldidx >= RESULT->numfields) {
993     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
994     return my_ERROR;
995   }
996   if (RESULT->field_types[fieldidx] != DBI_TYPE_INTEGER) {
997     _verbose_handler(RESULT->conn, "%s: field `%s` is not integer type\n",
998                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
999     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1000     return my_ERROR;
1001   }
1002 
1003   switch (RESULT->field_attribs[fieldidx] & DBI_INTEGER_SIZEMASK) {
1004   case DBI_INTEGER_SIZE1:
1005     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_char;
1006   case DBI_INTEGER_SIZE2:
1007     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_short;
1008   case DBI_INTEGER_SIZE3:
1009   case DBI_INTEGER_SIZE4:
1010     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_long;
1011   case DBI_INTEGER_SIZE8:
1012     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_longlong;
1013   default:
1014     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1015     return my_ERROR;
1016   }
1017 }
1018 
dbi_result_get_uchar(dbi_result Result,const char * fieldname)1019 unsigned char dbi_result_get_uchar(dbi_result Result, const char *fieldname) {
1020   return (unsigned char)dbi_result_get_char(Result, fieldname);
1021 }
1022 
dbi_result_get_uchar_idx(dbi_result Result,unsigned int fieldidx)1023 unsigned char dbi_result_get_uchar_idx(dbi_result Result, unsigned int fieldidx) {
1024   return (unsigned char)dbi_result_get_char_idx(Result, fieldidx);
1025 }
1026 
dbi_result_get_ushort(dbi_result Result,const char * fieldname)1027 unsigned short dbi_result_get_ushort(dbi_result Result, const char *fieldname) {
1028   return (unsigned short)dbi_result_get_short(Result, fieldname);
1029 }
1030 
dbi_result_get_ushort_idx(dbi_result Result,unsigned int fieldidx)1031 unsigned short dbi_result_get_ushort_idx(dbi_result Result, unsigned int fieldidx) {
1032   return (unsigned short)dbi_result_get_short_idx(Result, fieldidx);
1033 }
1034 
dbi_result_get_uint(dbi_result Result,const char * fieldname)1035 unsigned int dbi_result_get_uint(dbi_result Result, const char *fieldname) {
1036   return (unsigned int)dbi_result_get_int(Result, fieldname);
1037 }
1038 
dbi_result_get_ulong(dbi_result Result,const char * fieldname)1039 unsigned int dbi_result_get_ulong(dbi_result Result, const char *fieldname) {
1040   return dbi_result_get_uint(Result, fieldname);
1041 }
1042 
dbi_result_get_uint_idx(dbi_result Result,unsigned int fieldidx)1043 unsigned int dbi_result_get_uint_idx(dbi_result Result, unsigned int fieldidx) {
1044   return (unsigned int)dbi_result_get_int_idx(Result, fieldidx);
1045 }
1046 
dbi_result_get_ulong_idx(dbi_result Result,unsigned int fieldidx)1047 unsigned int dbi_result_get_ulong_idx(dbi_result Result, unsigned int fieldidx) {
1048   return dbi_result_get_uint_idx(Result, fieldidx);
1049 }
1050 
dbi_result_get_ulonglong(dbi_result Result,const char * fieldname)1051 unsigned long long dbi_result_get_ulonglong(dbi_result Result, const char *fieldname) {
1052   return (unsigned long long)dbi_result_get_longlong(Result, fieldname);
1053 }
1054 
dbi_result_get_ulonglong_idx(dbi_result Result,unsigned int fieldidx)1055 unsigned long long dbi_result_get_ulonglong_idx(dbi_result Result, unsigned int fieldidx) {
1056   return (unsigned long long)dbi_result_get_longlong_idx(Result, fieldidx);
1057 }
1058 
dbi_result_get_float(dbi_result Result,const char * fieldname)1059 float dbi_result_get_float(dbi_result Result, const char *fieldname) {
1060   float my_ERROR = 0.0;
1061   dbi_error_flag errflag = DBI_ERROR_NONE;
1062   unsigned int fieldidx;
1063 
1064   _reset_conn_error(RESULT->conn);
1065 
1066   fieldidx = _find_field(RESULT, fieldname, &errflag);
1067   if (errflag != DBI_ERROR_NONE) {
1068     dbi_conn_t *conn = RESULT->conn;
1069     _error_handler(conn, DBI_ERROR_BADNAME);
1070     return my_ERROR;
1071   }
1072   return dbi_result_get_float_idx(Result, fieldidx+1);
1073 }
1074 
dbi_result_get_float_idx(dbi_result Result,unsigned int fieldidx)1075 float dbi_result_get_float_idx(dbi_result Result, unsigned int fieldidx) {
1076   float my_ERROR = 0.0;
1077   fieldidx--;
1078 
1079   _reset_conn_error(RESULT->conn);
1080 
1081 
1082   if (fieldidx >= RESULT->numfields) {
1083     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
1084     return my_ERROR;
1085   }
1086   if (RESULT->field_types[fieldidx] != DBI_TYPE_DECIMAL) {
1087     _verbose_handler(RESULT->conn, "%s: field `%s` is not float type\n",
1088                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
1089     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1090     return my_ERROR;
1091   }
1092 
1093   switch (RESULT->field_attribs[fieldidx] & DBI_DECIMAL_SIZEMASK) {
1094   case DBI_DECIMAL_SIZE4:
1095     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_float;
1096   case DBI_DECIMAL_SIZE8:
1097     _verbose_handler(RESULT->conn, "%s: field `%s` is double, not float\n",
1098                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
1099   default:
1100     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1101     return my_ERROR;
1102   }
1103 }
1104 
dbi_result_get_double(dbi_result Result,const char * fieldname)1105 double dbi_result_get_double(dbi_result Result, const char *fieldname) {
1106   double my_ERROR = 0.0;
1107   unsigned int fieldidx;
1108   dbi_error_flag errflag = DBI_ERROR_NONE;
1109 
1110   _reset_conn_error(RESULT->conn);
1111 
1112   fieldidx = _find_field(RESULT, fieldname, &errflag);
1113   if (errflag != DBI_ERROR_NONE) {
1114     dbi_conn_t *conn = RESULT->conn;
1115     _error_handler(conn, DBI_ERROR_BADNAME);
1116     return my_ERROR;
1117   }
1118   return dbi_result_get_double_idx(Result, fieldidx+1);
1119 }
1120 
dbi_result_get_double_idx(dbi_result Result,unsigned int fieldidx)1121 double dbi_result_get_double_idx(dbi_result Result, unsigned int fieldidx) {
1122   double my_ERROR = 0.0;
1123   fieldidx--;
1124 
1125   _reset_conn_error(RESULT->conn);
1126 
1127   if (fieldidx >= RESULT->numfields) {
1128     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
1129     return my_ERROR;
1130   }
1131   if (RESULT->field_types[fieldidx] != DBI_TYPE_DECIMAL) {
1132     _verbose_handler(RESULT->conn, "%s: field `%s` is not double type\n",
1133                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
1134     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1135     return my_ERROR;
1136   }
1137 
1138   switch (RESULT->field_attribs[fieldidx] & DBI_DECIMAL_SIZEMASK) {
1139   case DBI_DECIMAL_SIZE4:
1140     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_float;
1141   case DBI_DECIMAL_SIZE8:
1142     return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_double;
1143   default:
1144     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1145     return my_ERROR;
1146   }
1147 }
1148 
dbi_result_get_string(dbi_result Result,const char * fieldname)1149 const char *dbi_result_get_string(dbi_result Result, const char *fieldname) {
1150   const char *my_ERROR = "ERROR";
1151   unsigned int fieldidx;
1152   dbi_error_flag errflag = DBI_ERROR_NONE;
1153 
1154   _reset_conn_error(RESULT->conn);
1155 
1156   fieldidx = _find_field(RESULT, fieldname, &errflag);
1157   if (errflag != DBI_ERROR_NONE) {
1158     dbi_conn_t *conn = RESULT->conn;
1159     _error_handler(conn, DBI_ERROR_BADNAME);
1160     return my_ERROR;
1161   }
1162   return dbi_result_get_string_idx(Result, fieldidx+1);
1163 }
1164 
dbi_result_get_string_idx(dbi_result Result,unsigned int fieldidx)1165 const char *dbi_result_get_string_idx(dbi_result Result, unsigned int fieldidx) {
1166   const char *my_ERROR = "ERROR";
1167   fieldidx--;
1168 
1169   _reset_conn_error(RESULT->conn);
1170 
1171 
1172   if (fieldidx >= RESULT->numfields) {
1173     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
1174     return my_ERROR;
1175   }
1176 
1177   if (RESULT->field_types[fieldidx] != DBI_TYPE_STRING) {
1178     dbi_conn_t *conn = RESULT->conn;
1179     _verbose_handler(conn, "%s: field `%s` is not string type\n",
1180                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
1181     _error_handler(conn, DBI_ERROR_BADTYPE);
1182     return my_ERROR;
1183   }
1184   if (RESULT->rows[RESULT->currowidx]->field_sizes[fieldidx] == 0
1185       && _get_field_flag(RESULT->rows[RESULT->currowidx], fieldidx, DBI_VALUE_NULL)) {
1186     /* string does not exist */
1187     return NULL;
1188   }
1189   /* else if field size == 0: empty string */
1190 
1191   return (const char *)(RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_string);
1192 }
1193 
dbi_result_get_binary(dbi_result Result,const char * fieldname)1194 const unsigned char *dbi_result_get_binary(dbi_result Result, const char *fieldname) {
1195   const char *my_ERROR = "ERROR";
1196   unsigned int fieldidx;
1197   dbi_error_flag errflag = DBI_ERROR_NONE;
1198 
1199   _reset_conn_error(RESULT->conn);
1200 
1201   fieldidx = _find_field(RESULT, fieldname, &errflag);
1202   if (errflag != DBI_ERROR_NONE) {
1203     dbi_conn_t *conn = RESULT->conn;
1204     _error_handler(conn, DBI_ERROR_BADNAME);
1205     return (const unsigned char*)my_ERROR;
1206   }
1207   return dbi_result_get_binary_idx(Result, fieldidx+1);
1208 }
1209 
dbi_result_get_binary_idx(dbi_result Result,unsigned int fieldidx)1210 const unsigned char *dbi_result_get_binary_idx(dbi_result Result, unsigned int fieldidx) {
1211   const char *my_ERROR = "ERROR";
1212   fieldidx--;
1213 
1214   _reset_conn_error(RESULT->conn);
1215 
1216 
1217   if (fieldidx >= RESULT->numfields) {
1218     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
1219     return (const unsigned char*)my_ERROR;
1220   }
1221   if (RESULT->field_types[fieldidx] != DBI_TYPE_BINARY) {
1222     _verbose_handler(RESULT->conn, "%s: field `%s` is not binary type\n",
1223                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
1224     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1225     return (const unsigned char*)my_ERROR;
1226   }
1227   if (RESULT->rows[RESULT->currowidx]->field_sizes[fieldidx] == 0) return NULL;
1228 
1229   return (const unsigned char *)(RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_string);
1230 }
1231 
dbi_result_get_string_copy(dbi_result Result,const char * fieldname)1232 char *dbi_result_get_string_copy(dbi_result Result, const char *fieldname) {
1233   char *my_ERROR = "ERROR";
1234   unsigned int fieldidx;
1235   dbi_error_flag errflag = DBI_ERROR_NONE;
1236 
1237   _reset_conn_error(RESULT->conn);
1238 
1239   fieldidx = _find_field(RESULT, fieldname, &errflag);
1240   if (errflag != DBI_ERROR_NONE) {
1241     dbi_conn_t *conn = RESULT->conn;
1242     _error_handler(conn, DBI_ERROR_BADNAME);
1243     return strdup(my_ERROR);
1244   }
1245   return dbi_result_get_string_copy_idx(Result, fieldidx+1);
1246 }
1247 
dbi_result_get_string_copy_idx(dbi_result Result,unsigned int fieldidx)1248 char *dbi_result_get_string_copy_idx(dbi_result Result, unsigned int fieldidx) {
1249   char *my_ERROR = "ERROR";
1250   char *newstring = NULL;
1251   fieldidx--;
1252 
1253   _reset_conn_error(RESULT->conn);
1254 
1255 
1256   if (fieldidx >= RESULT->numfields) {
1257     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
1258     return strdup(my_ERROR);
1259   }
1260   if (RESULT->field_types[fieldidx] != DBI_TYPE_STRING) {
1261     _verbose_handler(RESULT->conn, "%s: field `%s` is not string type\n",
1262                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
1263     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1264     return strdup(my_ERROR);
1265   }
1266   if (RESULT->rows[RESULT->currowidx]->field_sizes[fieldidx] == 0
1267    && RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_string == NULL) {
1268     // mysql returns 0 for the field size of an empty string, so size==0
1269     // doesn't necessarily mean NULL
1270     return NULL;
1271   }
1272 
1273   newstring = strdup(RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_string);
1274 
1275   if (newstring) {
1276     return newstring;
1277   }
1278   else {
1279     _error_handler(RESULT->conn, DBI_ERROR_NOMEM);
1280     return strdup(my_ERROR);
1281   }
1282 }
1283 
dbi_result_get_binary_copy(dbi_result Result,const char * fieldname)1284 unsigned char *dbi_result_get_binary_copy(dbi_result Result, const char *fieldname) {
1285   char *my_ERROR = "ERROR";
1286   unsigned int fieldidx;
1287   dbi_error_flag errflag = DBI_ERROR_NONE;
1288 
1289   _reset_conn_error(RESULT->conn);
1290 
1291   fieldidx = _find_field(RESULT, fieldname, &errflag);
1292   if (errflag != DBI_ERROR_NONE) {
1293     dbi_conn_t *conn = RESULT->conn;
1294     _error_handler(conn, DBI_ERROR_BADNAME);
1295     return (unsigned char *)strdup(my_ERROR);
1296   }
1297   return dbi_result_get_binary_copy_idx(Result, fieldidx+1);
1298 }
1299 
dbi_result_get_binary_copy_idx(dbi_result Result,unsigned int fieldidx)1300 unsigned char *dbi_result_get_binary_copy_idx(dbi_result Result, unsigned int fieldidx) {
1301   char *my_ERROR = "ERROR";
1302   unsigned char *newblob = NULL;
1303   unsigned long long size;
1304   fieldidx--;
1305 
1306   _reset_conn_error(RESULT->conn);
1307 
1308 
1309   if (fieldidx >= RESULT->numfields) {
1310     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
1311     return (unsigned char *)strdup(my_ERROR);
1312   }
1313   if (RESULT->field_types[fieldidx] != DBI_TYPE_BINARY) {
1314     _verbose_handler(RESULT->conn, "%s: field `%s` is not binary type\n",
1315                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
1316     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1317     return (unsigned char *)strdup(my_ERROR);
1318   }
1319   if (RESULT->rows[RESULT->currowidx]->field_sizes[fieldidx] == 0) return NULL;
1320 
1321   /* API function must use 1-based index */
1322   size = dbi_result_get_field_length_idx(Result, fieldidx+1);
1323   newblob = malloc(size);
1324   if (!newblob) {
1325     _error_handler(RESULT->conn, DBI_ERROR_NOMEM);
1326     return (unsigned char *)strdup(my_ERROR);
1327   }
1328   memcpy(newblob, RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_string, size);
1329   return newblob;
1330 }
1331 
dbi_result_get_datetime(dbi_result Result,const char * fieldname)1332 time_t dbi_result_get_datetime(dbi_result Result, const char *fieldname) {
1333   time_t my_ERROR = 0;
1334   unsigned int fieldidx;
1335   dbi_error_flag errflag = DBI_ERROR_NONE;
1336 
1337   _reset_conn_error(RESULT->conn);
1338 
1339   fieldidx = _find_field(RESULT, fieldname, &errflag);
1340   if (errflag != DBI_ERROR_NONE) {
1341     dbi_conn_t *conn = RESULT->conn;
1342     _error_handler(conn, DBI_ERROR_BADNAME);
1343     return my_ERROR;
1344   }
1345   return dbi_result_get_datetime_idx(Result, fieldidx+1);
1346 }
1347 
dbi_result_get_datetime_idx(dbi_result Result,unsigned int fieldidx)1348 time_t dbi_result_get_datetime_idx(dbi_result Result, unsigned int fieldidx) {
1349   time_t my_ERROR = 0;
1350   fieldidx--;
1351 
1352   _reset_conn_error(RESULT->conn);
1353 
1354   if (fieldidx >= RESULT->numfields) {
1355     _error_handler(RESULT->conn, DBI_ERROR_BADIDX);
1356     return my_ERROR;
1357   }
1358   if (RESULT->field_types[fieldidx] != DBI_TYPE_DATETIME) {
1359     _verbose_handler(RESULT->conn, "%s: field `%s` is not datetime type\n",
1360                      __func__, dbi_result_get_field_name(Result, fieldidx+1));
1361     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1362     return my_ERROR;
1363   }
1364 
1365   return (time_t)(RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_datetime);
1366 }
1367 
1368 /* RESULT: get_as* functions */
1369 
dbi_result_get_as_longlong(dbi_result Result,const char * fieldname)1370 long long dbi_result_get_as_longlong(dbi_result Result, const char *fieldname) {
1371   long long my_ERROR = 0;
1372   unsigned int fieldidx;
1373   dbi_error_flag errflag = DBI_ERROR_NONE;
1374 
1375   _reset_conn_error(RESULT->conn);
1376 
1377   fieldidx = _find_field(RESULT, fieldname, &errflag);
1378   if (errflag != DBI_ERROR_NONE) {
1379     dbi_conn_t *conn = RESULT->conn;
1380     _error_handler(conn, DBI_ERROR_BADNAME);
1381     return my_ERROR;
1382   }
1383   return dbi_result_get_as_longlong_idx(Result, fieldidx+1);
1384 }
1385 
dbi_result_get_as_longlong_idx(dbi_result Result,unsigned int fieldidx)1386 long long dbi_result_get_as_longlong_idx(dbi_result Result, unsigned int fieldidx) {
1387   long long my_ERROR = 0;
1388   fieldidx--;
1389 
1390   switch (RESULT->field_types[fieldidx]) {
1391   case DBI_TYPE_INTEGER:
1392     switch (RESULT->field_attribs[fieldidx] & DBI_INTEGER_SIZEMASK) {
1393     case DBI_INTEGER_SIZE1:
1394       return (long long)RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_char;
1395     case DBI_INTEGER_SIZE2:
1396       return (long long)RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_short;
1397     case DBI_INTEGER_SIZE3:
1398     case DBI_INTEGER_SIZE4:
1399       return (long long)RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_long;
1400     case DBI_INTEGER_SIZE8:
1401       return RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_longlong;
1402     default:
1403       _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1404       return my_ERROR;
1405     }
1406   case DBI_TYPE_DECIMAL:
1407     switch (RESULT->field_attribs[fieldidx] & DBI_DECIMAL_SIZEMASK) {
1408     case DBI_DECIMAL_SIZE4:
1409       return (long long)RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_float;
1410     case DBI_DECIMAL_SIZE8:
1411       return (long long)RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_double;
1412     default:
1413       _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1414       return my_ERROR;
1415     }
1416   case DBI_TYPE_STRING:
1417     if (RESULT->rows[RESULT->currowidx]->field_sizes[fieldidx] == 0
1418 	&& RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_string == NULL) {
1419       /* string does not exist */
1420       return 0; /* do not raise an error */
1421     }
1422     /* else if field size == 0: empty string */
1423     /* todo: do we need strtoll() error handling? */
1424     return strtoll((const char *)(RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_string), NULL, 10);
1425   case DBI_TYPE_BINARY:
1426     return 0; /* do not raise an error */
1427   case DBI_TYPE_DATETIME:
1428     return (long long)(RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_datetime);
1429   default:
1430     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1431     return my_ERROR;
1432   }
1433 }
1434 
dbi_result_get_as_string_copy(dbi_result Result,const char * fieldname)1435 char *dbi_result_get_as_string_copy(dbi_result Result, const char *fieldname) {
1436   char *my_ERROR = "ERROR";
1437   unsigned int fieldidx;
1438   dbi_error_flag errflag = DBI_ERROR_NONE;
1439 
1440   _reset_conn_error(RESULT->conn);
1441 
1442   fieldidx = _find_field(RESULT, fieldname, &errflag);
1443   if (errflag != DBI_ERROR_NONE) {
1444     dbi_conn_t *conn = RESULT->conn;
1445     _error_handler(conn, DBI_ERROR_BADNAME);
1446     return strdup(my_ERROR);
1447   }
1448   return dbi_result_get_as_string_copy_idx(Result, fieldidx+1);
1449 }
1450 
dbi_result_get_as_string_copy_idx(dbi_result Result,unsigned int fieldidx)1451 char *dbi_result_get_as_string_copy_idx(dbi_result Result, unsigned int fieldidx) {
1452   char *my_ERROR = "ERROR";
1453   char *newstring = NULL;
1454   char *oldstring = NULL;
1455   struct tm utctime;
1456 
1457   fieldidx--;
1458 
1459   newstring = malloc(32); /* sufficient for integers, decimal, and datetime */
1460 
1461   if (!newstring) {
1462     _error_handler(RESULT->conn, DBI_ERROR_NOMEM);
1463     return my_ERROR;
1464   }
1465   *newstring = '\0';
1466 
1467   /* output depends on: type, size, sign */
1468   switch (RESULT->field_types[fieldidx]) {
1469   case DBI_TYPE_INTEGER:
1470     switch (RESULT->field_attribs[fieldidx] & DBI_INTEGER_SIZEMASK) {
1471     case DBI_INTEGER_SIZE1:
1472       if (RESULT->field_attribs[fieldidx] & DBI_INTEGER_UNSIGNED) {
1473 	snprintf(newstring, 32, "%hhu", RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_char);
1474       }
1475       else {
1476 	snprintf(newstring, 32, "%hhd", RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_char);
1477       }
1478       break;
1479     case DBI_INTEGER_SIZE2:
1480       if (RESULT->field_attribs[fieldidx] & DBI_INTEGER_UNSIGNED) {
1481 	snprintf(newstring, 32, "%hu", RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_short);
1482       }
1483       else {
1484 	snprintf(newstring, 32, "%hd", RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_short);
1485       }
1486       break;
1487     case DBI_INTEGER_SIZE3:
1488     case DBI_INTEGER_SIZE4:
1489       if (RESULT->field_attribs[fieldidx] & DBI_INTEGER_UNSIGNED) {
1490 	snprintf(newstring, 32, "%u", RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_long);
1491       }
1492       else {
1493 	snprintf(newstring, 32, "%d", RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_long);
1494       }
1495       break;
1496     case DBI_INTEGER_SIZE8:
1497       if (RESULT->field_attribs[fieldidx] & DBI_INTEGER_UNSIGNED) {
1498 	snprintf(newstring, 32, "%llu", RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_longlong);
1499       }
1500       else {
1501 	snprintf(newstring, 32, "%lld", RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_longlong);
1502       }
1503       break;
1504     default:
1505       _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1506     }
1507     break;
1508   case DBI_TYPE_DECIMAL:
1509     switch (RESULT->field_attribs[fieldidx] & DBI_DECIMAL_SIZEMASK) {
1510     case DBI_DECIMAL_SIZE4:
1511       snprintf(newstring, 32, "%e", RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_float);
1512       break;
1513     case DBI_DECIMAL_SIZE8:
1514       snprintf(newstring, 32, "%e", RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_double);
1515       break;
1516     default:
1517       _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1518     }
1519     break;
1520   case DBI_TYPE_STRING:
1521     if (RESULT->rows[RESULT->currowidx]->field_sizes[fieldidx] == 0
1522 	&& RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_string == NULL) {
1523       /* string does not exist */
1524       /* return an empty string instead, no error */
1525     }
1526     else {
1527       /* else if field size == 0: empty string */
1528 
1529       oldstring = newstring;
1530       if ((newstring = strdup(RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_string)) == NULL) {
1531 	_error_handler(RESULT->conn, DBI_ERROR_NOMEM);
1532 	newstring = oldstring;
1533       }
1534       else {
1535 	/* don't free in case of an error as we'd return a dangling pointer */
1536 	free(oldstring);
1537       }
1538     }
1539     break;
1540   case DBI_TYPE_BINARY:
1541     break; /* return empty string, do not raise an error */
1542   case DBI_TYPE_DATETIME:
1543     gmtime_r(&(RESULT->rows[RESULT->currowidx]->field_values[fieldidx].d_datetime), &utctime);
1544     snprintf(newstring, 32, "%04d-%02d-%02d %02d:%02d:%02d", utctime.tm_year+1900, utctime.tm_mon+1, utctime.tm_mday, utctime.tm_hour, utctime.tm_min, utctime.tm_sec);
1545     break;
1546   default:
1547     _error_handler(RESULT->conn, DBI_ERROR_BADTYPE);
1548   }
1549 
1550   return newstring; /* is still empty string in case of an error */
1551 }
1552 
1553 
1554 /* RESULT: bind_* functions */
1555 
_setup_binding(dbi_result_t * result,const char * fieldname,void * bindto,void * helperfunc)1556 static int _setup_binding(dbi_result_t *result, const char *fieldname, void *bindto, void *helperfunc) {
1557   _field_binding_t *binding;
1558   if (!result) {
1559     _error_handler(/*RESULT->conn*/ NULL, DBI_ERROR_BADPTR);
1560     return DBI_BIND_ERROR;
1561   }
1562 
1563   _reset_conn_error(result->conn);
1564 
1565   if (!fieldname) {
1566     _error_handler(result->conn, DBI_ERROR_BADNAME);
1567     return DBI_BIND_ERROR;
1568   }
1569   binding = _find_or_create_binding_node(result, fieldname);
1570   if (!binding) {
1571     _error_handler(result->conn, DBI_ERROR_NOMEM);
1572     return DBI_BIND_ERROR;
1573   }
1574 
1575   if (bindto == NULL) {
1576     _remove_binding_node(result, binding);
1577   }
1578   else {
1579     binding->bindto = bindto;
1580     binding->helper_function = (void*)(_field_binding_t *)helperfunc;
1581   }
1582 
1583   return 0;
1584 }
1585 
_activate_bindings(dbi_result_t * result)1586 static void _activate_bindings(dbi_result_t *result) {
1587   _field_binding_t *binding = result->field_bindings;
1588   void (*helper_function)(_field_binding_t *);
1589 
1590   while (binding) {
1591     helper_function = binding->helper_function;
1592     helper_function(binding);
1593     binding = binding->next;
1594   }
1595   return;
1596 }
1597 
dbi_result_bind_char(dbi_result Result,const char * fieldname,char * bindto)1598 int dbi_result_bind_char(dbi_result Result, const char *fieldname, char *bindto) {
1599   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_char);
1600 }
1601 
dbi_result_bind_uchar(dbi_result Result,const char * fieldname,unsigned char * bindto)1602 int dbi_result_bind_uchar(dbi_result Result, const char *fieldname, unsigned char *bindto) {
1603   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_uchar);
1604 }
1605 
dbi_result_bind_short(dbi_result Result,const char * fieldname,short * bindto)1606 int dbi_result_bind_short(dbi_result Result, const char *fieldname, short *bindto) {
1607   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_short);
1608 }
1609 
dbi_result_bind_ushort(dbi_result Result,const char * fieldname,unsigned short * bindto)1610 int dbi_result_bind_ushort(dbi_result Result, const char *fieldname, unsigned short *bindto) {
1611   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_ushort);
1612 }
1613 
dbi_result_bind_int(dbi_result Result,const char * fieldname,int * bindto)1614 int dbi_result_bind_int(dbi_result Result, const char *fieldname, int *bindto) {
1615   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_int);
1616 }
1617 
dbi_result_bind_long(dbi_result Result,const char * fieldname,int * bindto)1618 int dbi_result_bind_long(dbi_result Result, const char *fieldname, int *bindto) {
1619   return dbi_result_bind_int(Result, fieldname, bindto);
1620 }
1621 
dbi_result_bind_uint(dbi_result Result,const char * fieldname,unsigned int * bindto)1622 int dbi_result_bind_uint(dbi_result Result, const char *fieldname, unsigned int *bindto) {
1623   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_uint);
1624 }
1625 
dbi_result_bind_ulong(dbi_result Result,const char * fieldname,unsigned int * bindto)1626 int dbi_result_bind_ulong(dbi_result Result, const char *fieldname, unsigned int *bindto) {
1627   return dbi_result_bind_uint(Result, fieldname, bindto);
1628 }
1629 
dbi_result_bind_longlong(dbi_result Result,const char * fieldname,long long * bindto)1630 int dbi_result_bind_longlong(dbi_result Result, const char *fieldname, long long *bindto) {
1631   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_longlong);
1632 }
1633 
dbi_result_bind_ulonglong(dbi_result Result,const char * fieldname,unsigned long long * bindto)1634 int dbi_result_bind_ulonglong(dbi_result Result, const char *fieldname, unsigned long long *bindto) {
1635   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_ulonglong);
1636 }
1637 
dbi_result_bind_float(dbi_result Result,const char * fieldname,float * bindto)1638 int dbi_result_bind_float(dbi_result Result, const char *fieldname, float *bindto) {
1639   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_float);
1640 }
1641 
dbi_result_bind_double(dbi_result Result,const char * fieldname,double * bindto)1642 int dbi_result_bind_double(dbi_result Result, const char *fieldname, double *bindto) {
1643   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_double);
1644 }
1645 
dbi_result_bind_string(dbi_result Result,const char * fieldname,const char ** bindto)1646 int dbi_result_bind_string(dbi_result Result, const char *fieldname, const char **bindto) {
1647   return _setup_binding(RESULT, fieldname, (char **)bindto, _bind_helper_string);
1648 }
1649 
dbi_result_bind_binary(dbi_result Result,const char * fieldname,const unsigned char ** bindto)1650 int dbi_result_bind_binary(dbi_result Result, const char *fieldname, const unsigned char **bindto) {
1651   return _setup_binding(RESULT, fieldname, (unsigned char **)bindto, _bind_helper_binary);
1652 }
1653 
dbi_result_bind_string_copy(dbi_result Result,const char * fieldname,char ** bindto)1654 int dbi_result_bind_string_copy(dbi_result Result, const char *fieldname, char **bindto) {
1655   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_string_copy);
1656 }
1657 
dbi_result_bind_binary_copy(dbi_result Result,const char * fieldname,unsigned char ** bindto)1658 int dbi_result_bind_binary_copy(dbi_result Result, const char *fieldname, unsigned char **bindto) {
1659   return _setup_binding(RESULT, fieldname, bindto, _bind_helper_binary_copy);
1660 }
1661 
dbi_result_bind_datetime(dbi_result Result,const char * fieldname,time_t * bindto)1662 int dbi_result_bind_datetime(dbi_result Result, const char *fieldname, time_t *bindto) {
1663   return _setup_binding(RESULT, fieldname, (time_t *)bindto, _bind_helper_datetime);
1664 }
1665 
_find_or_create_binding_node(dbi_result_t * result,const char * fieldname)1666 static _field_binding_t *_find_or_create_binding_node(dbi_result_t *result, const char *fieldname) {
1667   _field_binding_t *prevbinding = NULL;
1668   _field_binding_t *binding = result->field_bindings;
1669 
1670   while (binding && strcasecmp(fieldname, binding->fieldname)) {
1671     prevbinding = binding;
1672     binding = binding->next;
1673   }
1674   if (!binding) {
1675     /* allocate a new option node */
1676     binding = malloc(sizeof(_field_binding_t));
1677     if (!binding) {
1678       return NULL;
1679     }
1680     binding->result = result;
1681     binding->fieldname = strdup(fieldname);
1682     binding->next = NULL;
1683     if (result->field_bindings == NULL) {
1684       result->field_bindings = binding;
1685     }
1686     else {
1687       prevbinding->next = binding;
1688     }
1689   }
1690 
1691   return binding;
1692 }
1693 
_remove_binding_node(dbi_result_t * result,_field_binding_t * deadbinding)1694 static void _remove_binding_node(dbi_result_t *result, _field_binding_t *deadbinding) {
1695   _field_binding_t *prevbinding = NULL;
1696   _field_binding_t *binding = result->field_bindings;
1697 
1698   while (binding && (binding != deadbinding)) {
1699     prevbinding = binding;
1700     binding = binding->next;
1701   }
1702   if (!binding) {
1703     /* this should never ever happen. silently pretend it never did. */
1704     return;
1705   }
1706   free((char *)deadbinding->fieldname);
1707   if (result->field_bindings == deadbinding) {
1708     result->field_bindings = deadbinding->next;
1709   }
1710   else {
1711     prevbinding->next = deadbinding->next;
1712   }
1713   free(deadbinding);
1714 }
1715 
1716 /* returns the field index (>= 1), or 0 if no such field */
_find_field(dbi_result_t * result,const char * fieldname,dbi_error_flag * errflag)1717 static unsigned int _find_field(dbi_result_t *result, const char *fieldname, dbi_error_flag *errflag) {
1718   unsigned long i = 0;
1719   if (!result || !result->field_names) return DBI_FIELD_ERROR;
1720   while (i < result->numfields) {
1721     if (strcasecmp(result->field_names[i], fieldname) == 0) {
1722       *errflag = DBI_ERROR_NONE;
1723       return i;
1724     }
1725     i++;
1726   }
1727   _verbose_handler(result->conn, "result row has no field `%s`\n", fieldname);
1728   *errflag = DBI_ERROR_BADNAME;
1729   return 0;
1730 }
1731 
_is_row_fetched(dbi_result_t * result,unsigned long long row)1732 static int _is_row_fetched(dbi_result_t *result, unsigned long long row) {
1733   /* Bull patch reported by Tom Lane */
1734   /*  if (!result->rows || (row >= result->numrows_matched)) return -1; */
1735   if (!result->rows || (row > result->numrows_matched)) return -1;
1736   return !(result->rows[row] == NULL);
1737 }
1738 
1739 
1740 /* PRIVATE: bind helpers */
1741 
_bind_helper_char(_field_binding_t * binding)1742 static void _bind_helper_char(_field_binding_t *binding) {
1743   *(char *)binding->bindto = dbi_result_get_char((dbi_result)binding->result, binding->fieldname);
1744 }
1745 
_bind_helper_uchar(_field_binding_t * binding)1746 static void _bind_helper_uchar(_field_binding_t *binding) {
1747   *(unsigned char *)binding->bindto = dbi_result_get_uchar((dbi_result)binding->result, binding->fieldname);
1748 }
1749 
_bind_helper_short(_field_binding_t * binding)1750 static void _bind_helper_short(_field_binding_t *binding) {
1751   *(short *)binding->bindto = dbi_result_get_short((dbi_result)binding->result, binding->fieldname);
1752 }
1753 
_bind_helper_ushort(_field_binding_t * binding)1754 static void _bind_helper_ushort(_field_binding_t *binding) {
1755   *(unsigned short *)binding->bindto = dbi_result_get_ushort((dbi_result)binding->result, binding->fieldname);
1756 }
1757 
_bind_helper_int(_field_binding_t * binding)1758 static void _bind_helper_int(_field_binding_t *binding) {
1759   *(int *)binding->bindto = dbi_result_get_int((dbi_result)binding->result, binding->fieldname);
1760 }
1761 
_bind_helper_uint(_field_binding_t * binding)1762 static void _bind_helper_uint(_field_binding_t *binding) {
1763   *(unsigned int *)binding->bindto = dbi_result_get_uint((dbi_result)binding->result, binding->fieldname);
1764 }
1765 
_bind_helper_longlong(_field_binding_t * binding)1766 static void _bind_helper_longlong(_field_binding_t *binding) {
1767   *(long long *)binding->bindto = dbi_result_get_longlong((dbi_result)binding->result, binding->fieldname);
1768 }
1769 
_bind_helper_ulonglong(_field_binding_t * binding)1770 static void _bind_helper_ulonglong(_field_binding_t *binding) {
1771   *(unsigned long long *)binding->bindto = dbi_result_get_ulonglong((dbi_result)binding->result, binding->fieldname);
1772 }
1773 
_bind_helper_float(_field_binding_t * binding)1774 static void _bind_helper_float(_field_binding_t *binding) {
1775   *(float *)binding->bindto = dbi_result_get_float((dbi_result)binding->result, binding->fieldname);
1776 }
1777 
_bind_helper_double(_field_binding_t * binding)1778 static void _bind_helper_double(_field_binding_t *binding) {
1779   *(double *)binding->bindto = dbi_result_get_double((dbi_result)binding->result, binding->fieldname);
1780 }
1781 
_bind_helper_string(_field_binding_t * binding)1782 static void _bind_helper_string(_field_binding_t *binding) {
1783   *(const char **)binding->bindto = dbi_result_get_string((dbi_result)binding->result, binding->fieldname);
1784 }
1785 
_bind_helper_binary(_field_binding_t * binding)1786 static void _bind_helper_binary(_field_binding_t *binding) {
1787   *(const unsigned char **)binding->bindto = dbi_result_get_binary((dbi_result)binding->result, binding->fieldname);
1788 }
1789 
_bind_helper_string_copy(_field_binding_t * binding)1790 static void _bind_helper_string_copy(_field_binding_t *binding) {
1791   *(char **)binding->bindto = dbi_result_get_string_copy((dbi_result)binding->result, binding->fieldname);
1792 }
1793 
_bind_helper_binary_copy(_field_binding_t * binding)1794 static void _bind_helper_binary_copy(_field_binding_t *binding) {
1795   *(unsigned char **)binding->bindto = dbi_result_get_binary_copy((dbi_result)binding->result, binding->fieldname);
1796 }
1797 
_bind_helper_datetime(_field_binding_t * binding)1798 static void _bind_helper_datetime(_field_binding_t *binding) {
1799   *(time_t *)binding->bindto = dbi_result_get_datetime((dbi_result)binding->result, binding->fieldname);
1800 }
1801 
1802