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;