diff --git a/doc/src/sgml/ecpg.sgml b/doc/src/sgml/ecpg.sgml index d081ed66625..3ce5f66f4ea 100644 --- a/doc/src/sgml/ecpg.sgml +++ b/doc/src/sgml/ecpg.sgml @@ -1375,10 +1375,13 @@ EXEC SQL END DECLARE SECTION; Arrays - SQL-level arrays are not directly supported in ECPG. It is not - possible to simply map an SQL array into a C array host variable. - This will result in undefined behavior. Some workarounds exist, - however. + Multi-dimensional SQL-level arrays are not directly supported in ECPG. + One-dimensional SQL-level arrays can be mapped into C array host + variables and vice-versa. However, when creating a statement ecpg does + not know the types of the columns, so that it cannot check if a C array + is input into a corresponding SQL-level array. When processing the + output of a SQL statement, ecpg has the necessary information and thus + checks if both are arrays. diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c index 3ec774ca6d0..f2dbf6687a7 100644 --- a/src/interfaces/ecpg/ecpglib/data.c +++ b/src/interfaces/ecpg/ecpglib/data.c @@ -291,6 +291,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, date ddres; timestamp tres; interval *ires; + char *endptr, endchar; case ECPGt_short: case ECPGt_int: @@ -564,10 +565,11 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, case ECPGt_decimal: case ECPGt_numeric: - if (isarray && *pval == '"') - nres = PGTYPESnumeric_from_asc(pval + 1, &scan_length); - else - nres = PGTYPESnumeric_from_asc(pval, &scan_length); + 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) @@ -600,10 +602,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, } else { - if (isarray && *scan_length == '"') - scan_length++; - - if (garbage_left(isarray, scan_length, compat)) + if (!isarray && garbage_left(isarray, scan_length, compat)) { free(nres); ecpg_raise(lineno, ECPG_NUMERIC_FORMAT, @@ -622,10 +621,14 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, break; case ECPGt_interval: - if (isarray && *pval == '"') - ires = PGTYPESinterval_from_asc(pval + 1, &scan_length); - else - ires = PGTYPESinterval_from_asc(pval, &scan_length); + 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) @@ -654,10 +657,10 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, } else { - if (isarray && *scan_length == '"') + if (*scan_length == '"') scan_length++; - if (garbage_left(isarray, scan_length, compat)) + if (!isarray && garbage_left(isarray, scan_length, compat)) { free(ires); ecpg_raise(lineno, ECPG_INTERVAL_FORMAT, @@ -672,10 +675,14 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, break; case ECPGt_date: - if (isarray && *pval == '"') - ddres = PGTYPESdate_from_asc(pval + 1, &scan_length); - else - ddres = PGTYPESdate_from_asc(pval, &scan_length); + 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) @@ -700,10 +707,10 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, } else { - if (isarray && *scan_length == '"') + if (*scan_length == '"') scan_length++; - if (garbage_left(isarray, scan_length, compat)) + if (!isarray && garbage_left(isarray, scan_length, compat)) { ecpg_raise(lineno, ECPG_DATE_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); @@ -716,10 +723,14 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, break; case ECPGt_timestamp: - if (isarray && *pval == '"') - tres = PGTYPEStimestamp_from_asc(pval + 1, &scan_length); - else - tres = PGTYPEStimestamp_from_asc(pval, &scan_length); + 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) @@ -744,10 +755,10 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, } else { - if (isarray && *scan_length == '"') + if (*scan_length == '"') scan_length++; - if (garbage_left(isarray, scan_length, compat)) + if (!isarray && garbage_left(isarray, scan_length, compat)) { ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index 4acb345972c..9854a57ed3e 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -505,16 +505,10 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari char *newcopy = NULL; /* - * arrays are not possible unless the attribute is an array too FIXME: we - * do not know if the attribute is an array here + * arrays are not possible unless the column is an array, too + * FIXME: we do not know if the column is an array here + * array input to singleton column will result in a runtime error */ -#if 0 - if (var->arrsize > 1 &&...) - { - ecpg_raise(lineno, ECPG_ARRAY_INSERT, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL); - return false; - } -#endif /* * Some special treatment is needed for records since we want their @@ -572,12 +566,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari if (asize > 1) { - strcpy(mallocedval, "array ["); + strcpy(mallocedval, "{"); for (element = 0; element < asize; element++) sprintf(mallocedval + strlen(mallocedval), "%hd,", ((short *) var->value)[element]); - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); } else sprintf(mallocedval, "%hd", *((short *) var->value)); @@ -610,12 +604,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari if (asize > 1) { - strcpy(mallocedval, "array ["); + strcpy(mallocedval, "{"); for (element = 0; element < asize; element++) sprintf(mallocedval + strlen(mallocedval), "%hu,", ((unsigned short *) var->value)[element]); - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); } else sprintf(mallocedval, "%hu", *((unsigned short *) var->value)); @@ -629,12 +623,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari if (asize > 1) { - strcpy(mallocedval, "array ["); + strcpy(mallocedval, "{"); for (element = 0; element < asize; element++) sprintf(mallocedval + strlen(mallocedval), "%u,", ((unsigned int *) var->value)[element]); - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); } else sprintf(mallocedval, "%u", *((unsigned int *) var->value)); @@ -648,12 +642,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari if (asize > 1) { - strcpy(mallocedval, "array ["); + strcpy(mallocedval, "{"); for (element = 0; element < asize; element++) sprintf(mallocedval + strlen(mallocedval), "%ld,", ((long *) var->value)[element]); - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); } else sprintf(mallocedval, "%ld", *((long *) var->value)); @@ -667,12 +661,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari if (asize > 1) { - strcpy(mallocedval, "array ["); + strcpy(mallocedval, "{"); for (element = 0; element < asize; element++) sprintf(mallocedval + strlen(mallocedval), "%lu,", ((unsigned long *) var->value)[element]); - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); } else sprintf(mallocedval, "%lu", *((unsigned long *) var->value)); @@ -686,12 +680,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari if (asize > 1) { - strcpy(mallocedval, "array ["); + strcpy(mallocedval, "{"); for (element = 0; element < asize; element++) sprintf(mallocedval + strlen(mallocedval), "%lld,", ((long long int *) var->value)[element]); - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); } else sprintf(mallocedval, "%lld", *((long long int *) var->value)); @@ -705,12 +699,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari if (asize > 1) { - strcpy(mallocedval, "array ["); + strcpy(mallocedval, "{"); for (element = 0; element < asize; element++) sprintf(mallocedval + strlen(mallocedval), "%llu,", ((unsigned long long int *) var->value)[element]); - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); } else sprintf(mallocedval, "%llu", *((unsigned long long int *) var->value)); @@ -724,12 +718,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari if (asize > 1) { - strcpy(mallocedval, "array ["); + strcpy(mallocedval, "{"); for (element = 0; element < asize; element++) sprintf_float_value(mallocedval + strlen(mallocedval), ((float *) var->value)[element], ","); - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); } else sprintf_float_value(mallocedval, *((float *) var->value), ""); @@ -743,12 +737,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari if (asize > 1) { - strcpy(mallocedval, "array ["); + strcpy(mallocedval, "{"); for (element = 0; element < asize; element++) sprintf_double_value(mallocedval + strlen(mallocedval), ((double *) var->value)[element], ","); - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); } else sprintf_double_value(mallocedval, *((double *) var->value), ""); @@ -757,27 +751,27 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari break; case ECPGt_bool: - if (!(mallocedval = ecpg_alloc(var->arrsize + sizeof("array []"), lineno))) + if (!(mallocedval = ecpg_alloc(var->arrsize + sizeof("{}"), lineno))) return false; if (var->arrsize > 1) { - strcpy(mallocedval, "array ["); + strcpy(mallocedval, "{"); if (var->offset == sizeof(char)) - for (element = 0; element < var->arrsize; element++) + for (element = 0; element < asize; element++) sprintf(mallocedval + strlen(mallocedval), "%c,", (((char *) var->value)[element]) ? 't' : 'f'); /* * this is necessary since sizeof(C++'s bool)==sizeof(int) */ else if (var->offset == sizeof(int)) - for (element = 0; element < var->arrsize; element++) + for (element = 0; element < asize; element++) sprintf(mallocedval + strlen(mallocedval), "%c,", (((int *) var->value)[element]) ? 't' : 'f'); else ecpg_raise(lineno, ECPG_CONVERT_BOOL, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL); - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); } else { @@ -853,63 +847,59 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari numeric *nval; if (var->arrsize > 1) - { - if (!(mallocedval = ecpg_strdup("array [", lineno))) + mallocedval = ecpg_strdup("{", lineno); + else + mallocedval = ecpg_strdup("", lineno); + + if (!mallocedval) return false; - for (element = 0; element < var->arrsize; element++) - { - nval = PGTYPESnumeric_new(); - if (!nval) - return false; - - if (var->type == ECPGt_numeric) - PGTYPESnumeric_copy((numeric *) ((var + var->offset * element)->value), nval); - else - PGTYPESnumeric_from_decimal((decimal *) ((var + var->offset * element)->value), nval); - - str = PGTYPESnumeric_to_asc(nval, nval->dscale); - slen = strlen(str); - PGTYPESnumeric_free(nval); - - if (!(mallocedval = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno))) - { - ecpg_free(str); - return false; - } - - strncpy(mallocedval + strlen(mallocedval), str, slen + 1); - strcpy(mallocedval + strlen(mallocedval), ","); - ecpg_free(str); - } - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); - } - else + for (element = 0; element < asize; element++) { + int result; + nval = PGTYPESnumeric_new(); if (!nval) + { + ecpg_free(mallocedval); return false; + } if (var->type == ECPGt_numeric) - PGTYPESnumeric_copy((numeric *) (var->value), nval); + result = PGTYPESnumeric_copy(&(((numeric *) (var->value))[element]), nval); else - PGTYPESnumeric_from_decimal((decimal *) (var->value), nval); + result = PGTYPESnumeric_from_decimal(&(((decimal *) (var->value))[element]), nval); + + if (result != 0) + { + PGTYPESnumeric_free(nval); + ecpg_free(mallocedval); + return false; + } str = PGTYPESnumeric_to_asc(nval, nval->dscale); slen = strlen(str); PGTYPESnumeric_free(nval); - if (!(mallocedval = ecpg_alloc(slen + 1, lineno))) + if (!(newcopy = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno))) { - free(str); + ecpg_free(mallocedval); + ecpg_free(str); return false; } + mallocedval = newcopy; + + /* also copy trailing '\0' */ + memcpy(mallocedval + strlen(mallocedval), str, slen + 1); + if (var->arrsize > 1) + strcpy(mallocedval + strlen(mallocedval), ","); - strncpy(mallocedval, str, slen); - mallocedval[slen] = '\0'; ecpg_free(str); } + if (var->arrsize > 1) + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); + *tobeinserted_p = mallocedval; } break; @@ -920,47 +910,43 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari int slen; if (var->arrsize > 1) - { - if (!(mallocedval = ecpg_strdup("array [", lineno))) - return false; - - for (element = 0; element < var->arrsize; element++) - { - str = quote_postgres(PGTYPESinterval_to_asc((interval *) ((var + var->offset * element)->value)), quote, lineno); - if (!str) - return false; - slen = strlen(str); - - if (!(mallocedval = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno))) - { - ecpg_free(str); - return false; - } - - strncpy(mallocedval + strlen(mallocedval), str, slen + 1); - strcpy(mallocedval + strlen(mallocedval), ","); - ecpg_free(str); - } - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); - } + mallocedval = ecpg_strdup("{", lineno); else - { - str = quote_postgres(PGTYPESinterval_to_asc((interval *) (var->value)), quote, lineno); - if (!str) + mallocedval = ecpg_strdup("", lineno); + + if (!mallocedval) return false; + + for (element = 0; element < asize; element++) + { + str = quote_postgres(PGTYPESinterval_to_asc(&(((interval *) (var->value))[element])), quote, lineno); + if (!str) + { + ecpg_free(mallocedval); + return false; + } + slen = strlen(str); - if (!(mallocedval = ecpg_alloc(slen + sizeof("interval ") + 1, lineno))) + if (!(newcopy = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno))) { + ecpg_free(mallocedval); ecpg_free(str); return false; } + mallocedval = newcopy; /* also copy trailing '\0' */ - strncpy(mallocedval + strlen(mallocedval), str, slen + 1); + memcpy(mallocedval + strlen(mallocedval), str, slen + 1); + if (var->arrsize > 1) + strcpy(mallocedval + strlen(mallocedval), ","); + ecpg_free(str); } + if (var->arrsize > 1) + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); + *tobeinserted_p = mallocedval; } break; @@ -971,47 +957,43 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari int slen; if (var->arrsize > 1) - { - if (!(mallocedval = ecpg_strdup("array [", lineno))) - return false; - - for (element = 0; element < var->arrsize; element++) - { - str = quote_postgres(PGTYPESdate_to_asc(*(date *) ((var + var->offset * element)->value)), quote, lineno); - if (!str) - return false; - slen = strlen(str); - - if (!(mallocedval = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno))) - { - ecpg_free(str); - return false; - } - - strncpy(mallocedval + strlen(mallocedval), str, slen + 1); - strcpy(mallocedval + strlen(mallocedval), ","); - ecpg_free(str); - } - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); - } + mallocedval = ecpg_strdup("{", lineno); else - { - str = quote_postgres(PGTYPESdate_to_asc(*(date *) (var->value)), quote, lineno); - if (!str) + mallocedval = ecpg_strdup("", lineno); + + if (!mallocedval) return false; + + for (element = 0; element < asize; element++) + { + str = quote_postgres(PGTYPESdate_to_asc(((date *) (var->value))[element]), quote, lineno); + if (!str) + { + ecpg_free(mallocedval); + return false; + } + slen = strlen(str); - if (!(mallocedval = ecpg_alloc(slen + sizeof("date ") + 1, lineno))) + if (!(newcopy = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno))) { + ecpg_free(mallocedval); ecpg_free(str); return false; } + mallocedval = newcopy; /* also copy trailing '\0' */ - strncpy(mallocedval + strlen(mallocedval), str, slen + 1); + memcpy(mallocedval + strlen(mallocedval), str, slen + 1); + if (var->arrsize > 1) + strcpy(mallocedval + strlen(mallocedval), ","); + ecpg_free(str); } + if (var->arrsize > 1) + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); + *tobeinserted_p = mallocedval; } break; @@ -1022,48 +1004,43 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari int slen; if (var->arrsize > 1) - { - if (!(mallocedval = ecpg_strdup("array [", lineno))) - return false; - - for (element = 0; element < var->arrsize; element++) - { - str = quote_postgres(PGTYPEStimestamp_to_asc(*(timestamp *) ((var + var->offset * element)->value)), quote, lineno); - if (!str) - return false; - - slen = strlen(str); - - if (!(mallocedval = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno))) - { - ecpg_free(str); - return false; - } - - strncpy(mallocedval + strlen(mallocedval), str, slen + 1); - strcpy(mallocedval + strlen(mallocedval), ","); - ecpg_free(str); - } - strcpy(mallocedval + strlen(mallocedval) - 1, "]"); - } + mallocedval = ecpg_strdup("{", lineno); else - { - str = quote_postgres(PGTYPEStimestamp_to_asc(*(timestamp *) (var->value)), quote, lineno); - if (!str) + mallocedval = ecpg_strdup("", lineno); + + if (!mallocedval) return false; + + for (element = 0; element < asize; element++) + { + str = quote_postgres(PGTYPEStimestamp_to_asc(((timestamp *) (var->value))[element]), quote, lineno); + if (!str) + { + ecpg_free(mallocedval); + return false; + } + slen = strlen(str); - if (!(mallocedval = ecpg_alloc(slen + sizeof("timestamp") + 1, lineno))) + if (!(newcopy = ecpg_realloc(mallocedval, strlen(mallocedval) + slen + 2, lineno))) { + ecpg_free(mallocedval); ecpg_free(str); return false; } + mallocedval = newcopy; /* also copy trailing '\0' */ - strncpy(mallocedval + strlen(mallocedval), str, slen + 1); + memcpy(mallocedval + strlen(mallocedval), str, slen + 1); + if (var->arrsize > 1) + strcpy(mallocedval + strlen(mallocedval), ","); + ecpg_free(str); } + if (var->arrsize > 1) + strcpy(mallocedval + strlen(mallocedval) - 1, "}"); + *tobeinserted_p = mallocedval; } break;