1 /* src/interfaces/ecpg/ecpglib/data.c */
3 #define POSTGRES_ECPG_INTERNAL
4 #include "postgres_fe.h"
13 #include "ecpgerrno.h"
16 #include "pgtypes_numeric.h"
17 #include "pgtypes_date.h"
18 #include "pgtypes_timestamp.h"
19 #include "pgtypes_interval.h"
21 /* returns true if character c is a delimiter for the given array type */
23 array_delimiter(enum ARRAY_TYPE isarray, char c)
25 if (isarray == ECPG_ARRAY_ARRAY && c == ',')
28 if (isarray == ECPG_ARRAY_VECTOR && c == ' ')
34 /* returns true if character c marks the boundary for the given array type */
36 array_boundary(enum ARRAY_TYPE isarray, char c)
38 if (isarray == ECPG_ARRAY_ARRAY && c == '}')
41 if (isarray == ECPG_ARRAY_VECTOR && c == '\0')
47 /* returns true if some garbage is found at the end of the scanned string */
49 garbage_left(enum ARRAY_TYPE isarray, char *scan_length, enum COMPAT_MODE compat)
52 * INFORMIX allows for selecting a numeric into an int, the result is
55 if (isarray == ECPG_ARRAY_NONE)
57 if (INFORMIX_MODE(compat) && *scan_length == '.')
60 if (*scan_length != ' ' && *scan_length != '\0')
63 else if (ECPG_IS_ARRAY(isarray) && !array_delimiter(isarray, *scan_length) && !array_boundary(isarray, *scan_length))
69 /* stolen code from src/backend/utils/adt/float.c */
70 #if defined(WIN32) && !defined(NAN)
71 static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
73 #define NAN (*(const double *) nan)
77 get_float8_infinity(void)
80 return (double) INFINITY;
82 return (double) (HUGE_VAL * HUGE_VAL);
89 /* (double) NAN doesn't work on some NetBSD/MIPS releases */
90 #if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
93 return (double) (0.0 / 0.0);
98 check_special_value(char *ptr, double *retval, char **endptr)
100 if (pg_strncasecmp(ptr, "NaN", 3) == 0)
102 *retval = get_float8_nan();
106 else if (pg_strncasecmp(ptr, "Infinity", 8) == 0)
108 *retval = get_float8_infinity();
112 else if (pg_strncasecmp(ptr, "-Infinity", 9) == 0)
114 *retval = -get_float8_infinity();
123 ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
124 enum ECPGttype type, enum ECPGttype ind_type,
125 char *var, char *ind, long varcharsize, long offset,
126 long ind_offset, enum ARRAY_TYPE isarray, enum COMPAT_MODE compat, bool force_indicator)
128 struct sqlca_t *sqlca = ECPGget_sqlca();
129 char *pval = (char *) PQgetvalue(results, act_tuple, act_field);
130 int binary = PQfformat(results, act_field);
131 int size = PQgetlength(results, act_tuple, act_field);
132 int value_for_indicator = 0;
137 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
138 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
143 * If we are running in a regression test, do not log the offset variable,
144 * it depends on the machine's alignment.
146 if (ecpg_internal_regression_mode)
151 ecpg_log("ecpg_get_data on line %d: RESULT: %s offset: %ld; array: %s\n", lineno, pval ? (binary ? "BINARY" : pval) : "EMPTY", log_offset, ECPG_IS_ARRAY(isarray) ? "yes" : "no");
153 /* pval is a pointer to the value */
157 * This should never happen because we already checked that we found
158 * at least one tuple, but let's play it safe.
160 ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
164 /* We will have to decode the value */
167 * check for null value and set indicator accordingly, i.e. -1 if NULL and
170 if (PQgetisnull(results, act_tuple, act_field))
171 value_for_indicator = -1;
176 case ECPGt_unsigned_short:
177 *((short *) (ind + ind_offset * act_tuple)) = value_for_indicator;
180 case ECPGt_unsigned_int:
181 *((int *) (ind + ind_offset * act_tuple)) = value_for_indicator;
184 case ECPGt_unsigned_long:
185 *((long *) (ind + ind_offset * act_tuple)) = value_for_indicator;
187 #ifdef HAVE_LONG_LONG_INT
188 case ECPGt_long_long:
189 case ECPGt_unsigned_long_long:
190 *((long long int *) (ind + ind_offset * act_tuple)) = value_for_indicator;
192 #endif /* HAVE_LONG_LONG_INT */
193 case ECPGt_NO_INDICATOR:
194 if (value_for_indicator == -1)
196 if (force_indicator == false)
199 * Informix has an additional way to specify NULLs note
200 * that this uses special values to denote NULL
202 ECPGset_noind_null(type, var + offset * act_tuple);
206 ecpg_raise(lineno, ECPG_MISSING_INDICATOR,
207 ECPG_SQLSTATE_NULL_VALUE_NO_INDICATOR_PARAMETER,
214 ecpg_raise(lineno, ECPG_UNSUPPORTED,
215 ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
216 ecpg_type_name(ind_type));
221 if (value_for_indicator == -1)
224 /* let's check if it really is an array if it should be one */
225 if (isarray == ECPG_ARRAY_ARRAY)
229 ecpg_raise(lineno, ECPG_DATA_NOT_ARRAY,
230 ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
237 case ECPGt_unsigned_char:
252 if (varcharsize == 0 || varcharsize * offset >= size)
253 memcpy(var + offset * act_tuple, pval, size);
256 memcpy(var + offset * act_tuple, pval, varcharsize * offset);
258 if (varcharsize * offset < size)
264 case ECPGt_unsigned_short:
265 *((short *) (ind + ind_offset * act_tuple)) = size;
268 case ECPGt_unsigned_int:
269 *((int *) (ind + ind_offset * act_tuple)) = size;
272 case ECPGt_unsigned_long:
273 *((long *) (ind + ind_offset * act_tuple)) = size;
275 #ifdef HAVE_LONG_LONG_INT
276 case ECPGt_long_long:
277 case ECPGt_unsigned_long_long:
278 *((long long int *) (ind + ind_offset * act_tuple)) = size;
280 #endif /* HAVE_LONG_LONG_INT */
284 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
307 res = strtol(pval, &scan_length, 10);
308 if (garbage_left(isarray, scan_length, compat))
310 ecpg_raise(lineno, ECPG_INT_FORMAT,
311 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
319 *((short *) (var + offset * act_tuple)) = (short) res;
322 *((int *) (var + offset * act_tuple)) = (int) res;
325 *((long *) (var + offset * act_tuple)) = (long) res;
333 case ECPGt_unsigned_short:
334 case ECPGt_unsigned_int:
335 case ECPGt_unsigned_long:
336 ures = strtoul(pval, &scan_length, 10);
337 if (garbage_left(isarray, scan_length, compat))
339 ecpg_raise(lineno, ECPG_UINT_FORMAT,
340 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
347 case ECPGt_unsigned_short:
348 *((unsigned short *) (var + offset * act_tuple)) = (unsigned short) ures;
350 case ECPGt_unsigned_int:
351 *((unsigned int *) (var + offset * act_tuple)) = (unsigned int) ures;
353 case ECPGt_unsigned_long:
354 *((unsigned long *) (var + offset * act_tuple)) = (unsigned long) ures;
362 #ifdef HAVE_LONG_LONG_INT
364 case ECPGt_long_long:
365 *((long long int *) (var + offset * act_tuple)) = strtoll(pval, &scan_length, 10);
366 if (garbage_left(isarray, scan_length, compat))
368 ecpg_raise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
374 #endif /* HAVE_STRTOLL */
376 case ECPGt_unsigned_long_long:
377 *((unsigned long long int *) (var + offset * act_tuple)) = strtoull(pval, &scan_length, 10);
378 if ((isarray && *scan_length != ',' && *scan_length != '}')
379 || (!isarray && !(INFORMIX_MODE(compat) && *scan_length == '.') && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */
381 ecpg_raise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
387 #endif /* HAVE_STRTOULL */
388 #endif /* HAVE_LONG_LONG_INT */
392 if (isarray && *pval == '"')
395 if (!check_special_value(pval, &dres, &scan_length))
396 dres = strtod(pval, &scan_length);
398 if (isarray && *scan_length == '"')
401 if (garbage_left(isarray, scan_length, compat))
403 ecpg_raise(lineno, ECPG_FLOAT_FORMAT,
404 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
412 *((float *) (var + offset * act_tuple)) = dres;
415 *((double *) (var + offset * act_tuple)) = dres;
424 if (pval[0] == 'f' && pval[1] == '\0')
426 *((bool *) (var + offset * act_tuple)) = false;
430 else if (pval[0] == 't' && pval[1] == '\0')
432 *((bool *) (var + offset * act_tuple)) = true;
436 else if (pval[0] == '\0' && PQgetisnull(results, act_tuple, act_field))
442 ecpg_raise(lineno, ECPG_CONVERT_BOOL,
443 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
448 case ECPGt_unsigned_char:
451 char *str = (char *) (var + offset * act_tuple);
454 * If varcharsize is unknown and the offset is that of
455 * char *, then this variable represents the array of
456 * character pointers. So, use extra indirection.
458 if (varcharsize == 0 && offset == sizeof(char *))
459 str = *(char **) str;
461 if (varcharsize == 0 || varcharsize > size)
463 strncpy(str, pval, size + 1);
465 if (type == ECPGt_string)
467 char *last = str + size;
469 while (last > str && (*last == ' ' || *last == '\0'))
478 strncpy(str, pval, varcharsize);
480 if (varcharsize < size)
486 case ECPGt_unsigned_short:
487 *((short *) (ind + ind_offset * act_tuple)) = size;
490 case ECPGt_unsigned_int:
491 *((int *) (ind + ind_offset * act_tuple)) = size;
494 case ECPGt_unsigned_long:
495 *((long *) (ind + ind_offset * act_tuple)) = size;
497 #ifdef HAVE_LONG_LONG_INT
498 case ECPGt_long_long:
499 case ECPGt_unsigned_long_long:
500 *((long long int *) (ind + ind_offset * act_tuple)) = size;
502 #endif /* HAVE_LONG_LONG_INT */
506 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
515 struct ECPGgeneric_varchar *variable =
516 (struct ECPGgeneric_varchar *) (var + offset * act_tuple);
518 variable->len = size;
519 if (varcharsize == 0)
520 strncpy(variable->arr, pval, variable->len);
523 strncpy(variable->arr, pval, varcharsize);
525 if (variable->len > varcharsize)
531 case ECPGt_unsigned_short:
532 *((short *) (ind + ind_offset * act_tuple)) = variable->len;
535 case ECPGt_unsigned_int:
536 *((int *) (ind + ind_offset * act_tuple)) = variable->len;
539 case ECPGt_unsigned_long:
540 *((long *) (ind + ind_offset * act_tuple)) = variable->len;
542 #ifdef HAVE_LONG_LONG_INT
543 case ECPGt_long_long:
544 case ECPGt_unsigned_long_long:
545 *((long long int *) (ind + ind_offset * act_tuple)) = variable->len;
547 #endif /* HAVE_LONG_LONG_INT */
551 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
553 variable->len = varcharsize;
562 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '}'; endptr++);
565 nres = PGTYPESnumeric_from_asc(pval, &scan_length);
568 /* did we get an error? */
571 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
572 lineno, pval, errno);
574 if (INFORMIX_MODE(compat))
577 * Informix wants its own NULL value here instead
580 nres = PGTYPESnumeric_new();
582 ECPGset_noind_null(ECPGt_numeric, nres);
585 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
586 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
592 ecpg_raise(lineno, ECPG_NUMERIC_FORMAT,
593 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
599 if (!isarray && garbage_left(isarray, scan_length, compat))
602 ecpg_raise(lineno, ECPG_NUMERIC_FORMAT,
603 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
609 if (type == ECPGt_numeric)
610 PGTYPESnumeric_copy(nres, (numeric *) (var + offset * act_tuple));
612 PGTYPESnumeric_to_decimal(nres, (decimal *) (var + offset * act_tuple));
614 PGTYPESnumeric_free(nres);
621 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++);
624 ires = PGTYPESinterval_from_asc(pval, &scan_length);
627 /* did we get an error? */
630 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
631 lineno, pval, errno);
633 if (INFORMIX_MODE(compat))
636 * Informix wants its own NULL value here instead
639 ires = (interval *) ecpg_alloc(sizeof(interval), lineno);
643 ECPGset_noind_null(ECPGt_interval, ires);
647 ecpg_raise(lineno, ECPG_INTERVAL_FORMAT,
648 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
654 if (*scan_length == '"')
657 if (!isarray && garbage_left(isarray, scan_length, compat))
660 ecpg_raise(lineno, ECPG_INTERVAL_FORMAT,
661 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
667 PGTYPESinterval_copy(ires, (interval *) (var + offset * act_tuple));
675 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++);
678 ddres = PGTYPESdate_from_asc(pval, &scan_length);
681 /* did we get an error? */
684 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
685 lineno, pval, errno);
687 if (INFORMIX_MODE(compat))
690 * Informix wants its own NULL value here instead
693 ECPGset_noind_null(ECPGt_date, &ddres);
697 ecpg_raise(lineno, ECPG_DATE_FORMAT,
698 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
704 if (*scan_length == '"')
707 if (!isarray && garbage_left(isarray, scan_length, compat))
709 ecpg_raise(lineno, ECPG_DATE_FORMAT,
710 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
715 *((date *) (var + offset * act_tuple)) = ddres;
719 case ECPGt_timestamp:
723 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++);
726 tres = PGTYPEStimestamp_from_asc(pval, &scan_length);
729 /* did we get an error? */
732 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
733 lineno, pval, errno);
735 if (INFORMIX_MODE(compat))
738 * Informix wants its own NULL value here instead
741 ECPGset_noind_null(ECPGt_timestamp, &tres);
745 ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT,
746 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
752 if (*scan_length == '"')
755 if (!isarray && garbage_left(isarray, scan_length, compat))
757 ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT,
758 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
763 *((timestamp *) (var + offset * act_tuple)) = tres;
768 ecpg_raise(lineno, ECPG_UNSUPPORTED,
769 ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
770 ecpg_type_name(type));
774 if (ECPG_IS_ARRAY(isarray))
778 /* set array to next entry */
781 /* set pval to the next entry */
784 * *pval != '\0' should not be needed, but is used as a safety
787 for (; *pval != '\0' && (string || (!array_delimiter(isarray, *pval) && !array_boundary(isarray, *pval))); ++pval)
789 string = string ? false : true;
791 if (array_delimiter(isarray, *pval))
795 } while (*pval != '\0' && !array_boundary(isarray, *pval));