diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:15:05 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:15:05 +0000 |
commit | 46651ce6fe013220ed397add242004d764fc0153 (patch) | |
tree | 6e5299f990f88e60174a1d3ae6e48eedd2688b2b /src/interfaces/ecpg/ecpglib/data.c | |
parent | Initial commit. (diff) | |
download | postgresql-14-upstream.tar.xz postgresql-14-upstream.zip |
Adding upstream version 14.5.upstream/14.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/interfaces/ecpg/ecpglib/data.c')
-rw-r--r-- | src/interfaces/ecpg/ecpglib/data.c | 968 |
1 files changed, 968 insertions, 0 deletions
diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c new file mode 100644 index 0000000..6bc91ef --- /dev/null +++ b/src/interfaces/ecpg/ecpglib/data.c @@ -0,0 +1,968 @@ +/* src/interfaces/ecpg/ecpglib/data.c */ + +#define POSTGRES_ECPG_INTERNAL +#include "postgres_fe.h" + +#include <math.h> + +#include "ecpgerrno.h" +#include "ecpglib.h" +#include "ecpglib_extern.h" +#include "ecpgtype.h" +#include "pgtypes_date.h" +#include "pgtypes_interval.h" +#include "pgtypes_numeric.h" +#include "pgtypes_timestamp.h" +#include "sqlca.h" + +/* returns true if character c is a delimiter for the given array type */ +static bool +array_delimiter(enum ARRAY_TYPE isarray, char c) +{ + if (isarray == ECPG_ARRAY_ARRAY && c == ',') + return true; + + if (isarray == ECPG_ARRAY_VECTOR && c == ' ') + return true; + + return false; +} + +/* returns true if character c marks the boundary for the given array type */ +static bool +array_boundary(enum ARRAY_TYPE isarray, char c) +{ + if (isarray == ECPG_ARRAY_ARRAY && c == '}') + return true; + + if (isarray == ECPG_ARRAY_VECTOR && c == '\0') + return true; + + return false; +} + +/* returns true if some garbage is found at the end of the scanned string */ +static bool +garbage_left(enum ARRAY_TYPE isarray, char **scan_length, enum COMPAT_MODE compat) +{ + /* + * INFORMIX allows for selecting a numeric into an int, the result is + * truncated + */ + if (isarray == ECPG_ARRAY_NONE) + { + if (INFORMIX_MODE(compat) && **scan_length == '.') + { + /* skip invalid characters */ + do + { + (*scan_length)++; + } while (isdigit((unsigned char) **scan_length)); + } + + if (**scan_length != ' ' && **scan_length != '\0') + return true; + } + else if (ECPG_IS_ARRAY(isarray) && !array_delimiter(isarray, **scan_length) && !array_boundary(isarray, **scan_length)) + return true; + + return false; +} + +/* stolen code from src/backend/utils/adt/float.c */ +#if defined(WIN32) && !defined(NAN) +static const uint32 nan[2] = {0xffffffff, 0x7fffffff}; + +#define NAN (*(const double *) nan) +#endif + +static double +get_float8_infinity(void) +{ +#ifdef INFINITY + return (double) INFINITY; +#else + return (double) (HUGE_VAL * HUGE_VAL); +#endif +} + +static double +get_float8_nan(void) +{ + /* (double) NAN doesn't work on some NetBSD/MIPS releases */ +#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__)) + return (double) NAN; +#else + return (double) (0.0 / 0.0); +#endif +} + +static bool +check_special_value(char *ptr, double *retval, char **endptr) +{ + if (pg_strncasecmp(ptr, "NaN", 3) == 0) + { + *retval = get_float8_nan(); + *endptr = ptr + 3; + return true; + } + else if (pg_strncasecmp(ptr, "Infinity", 8) == 0) + { + *retval = get_float8_infinity(); + *endptr = ptr + 8; + return true; + } + else if (pg_strncasecmp(ptr, "-Infinity", 9) == 0) + { + *retval = -get_float8_infinity(); + *endptr = ptr + 9; + return true; + } + + return false; +} + +/* imported from src/backend/utils/adt/encode.c */ + +unsigned +ecpg_hex_enc_len(unsigned srclen) +{ + return srclen << 1; +} + +unsigned +ecpg_hex_dec_len(unsigned srclen) +{ + return srclen >> 1; +} + +static inline char +get_hex(char c) +{ + static const int8 hexlookup[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + int res = -1; + + if (c > 0 && c < 127) + res = hexlookup[(unsigned char) c]; + + return (char) res; +} + +static unsigned +hex_decode(const char *src, unsigned len, char *dst) +{ + const char *s, + *srcend; + char v1, + v2, + *p; + + srcend = src + len; + s = src; + p = dst; + while (s < srcend) + { + if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') + { + s++; + continue; + } + v1 = get_hex(*s++) << 4; + if (s >= srcend) + return -1; + + v2 = get_hex(*s++); + *p++ = v1 | v2; + } + + return p - dst; +} + +unsigned +ecpg_hex_encode(const char *src, unsigned len, char *dst) +{ + static const char hextbl[] = "0123456789abcdef"; + const char *end = src + len; + + while (src < end) + { + *dst++ = hextbl[(*src >> 4) & 0xF]; + *dst++ = hextbl[*src & 0xF]; + src++; + } + return len * 2; +} + +bool +ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, + enum ECPGttype type, enum ECPGttype ind_type, + char *var, char *ind, long varcharsize, long offset, + long ind_offset, enum ARRAY_TYPE isarray, enum COMPAT_MODE compat, bool force_indicator) +{ + struct sqlca_t *sqlca = ECPGget_sqlca(); + char *pval = (char *) PQgetvalue(results, act_tuple, act_field); + int binary = PQfformat(results, act_field); + int size = PQgetlength(results, act_tuple, act_field); + int value_for_indicator = 0; + long log_offset; + + if (sqlca == NULL) + { + ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, + ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL); + return false; + } + + /* + * If we are running in a regression test, do not log the offset variable, + * it depends on the machine's alignment. + */ + if (ecpg_internal_regression_mode) + log_offset = -1; + else + log_offset = offset; + + 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"); + + /* pval is a pointer to the value */ + if (!pval) + { + /* + * This should never happen because we already checked that we found + * at least one tuple, but let's play it safe. + */ + ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL); + return false; + } + + /* We will have to decode the value */ + + /* + * check for null value and set indicator accordingly, i.e. -1 if NULL and + * 0 if not + */ + if (PQgetisnull(results, act_tuple, act_field)) + value_for_indicator = -1; + + switch (ind_type) + { + case ECPGt_short: + case ECPGt_unsigned_short: + *((short *) (ind + ind_offset * act_tuple)) = value_for_indicator; + break; + case ECPGt_int: + case ECPGt_unsigned_int: + *((int *) (ind + ind_offset * act_tuple)) = value_for_indicator; + break; + case ECPGt_long: + case ECPGt_unsigned_long: + *((long *) (ind + ind_offset * act_tuple)) = value_for_indicator; + break; + case ECPGt_long_long: + case ECPGt_unsigned_long_long: + *((long long int *) (ind + ind_offset * act_tuple)) = value_for_indicator; + break; + case ECPGt_NO_INDICATOR: + if (value_for_indicator == -1) + { + if (force_indicator == false) + { + /* + * Informix has an additional way to specify NULLs note + * that this uses special values to denote NULL + */ + ECPGset_noind_null(type, var + offset * act_tuple); + } + else + { + ecpg_raise(lineno, ECPG_MISSING_INDICATOR, + ECPG_SQLSTATE_NULL_VALUE_NO_INDICATOR_PARAMETER, + NULL); + return false; + } + } + break; + default: + ecpg_raise(lineno, ECPG_UNSUPPORTED, + ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, + ecpg_type_name(ind_type)); + return false; + break; + } + + if (value_for_indicator == -1) + return true; + + /* let's check if it really is an array if it should be one */ + if (isarray == ECPG_ARRAY_ARRAY) + { + if (*pval != '{') + { + ecpg_raise(lineno, ECPG_DATA_NOT_ARRAY, + ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL); + return false; + } + + switch (type) + { + case ECPGt_char: + case ECPGt_unsigned_char: + case ECPGt_varchar: + case ECPGt_string: + break; + + default: + pval++; + break; + } + } + + do + { + if (binary) + { + if (varcharsize == 0 || varcharsize * offset >= size) + memcpy(var + offset * act_tuple, pval, size); + else + { + memcpy(var + offset * act_tuple, pval, varcharsize * offset); + + if (varcharsize * offset < size) + { + /* truncation */ + switch (ind_type) + { + case ECPGt_short: + case ECPGt_unsigned_short: + *((short *) (ind + ind_offset * act_tuple)) = size; + break; + case ECPGt_int: + case ECPGt_unsigned_int: + *((int *) (ind + ind_offset * act_tuple)) = size; + break; + case ECPGt_long: + case ECPGt_unsigned_long: + *((long *) (ind + ind_offset * act_tuple)) = size; + break; + case ECPGt_long_long: + case ECPGt_unsigned_long_long: + *((long long int *) (ind + ind_offset * act_tuple)) = size; + break; + default: + break; + } + sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W'; + } + } + pval += size; + } + else + { + switch (type) + { + long res; + unsigned long ures; + double dres; + char *scan_length; + numeric *nres; + date ddres; + timestamp tres; + interval *ires; + char *endptr, + endchar; + + case ECPGt_short: + case ECPGt_int: + case ECPGt_long: + res = strtol(pval, &scan_length, 10); + if (garbage_left(isarray, &scan_length, compat)) + { + ecpg_raise(lineno, ECPG_INT_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + pval = scan_length; + + switch (type) + { + case ECPGt_short: + *((short *) (var + offset * act_tuple)) = (short) res; + break; + case ECPGt_int: + *((int *) (var + offset * act_tuple)) = (int) res; + break; + case ECPGt_long: + *((long *) (var + offset * act_tuple)) = (long) res; + break; + default: + /* Cannot happen */ + break; + } + break; + + case ECPGt_unsigned_short: + case ECPGt_unsigned_int: + case ECPGt_unsigned_long: + ures = strtoul(pval, &scan_length, 10); + if (garbage_left(isarray, &scan_length, compat)) + { + ecpg_raise(lineno, ECPG_UINT_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + pval = scan_length; + + switch (type) + { + case ECPGt_unsigned_short: + *((unsigned short *) (var + offset * act_tuple)) = (unsigned short) ures; + break; + case ECPGt_unsigned_int: + *((unsigned int *) (var + offset * act_tuple)) = (unsigned int) ures; + break; + case ECPGt_unsigned_long: + *((unsigned long *) (var + offset * act_tuple)) = (unsigned long) ures; + break; + default: + /* Cannot happen */ + break; + } + break; + +#ifdef HAVE_STRTOLL + case ECPGt_long_long: + *((long long int *) (var + offset * act_tuple)) = strtoll(pval, &scan_length, 10); + if (garbage_left(isarray, &scan_length, compat)) + { + ecpg_raise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + pval = scan_length; + + break; +#endif /* HAVE_STRTOLL */ +#ifdef HAVE_STRTOULL + case ECPGt_unsigned_long_long: + *((unsigned long long int *) (var + offset * act_tuple)) = strtoull(pval, &scan_length, 10); + if (garbage_left(isarray, &scan_length, compat)) + { + ecpg_raise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + pval = scan_length; + + break; +#endif /* HAVE_STRTOULL */ + + case ECPGt_float: + case ECPGt_double: + if (isarray && *pval == '"') + pval++; + + if (!check_special_value(pval, &dres, &scan_length)) + dres = strtod(pval, &scan_length); + + if (isarray && *scan_length == '"') + scan_length++; + + /* no special INFORMIX treatment for floats */ + if (garbage_left(isarray, &scan_length, ECPG_COMPAT_PGSQL)) + { + ecpg_raise(lineno, ECPG_FLOAT_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + pval = scan_length; + + switch (type) + { + case ECPGt_float: + *((float *) (var + offset * act_tuple)) = dres; + break; + case ECPGt_double: + *((double *) (var + offset * act_tuple)) = dres; + break; + default: + /* Cannot happen */ + break; + } + break; + + case ECPGt_bool: + if (pval[0] == 'f' && pval[1] == '\0') + { + *((bool *) (var + offset * act_tuple)) = false; + pval++; + break; + } + else if (pval[0] == 't' && pval[1] == '\0') + { + *((bool *) (var + offset * act_tuple)) = true; + pval++; + break; + } + else if (pval[0] == '\0' && PQgetisnull(results, act_tuple, act_field)) + { + /* NULL is valid */ + break; + } + + ecpg_raise(lineno, ECPG_CONVERT_BOOL, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + break; + + case ECPGt_bytea: + { + struct ECPGgeneric_bytea *variable = + (struct ECPGgeneric_bytea *) (var + offset * act_tuple); + long dst_size, + src_size, + dec_size; + + dst_size = ecpg_hex_enc_len(varcharsize); + src_size = size - 2; /* exclude backslash + 'x' */ + dec_size = src_size < dst_size ? src_size : dst_size; + variable->len = hex_decode(pval + 2, dec_size, variable->arr); + + if (dst_size < src_size) + { + long rcv_size = ecpg_hex_dec_len(size - 2); + + /* truncation */ + switch (ind_type) + { + case ECPGt_short: + case ECPGt_unsigned_short: + *((short *) (ind + ind_offset * act_tuple)) = rcv_size; + break; + case ECPGt_int: + case ECPGt_unsigned_int: + *((int *) (ind + ind_offset * act_tuple)) = rcv_size; + break; + case ECPGt_long: + case ECPGt_unsigned_long: + *((long *) (ind + ind_offset * act_tuple)) = rcv_size; + break; + case ECPGt_long_long: + case ECPGt_unsigned_long_long: + *((long long int *) (ind + ind_offset * act_tuple)) = rcv_size; + break; + default: + break; + } + sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W'; + } + + pval += size; + + } + break; + + case ECPGt_char: + case ECPGt_unsigned_char: + case ECPGt_string: + { + char *str = (char *) (var + offset * act_tuple); + + /* + * If varcharsize is unknown and the offset is that of + * char *, then this variable represents the array of + * character pointers. So, use extra indirection. + */ + if (varcharsize == 0 && offset == sizeof(char *)) + str = *(char **) str; + + if (varcharsize == 0 || varcharsize > size) + { + /* + * compatibility mode, blank pad and null + * terminate char array + */ + if (ORACLE_MODE(compat) && (type == ECPGt_char || type == ECPGt_unsigned_char)) + { + memset(str, ' ', varcharsize); + memcpy(str, pval, size); + str[varcharsize - 1] = '\0'; + + /* + * compatibility mode empty string gets -1 + * indicator but no warning + */ + if (size == 0) + { + /* truncation */ + switch (ind_type) + { + case ECPGt_short: + case ECPGt_unsigned_short: + *((short *) (ind + ind_offset * act_tuple)) = -1; + break; + case ECPGt_int: + case ECPGt_unsigned_int: + *((int *) (ind + ind_offset * act_tuple)) = -1; + break; + case ECPGt_long: + case ECPGt_unsigned_long: + *((long *) (ind + ind_offset * act_tuple)) = -1; + break; + case ECPGt_long_long: + case ECPGt_unsigned_long_long: + *((long long int *) (ind + ind_offset * act_tuple)) = -1; + break; + default: + break; + } + } + } + else + { + strncpy(str, pval, size + 1); + } + /* do the rtrim() */ + if (type == ECPGt_string) + { + char *last = str + size; + + while (last > str && (*last == ' ' || *last == '\0')) + { + *last = '\0'; + last--; + } + } + } + else + { + strncpy(str, pval, varcharsize); + + /* compatibility mode, null terminate char array */ + if (ORACLE_MODE(compat) && (varcharsize - 1) < size) + { + if (type == ECPGt_char || type == ECPGt_unsigned_char) + str[varcharsize - 1] = '\0'; + } + + if (varcharsize < size || (ORACLE_MODE(compat) && (varcharsize - 1) < size)) + { + /* truncation */ + switch (ind_type) + { + case ECPGt_short: + case ECPGt_unsigned_short: + *((short *) (ind + ind_offset * act_tuple)) = size; + break; + case ECPGt_int: + case ECPGt_unsigned_int: + *((int *) (ind + ind_offset * act_tuple)) = size; + break; + case ECPGt_long: + case ECPGt_unsigned_long: + *((long *) (ind + ind_offset * act_tuple)) = size; + break; + case ECPGt_long_long: + case ECPGt_unsigned_long_long: + *((long long int *) (ind + ind_offset * act_tuple)) = size; + break; + default: + break; + } + sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W'; + } + } + pval += size; + } + break; + + case ECPGt_varchar: + { + struct ECPGgeneric_varchar *variable = + (struct ECPGgeneric_varchar *) (var + offset * act_tuple); + + variable->len = size; + if (varcharsize == 0) + strncpy(variable->arr, pval, variable->len); + else + { + strncpy(variable->arr, pval, varcharsize); + + if (variable->len > varcharsize) + { + /* truncation */ + switch (ind_type) + { + case ECPGt_short: + case ECPGt_unsigned_short: + *((short *) (ind + ind_offset * act_tuple)) = variable->len; + break; + case ECPGt_int: + case ECPGt_unsigned_int: + *((int *) (ind + ind_offset * act_tuple)) = variable->len; + break; + case ECPGt_long: + case ECPGt_unsigned_long: + *((long *) (ind + ind_offset * act_tuple)) = variable->len; + break; + case ECPGt_long_long: + case ECPGt_unsigned_long_long: + *((long long int *) (ind + ind_offset * act_tuple)) = variable->len; + break; + default: + break; + } + sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W'; + + variable->len = varcharsize; + } + } + pval += size; + } + break; + + case ECPGt_decimal: + case ECPGt_numeric: + for (endptr = pval; *endptr && *endptr != ',' && *endptr != '}'; endptr++); + endchar = *endptr; + *endptr = '\0'; + nres = PGTYPESnumeric_from_asc(pval, &scan_length); + *endptr = endchar; + + /* did we get an error? */ + if (nres == NULL) + { + ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n", + lineno, pval, errno); + + if (INFORMIX_MODE(compat)) + { + /* + * Informix wants its own NULL value here instead + * of an error + */ + nres = PGTYPESnumeric_new(); + if (nres) + ECPGset_noind_null(ECPGt_numeric, nres); + else + { + ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, + ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL); + return false; + } + } + else + { + ecpg_raise(lineno, ECPG_NUMERIC_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + } + else + { + if (!isarray && garbage_left(isarray, &scan_length, compat)) + { + free(nres); + ecpg_raise(lineno, ECPG_NUMERIC_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + } + pval = scan_length; + + if (type == ECPGt_numeric) + PGTYPESnumeric_copy(nres, (numeric *) (var + offset * act_tuple)); + else + PGTYPESnumeric_to_decimal(nres, (decimal *) (var + offset * act_tuple)); + + PGTYPESnumeric_free(nres); + break; + + case ECPGt_interval: + if (*pval == '"') + pval++; + + for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++); + endchar = *endptr; + *endptr = '\0'; + ires = PGTYPESinterval_from_asc(pval, &scan_length); + *endptr = endchar; + + /* did we get an error? */ + if (ires == NULL) + { + ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n", + lineno, pval, errno); + + if (INFORMIX_MODE(compat)) + { + /* + * Informix wants its own NULL value here instead + * of an error + */ + ires = (interval *) ecpg_alloc(sizeof(interval), lineno); + if (!ires) + return false; + + ECPGset_noind_null(ECPGt_interval, ires); + } + else + { + ecpg_raise(lineno, ECPG_INTERVAL_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + } + else + { + if (*scan_length == '"') + scan_length++; + + if (!isarray && garbage_left(isarray, &scan_length, compat)) + { + free(ires); + ecpg_raise(lineno, ECPG_INTERVAL_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + } + pval = scan_length; + + PGTYPESinterval_copy(ires, (interval *) (var + offset * act_tuple)); + free(ires); + break; + + case ECPGt_date: + if (*pval == '"') + pval++; + + for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++); + endchar = *endptr; + *endptr = '\0'; + ddres = PGTYPESdate_from_asc(pval, &scan_length); + *endptr = endchar; + + /* did we get an error? */ + if (errno != 0) + { + ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n", + lineno, pval, errno); + + if (INFORMIX_MODE(compat)) + { + /* + * Informix wants its own NULL value here instead + * of an error + */ + ECPGset_noind_null(ECPGt_date, &ddres); + } + else + { + ecpg_raise(lineno, ECPG_DATE_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + } + else + { + if (*scan_length == '"') + scan_length++; + + if (!isarray && garbage_left(isarray, &scan_length, compat)) + { + ecpg_raise(lineno, ECPG_DATE_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + } + + *((date *) (var + offset * act_tuple)) = ddres; + pval = scan_length; + break; + + case ECPGt_timestamp: + if (*pval == '"') + pval++; + + for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++); + endchar = *endptr; + *endptr = '\0'; + tres = PGTYPEStimestamp_from_asc(pval, &scan_length); + *endptr = endchar; + + /* did we get an error? */ + if (errno != 0) + { + ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n", + lineno, pval, errno); + + if (INFORMIX_MODE(compat)) + { + /* + * Informix wants its own NULL value here instead + * of an error + */ + ECPGset_noind_null(ECPGt_timestamp, &tres); + } + else + { + ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + } + else + { + if (*scan_length == '"') + scan_length++; + + if (!isarray && garbage_left(isarray, &scan_length, compat)) + { + ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT, + ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); + return false; + } + } + + *((timestamp *) (var + offset * act_tuple)) = tres; + pval = scan_length; + break; + + default: + ecpg_raise(lineno, ECPG_UNSUPPORTED, + ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, + ecpg_type_name(type)); + return false; + break; + } + if (ECPG_IS_ARRAY(isarray)) + { + bool string = false; + + /* set array to next entry */ + ++act_tuple; + + /* set pval to the next entry */ + + /* + * *pval != '\0' should not be needed, but is used as a safety + * guard + */ + for (; *pval != '\0' && (string || (!array_delimiter(isarray, *pval) && !array_boundary(isarray, *pval))); ++pval) + if (*pval == '"') + string = string ? false : true; + + if (array_delimiter(isarray, *pval)) + ++pval; + } + } + } while (*pval != '\0' && !array_boundary(isarray, *pval)); + + return true; +} |