Fix obsolete comment regarding FSM truncation.
[PostgreSQL.git] / src / interfaces / ecpg / ecpglib / data.c
blob54c60ac10f08868b10861eacd0b1dc94683881cf
1 /* $PostgreSQL$ */
3 #define POSTGRES_ECPG_INTERNAL
4 #include "postgres_fe.h"
6 #include <stdlib.h>
7 #include <string.h>
9 #include "ecpgtype.h"
10 #include "ecpglib.h"
11 #include "ecpgerrno.h"
12 #include "extern.h"
13 #include "sqlca.h"
14 #include "pgtypes_numeric.h"
15 #include "pgtypes_date.h"
16 #include "pgtypes_timestamp.h"
17 #include "pgtypes_interval.h"
19 static bool
20 garbage_left(enum ARRAY_TYPE isarray, char *scan_length, enum COMPAT_MODE compat)
23 * INFORMIX allows for selecting a numeric into an int, the result is
24 * truncated
26 if (isarray == ECPG_ARRAY_NONE && INFORMIX_MODE(compat) && *scan_length == '.')
27 return false;
29 if (isarray == ECPG_ARRAY_ARRAY && *scan_length != ',' && *scan_length != '}')
30 return true;
32 if (isarray == ECPG_ARRAY_VECTOR && *scan_length != ' ' && *scan_length != '\0')
33 return true;
35 if (isarray == ECPG_ARRAY_NONE && *scan_length != ' ' && *scan_length != '\0')
36 return true;
38 return false;
41 bool
42 ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
43 enum ECPGttype type, enum ECPGttype ind_type,
44 char *var, char *ind, long varcharsize, long offset,
45 long ind_offset, enum ARRAY_TYPE isarray, enum COMPAT_MODE compat, bool force_indicator)
47 struct sqlca_t *sqlca = ECPGget_sqlca();
48 char *pval = (char *) PQgetvalue(results, act_tuple, act_field);
49 int binary = PQfformat(results, act_field);
50 int size = PQgetlength(results, act_tuple, act_field);
51 int value_for_indicator = 0;
52 long log_offset;
55 * If we are running in a regression test, do not log the offset variable,
56 * it depends on the machine's alignment.
58 if (ecpg_internal_regression_mode)
59 log_offset = -1;
60 else
61 log_offset = offset;
63 ecpg_log("ecpg_get_data on line %d: RESULT: %s offset: %ld; array: %s\n", lineno, pval ? (binary ? _("BINARY") : pval) : _("EMPTY"), log_offset, isarray ? _("yes") : _("no"));
65 /* We will have to decode the value */
68 * check for null value and set indicator accordingly, i.e. -1 if NULL and
69 * 0 if not
71 if (PQgetisnull(results, act_tuple, act_field))
72 value_for_indicator = -1;
74 switch (ind_type)
76 case ECPGt_short:
77 case ECPGt_unsigned_short:
78 *((short *) (ind + ind_offset * act_tuple)) = value_for_indicator;
79 break;
80 case ECPGt_int:
81 case ECPGt_unsigned_int:
82 *((int *) (ind + ind_offset * act_tuple)) = value_for_indicator;
83 break;
84 case ECPGt_long:
85 case ECPGt_unsigned_long:
86 *((long *) (ind + ind_offset * act_tuple)) = value_for_indicator;
87 break;
88 #ifdef HAVE_LONG_LONG_INT_64
89 case ECPGt_long_long:
90 case ECPGt_unsigned_long_long:
91 *((long long int *) (ind + ind_offset * act_tuple)) = value_for_indicator;
92 break;
93 #endif /* HAVE_LONG_LONG_INT_64 */
94 case ECPGt_NO_INDICATOR:
95 if (value_for_indicator == -1)
97 if (force_indicator == false)
100 * Informix has an additional way to specify NULLs note
101 * that this uses special values to denote NULL
103 ECPGset_noind_null(type, var + offset * act_tuple);
105 else
107 ecpg_raise(lineno, ECPG_MISSING_INDICATOR,
108 ECPG_SQLSTATE_NULL_VALUE_NO_INDICATOR_PARAMETER,
109 NULL);
110 return (false);
113 break;
114 default:
115 ecpg_raise(lineno, ECPG_UNSUPPORTED,
116 ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
117 ecpg_type_name(ind_type));
118 return (false);
119 break;
122 if (value_for_indicator == -1)
123 return (true);
125 /* pval is a pointer to the value */
126 /* let's check if it really is an array if it should be one */
127 if (isarray == ECPG_ARRAY_ARRAY)
129 if (!pval || *pval != '{')
131 ecpg_raise(lineno, ECPG_DATA_NOT_ARRAY,
132 ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
133 return (false);
136 switch (type)
138 case ECPGt_char:
139 case ECPGt_unsigned_char:
140 case ECPGt_varchar:
141 break;
143 default:
144 pval++;
145 break;
151 if (binary)
153 if (pval)
155 if (varcharsize == 0 || varcharsize * offset >= size)
156 memcpy((char *) ((long) var + offset * act_tuple),
157 pval, size);
158 else
160 memcpy((char *) ((long) var + offset * act_tuple),
161 pval, varcharsize * offset);
163 if (varcharsize * offset < size)
165 /* truncation */
166 switch (ind_type)
168 case ECPGt_short:
169 case ECPGt_unsigned_short:
170 *((short *) (ind + ind_offset * act_tuple)) = size;
171 break;
172 case ECPGt_int:
173 case ECPGt_unsigned_int:
174 *((int *) (ind + ind_offset * act_tuple)) = size;
175 break;
176 case ECPGt_long:
177 case ECPGt_unsigned_long:
178 *((long *) (ind + ind_offset * act_tuple)) = size;
179 break;
180 #ifdef HAVE_LONG_LONG_INT_64
181 case ECPGt_long_long:
182 case ECPGt_unsigned_long_long:
183 *((long long int *) (ind + ind_offset * act_tuple)) = size;
184 break;
185 #endif /* HAVE_LONG_LONG_INT_64 */
186 default:
187 break;
189 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
192 pval += size;
195 else
197 switch (type)
199 long res;
200 unsigned long ures;
201 double dres;
202 char *scan_length;
203 numeric *nres;
204 date ddres;
205 timestamp tres;
206 interval *ires;
208 case ECPGt_short:
209 case ECPGt_int:
210 case ECPGt_long:
211 if (pval)
213 res = strtol(pval, &scan_length, 10);
214 if (garbage_left(isarray, scan_length, compat))
216 ecpg_raise(lineno, ECPG_INT_FORMAT,
217 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
218 return (false);
220 pval = scan_length;
222 else
223 res = 0L;
225 switch (type)
227 case ECPGt_short:
228 *((short *) (var + offset * act_tuple)) = (short) res;
229 break;
230 case ECPGt_int:
231 *((int *) (var + offset * act_tuple)) = (int) res;
232 break;
233 case ECPGt_long:
234 *((long *) (var + offset * act_tuple)) = (long) res;
235 break;
236 default:
237 /* Cannot happen */
238 break;
240 break;
242 case ECPGt_unsigned_short:
243 case ECPGt_unsigned_int:
244 case ECPGt_unsigned_long:
245 if (pval)
247 ures = strtoul(pval, &scan_length, 10);
248 if (garbage_left(isarray, scan_length, compat))
250 ecpg_raise(lineno, ECPG_UINT_FORMAT,
251 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
252 return (false);
254 pval = scan_length;
256 else
257 ures = 0L;
259 switch (type)
261 case ECPGt_unsigned_short:
262 *((unsigned short *) (var + offset * act_tuple)) = (unsigned short) ures;
263 break;
264 case ECPGt_unsigned_int:
265 *((unsigned int *) (var + offset * act_tuple)) = (unsigned int) ures;
266 break;
267 case ECPGt_unsigned_long:
268 *((unsigned long *) (var + offset * act_tuple)) = (unsigned long) ures;
269 break;
270 default:
271 /* Cannot happen */
272 break;
274 break;
276 #ifdef HAVE_LONG_LONG_INT_64
277 #ifdef HAVE_STRTOLL
278 case ECPGt_long_long:
279 if (pval)
281 *((long long int *) (var + offset * act_tuple)) = strtoll(pval, &scan_length, 10);
282 if (garbage_left(isarray, scan_length, compat))
284 ecpg_raise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
285 return (false);
287 pval = scan_length;
289 else
290 *((long long int *) (var + offset * act_tuple)) = (long long) 0;
292 break;
293 #endif /* HAVE_STRTOLL */
294 #ifdef HAVE_STRTOULL
295 case ECPGt_unsigned_long_long:
296 if (pval)
298 *((unsigned long long int *) (var + offset * act_tuple)) = strtoull(pval, &scan_length, 10);
299 if ((isarray && *scan_length != ',' && *scan_length != '}')
300 || (!isarray && !(INFORMIX_MODE(compat) && *scan_length == '.') && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */
302 ecpg_raise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
303 return (false);
305 pval = scan_length;
307 else
308 *((unsigned long long int *) (var + offset * act_tuple)) = (long long) 0;
310 break;
311 #endif /* HAVE_STRTOULL */
312 #endif /* HAVE_LONG_LONG_INT_64 */
314 case ECPGt_float:
315 case ECPGt_double:
316 if (pval)
318 if (isarray && *pval == '"')
319 dres = strtod(pval + 1, &scan_length);
320 else
321 dres = strtod(pval, &scan_length);
323 if (isarray && *scan_length == '"')
324 scan_length++;
326 if (garbage_left(isarray, scan_length, compat))
328 ecpg_raise(lineno, ECPG_FLOAT_FORMAT,
329 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
330 return (false);
332 pval = scan_length;
334 else
335 dres = 0.0;
337 switch (type)
339 case ECPGt_float:
340 *((float *) (var + offset * act_tuple)) = dres;
341 break;
342 case ECPGt_double:
343 *((double *) (var + offset * act_tuple)) = dres;
344 break;
345 default:
346 /* Cannot happen */
347 break;
349 break;
351 case ECPGt_bool:
352 if (pval)
354 if (pval[0] == 'f' && pval[1] == '\0')
356 if (offset == sizeof(char))
357 *((char *) (var + offset * act_tuple)) = false;
358 else if (offset == sizeof(int))
359 *((int *) (var + offset * act_tuple)) = false;
360 else
361 ecpg_raise(lineno, ECPG_CONVERT_BOOL,
362 ECPG_SQLSTATE_DATATYPE_MISMATCH,
363 _("different size"));
364 break;
366 else if (pval[0] == 't' && pval[1] == '\0')
368 if (offset == sizeof(char))
369 *((char *) (var + offset * act_tuple)) = true;
370 else if (offset == sizeof(int))
371 *((int *) (var + offset * act_tuple)) = true;
372 else
373 ecpg_raise(lineno, ECPG_CONVERT_BOOL,
374 ECPG_SQLSTATE_DATATYPE_MISMATCH,
375 _("different size"));
376 break;
378 else if (pval[0] == '\0' && PQgetisnull(results, act_tuple, act_field))
380 /* NULL is valid */
381 break;
385 ecpg_raise(lineno, ECPG_CONVERT_BOOL,
386 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
387 return (false);
388 break;
390 case ECPGt_char:
391 case ECPGt_unsigned_char:
392 if (pval)
394 if (varcharsize == 0 || varcharsize > size)
395 strncpy((char *) ((long) var + offset * act_tuple), pval, size + 1);
396 else
398 strncpy((char *) ((long) var + offset * act_tuple), pval, varcharsize);
400 if (varcharsize < size)
402 /* truncation */
403 switch (ind_type)
405 case ECPGt_short:
406 case ECPGt_unsigned_short:
407 *((short *) (ind + ind_offset * act_tuple)) = size;
408 break;
409 case ECPGt_int:
410 case ECPGt_unsigned_int:
411 *((int *) (ind + ind_offset * act_tuple)) = size;
412 break;
413 case ECPGt_long:
414 case ECPGt_unsigned_long:
415 *((long *) (ind + ind_offset * act_tuple)) = size;
416 break;
417 #ifdef HAVE_LONG_LONG_INT_64
418 case ECPGt_long_long:
419 case ECPGt_unsigned_long_long:
420 *((long long int *) (ind + ind_offset * act_tuple)) = size;
421 break;
422 #endif /* HAVE_LONG_LONG_INT_64 */
423 default:
424 break;
426 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
429 pval += size;
431 break;
433 case ECPGt_varchar:
434 if (pval)
436 struct ECPGgeneric_varchar *variable =
437 (struct ECPGgeneric_varchar *) ((long) var + offset * act_tuple);
439 variable->len = size;
440 if (varcharsize == 0)
441 strncpy(variable->arr, pval, variable->len);
442 else
444 strncpy(variable->arr, pval, varcharsize);
446 if (variable->len > varcharsize)
448 /* truncation */
449 switch (ind_type)
451 case ECPGt_short:
452 case ECPGt_unsigned_short:
453 *((short *) (ind + offset * act_tuple)) = variable->len;
454 break;
455 case ECPGt_int:
456 case ECPGt_unsigned_int:
457 *((int *) (ind + offset * act_tuple)) = variable->len;
458 break;
459 case ECPGt_long:
460 case ECPGt_unsigned_long:
461 *((long *) (ind + offset * act_tuple)) = variable->len;
462 break;
463 #ifdef HAVE_LONG_LONG_INT_64
464 case ECPGt_long_long:
465 case ECPGt_unsigned_long_long:
466 *((long long int *) (ind + ind_offset * act_tuple)) = variable->len;
467 break;
468 #endif /* HAVE_LONG_LONG_INT_64 */
469 default:
470 break;
472 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
474 variable->len = varcharsize;
477 pval += size;
479 break;
481 case ECPGt_decimal:
482 case ECPGt_numeric:
483 if (pval)
485 if (isarray && *pval == '"')
486 nres = PGTYPESnumeric_from_asc(pval + 1, &scan_length);
487 else
488 nres = PGTYPESnumeric_from_asc(pval, &scan_length);
490 /* did we get an error? */
491 if (nres == NULL)
493 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
494 lineno, pval ? pval : "", errno);
496 if (INFORMIX_MODE(compat))
499 * Informix wants its own NULL value here
500 * instead of an error
502 nres = PGTYPESnumeric_new();
503 if (nres)
504 ECPGset_noind_null(ECPGt_numeric, nres);
505 else
507 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
508 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
509 return (false);
512 else
514 ecpg_raise(lineno, ECPG_NUMERIC_FORMAT,
515 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
516 return (false);
519 else
521 if (isarray && *scan_length == '"')
522 scan_length++;
524 if (garbage_left(isarray, scan_length, compat))
526 free(nres);
527 ecpg_raise(lineno, ECPG_NUMERIC_FORMAT,
528 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
529 return (false);
532 pval = scan_length;
534 else
535 nres = PGTYPESnumeric_from_asc("0.0", &scan_length);
537 if (type == ECPGt_numeric)
538 PGTYPESnumeric_copy(nres, (numeric *) (var + offset * act_tuple));
539 else
540 PGTYPESnumeric_to_decimal(nres, (decimal *) (var + offset * act_tuple));
542 free(nres);
543 break;
545 case ECPGt_interval:
546 if (pval)
548 if (isarray && *pval == '"')
549 ires = PGTYPESinterval_from_asc(pval + 1, &scan_length);
550 else
551 ires = PGTYPESinterval_from_asc(pval, &scan_length);
553 /* did we get an error? */
554 if (ires == NULL)
556 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
557 lineno, pval ? pval : "", errno);
559 if (INFORMIX_MODE(compat))
562 * Informix wants its own NULL value here
563 * instead of an error
565 ires = (interval *) ecpg_alloc(sizeof(interval), lineno);
566 if (!ires)
567 return (false);
569 ECPGset_noind_null(ECPGt_interval, ires);
571 else
573 ecpg_raise(lineno, ECPG_INTERVAL_FORMAT,
574 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
575 return (false);
578 else
580 if (isarray && *scan_length == '"')
581 scan_length++;
583 if (garbage_left(isarray, scan_length, compat))
585 free(ires);
586 ecpg_raise(lineno, ECPG_INTERVAL_FORMAT,
587 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
588 return (false);
591 pval = scan_length;
593 else
594 ires = PGTYPESinterval_from_asc("0 seconds", NULL);
596 PGTYPESinterval_copy(ires, (interval *) (var + offset * act_tuple));
597 free(ires);
598 break;
599 case ECPGt_date:
600 if (pval)
602 if (isarray && *pval == '"')
603 ddres = PGTYPESdate_from_asc(pval + 1, &scan_length);
604 else
605 ddres = PGTYPESdate_from_asc(pval, &scan_length);
607 /* did we get an error? */
608 if (errno != 0)
610 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
611 lineno, pval ? pval : "", errno);
613 if (INFORMIX_MODE(compat))
616 * Informix wants its own NULL value here
617 * instead of an error
619 ECPGset_noind_null(ECPGt_date, &ddres);
621 else
623 ecpg_raise(lineno, ECPG_DATE_FORMAT,
624 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
625 return (false);
628 else
630 if (isarray && *scan_length == '"')
631 scan_length++;
633 if (garbage_left(isarray, scan_length, compat))
635 ecpg_raise(lineno, ECPG_DATE_FORMAT,
636 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
637 return (false);
641 *((date *) (var + offset * act_tuple)) = ddres;
642 pval = scan_length;
644 break;
646 case ECPGt_timestamp:
647 if (pval)
649 if (isarray && *pval == '"')
650 tres = PGTYPEStimestamp_from_asc(pval + 1, &scan_length);
651 else
652 tres = PGTYPEStimestamp_from_asc(pval, &scan_length);
654 /* did we get an error? */
655 if (errno != 0)
657 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
658 lineno, pval ? pval : "", errno);
660 if (INFORMIX_MODE(compat))
663 * Informix wants its own NULL value here
664 * instead of an error
666 ECPGset_noind_null(ECPGt_timestamp, &tres);
668 else
670 ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT,
671 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
672 return (false);
675 else
677 if (isarray && *scan_length == '"')
678 scan_length++;
680 if (garbage_left(isarray, scan_length, compat))
682 ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT,
683 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
684 return (false);
688 *((timestamp *) (var + offset * act_tuple)) = tres;
689 pval = scan_length;
691 break;
693 default:
694 ecpg_raise(lineno, ECPG_UNSUPPORTED,
695 ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
696 ecpg_type_name(type));
697 return (false);
698 break;
700 if (isarray == ECPG_ARRAY_ARRAY)
702 bool string = false;
704 /* set array to next entry */
705 ++act_tuple;
707 /* set pval to the next entry */
708 for (; string || (*pval != ',' && *pval != '}' && *pval != '\0'); ++pval)
709 if (*pval == '"')
710 string = string ? false : true;
712 if (*pval == ',')
713 ++pval;
715 else if (isarray == ECPG_ARRAY_VECTOR)
717 bool string = false;
719 /* set array to next entry */
720 ++act_tuple;
722 /* set pval to the next entry */
723 for (; string || (*pval != ' ' && *pval != '\0'); ++pval)
724 if (*pval == '"')
725 string = string ? false : true;
727 if (*pval == ' ')
728 ++pval;
731 } while (*pval != '\0' && ((isarray == ECPG_ARRAY_ARRAY && *pval != '}') || isarray == ECPG_ARRAY_VECTOR));
733 return (true);